diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 3425990ddd..f2a590cf67 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -2,9 +2,9 @@ ARMProxyStandaloneTest:test_ARMCallEmptyContractRevert() (gas: 19600) ARMProxyStandaloneTest:test_Constructor() (gas: 374544) ARMProxyStandaloneTest:test_SetARM() (gas: 16494) ARMProxyStandaloneTest:test_SetARMzero() (gas: 11216) -ARMProxyTest:test_ARMCallRevertReasonForwarded() (gas: 48006) -ARMProxyTest:test_ARMIsBlessed_Success() (gas: 48186) -ARMProxyTest:test_ARMIsCursed_Success() (gas: 50264) +ARMProxyTest:test_ARMCallRevertReasonForwarded() (gas: 47793) +ARMProxyTest:test_ARMIsBlessed_Success() (gas: 36269) +ARMProxyTest:test_ARMIsCursed_Success() (gas: 49740) AggregateTokenLimiter_constructor:test_Constructor_Success() (gas: 26920) AggregateTokenLimiter_getTokenBucket:test_GetTokenBucket_Success() (gas: 19691) AggregateTokenLimiter_getTokenBucket:test_Refill_Success() (gas: 40911) @@ -19,22 +19,22 @@ AggregateTokenLimiter_setAdmin:test_Owner_Success() (gas: 18989) AggregateTokenLimiter_setRateLimiterConfig:test_OnlyOnlyCallableByAdminOrOwner_Revert() (gas: 17479) AggregateTokenLimiter_setRateLimiterConfig:test_Owner_Success() (gas: 30062) AggregateTokenLimiter_setRateLimiterConfig:test_TokenLimitAdmin_Success() (gas: 32071) -BurnFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28789) -BurnFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55208) -BurnFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243632) +BurnFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28675) +BurnFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158) +BurnFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243541) BurnFromMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 23907) -BurnMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 27699) -BurnMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55208) -BurnMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 241523) +BurnMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 27585) +BurnMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158) +BurnMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 241432) BurnMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 17633) -BurnMintTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 28651) -BurnMintTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 56041) -BurnMintTokenPool_releaseOrMint:test_PoolMint_Success() (gas: 110771) -BurnWithFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28789) -BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55208) -BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243659) +BurnMintTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 28537) +BurnMintTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 55991) +BurnMintTokenPool_releaseOrMint:test_PoolMint_Success() (gas: 110657) +BurnWithFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28675) +BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158) +BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243568) BurnWithFromMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 24260) -CCIPClientExample_sanity:test_ImmutableExamples_Success() (gas: 2132891) +CCIPClientExample_sanity:test_ImmutableExamples_Success() (gas: 2132183) CCIPConfigSetup:test_getCapabilityConfiguration_Success() (gas: 9495) CCIPConfig_ConfigStateMachine:test__computeConfigDigest_Success() (gas: 70755) CCIPConfig_ConfigStateMachine:test__computeNewConfigWithMeta_InitToRunning_Success() (gas: 357994) @@ -85,40 +85,40 @@ CCIPConfig_validateConfig:test__validateConfig_TooManyBootstrapP2PIds_Reverts() CCIPConfig_validateConfig:test__validateConfig_TooManySigners_Reverts() (gas: 1160583) CCIPConfig_validateConfig:test__validateConfig_TooManyTransmitters_Reverts() (gas: 1158919) CCIPConfig_validateConfig:test_getCapabilityConfiguration_Success() (gas: 9562) -CommitStore_constructor:test_Constructor_Success() (gas: 3091440) -CommitStore_isUnpausedAndRMNHealthy:test_RMN_Success() (gas: 75331) -CommitStore_report:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 28784) -CommitStore_report:test_InvalidInterval_Revert() (gas: 28724) -CommitStore_report:test_InvalidRootRevert() (gas: 27957) -CommitStore_report:test_OnlyGasPriceUpdates_Success() (gas: 55519) -CommitStore_report:test_OnlyPriceUpdateStaleReport_Revert() (gas: 61429) -CommitStore_report:test_OnlyTokenPriceUpdates_Success() (gas: 55517) +CommitStore_constructor:test_Constructor_Success() (gas: 3091326) +CommitStore_isUnpausedAndRMNHealthy:test_RMN_Success() (gas: 73420) +CommitStore_report:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 28670) +CommitStore_report:test_InvalidInterval_Revert() (gas: 28610) +CommitStore_report:test_InvalidRootRevert() (gas: 27843) +CommitStore_report:test_OnlyGasPriceUpdates_Success() (gas: 55405) +CommitStore_report:test_OnlyPriceUpdateStaleReport_Revert() (gas: 61201) +CommitStore_report:test_OnlyTokenPriceUpdates_Success() (gas: 55403) CommitStore_report:test_Paused_Revert() (gas: 21259) -CommitStore_report:test_ReportAndPriceUpdate_Success() (gas: 86508) -CommitStore_report:test_ReportOnlyRootSuccess_gas() (gas: 56427) -CommitStore_report:test_RootAlreadyCommitted_Revert() (gas: 64197) -CommitStore_report:test_StaleReportWithRoot_Success() (gas: 119502) -CommitStore_report:test_Unhealthy_Revert() (gas: 44801) -CommitStore_report:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 103065) -CommitStore_report:test_ZeroEpochAndRound_Revert() (gas: 27740) +CommitStore_report:test_ReportAndPriceUpdate_Success() (gas: 86394) +CommitStore_report:test_ReportOnlyRootSuccess_gas() (gas: 56313) +CommitStore_report:test_RootAlreadyCommitted_Revert() (gas: 63969) +CommitStore_report:test_StaleReportWithRoot_Success() (gas: 119274) +CommitStore_report:test_Unhealthy_Revert() (gas: 44751) +CommitStore_report:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 102837) +CommitStore_report:test_ZeroEpochAndRound_Revert() (gas: 27626) CommitStore_resetUnblessedRoots:test_OnlyOwner_Revert() (gas: 11325) -CommitStore_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 140460) +CommitStore_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 143718) CommitStore_setDynamicConfig:test_InvalidCommitStoreConfig_Revert() (gas: 37263) CommitStore_setDynamicConfig:test_OnlyOwner_Revert() (gas: 37399) CommitStore_setDynamicConfig:test_PriceEpochCleared_Success() (gas: 129098) CommitStore_setLatestPriceEpochAndRound:test_OnlyOwner_Revert() (gas: 11047) CommitStore_setLatestPriceEpochAndRound:test_SetLatestPriceEpochAndRound_Success() (gas: 20642) CommitStore_setMinSeqNr:test_OnlyOwner_Revert() (gas: 11046) -CommitStore_verify:test_Blessed_Success() (gas: 96279) -CommitStore_verify:test_NotBlessed_Success() (gas: 58800) +CommitStore_verify:test_Blessed_Success() (gas: 96389) +CommitStore_verify:test_NotBlessed_Success() (gas: 61374) CommitStore_verify:test_Paused_Revert() (gas: 18496) CommitStore_verify:test_TooManyLeaves_Revert() (gas: 36785) DefensiveExampleTest:test_HappyPath_Success() (gas: 200018) DefensiveExampleTest:test_Recovery() (gas: 424253) -E2E:test_E2E_3MessagesSuccess_gas() (gas: 1106426) +E2E:test_E2E_3MessagesSuccess_gas() (gas: 1104821) EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_NotACompatiblePool_Revert() (gas: 38297) -EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_Success() (gas: 108537) -EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_TokenHandlingError_revert_Revert() (gas: 116989) +EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_Success() (gas: 108423) +EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_TokenHandlingError_revert_Revert() (gas: 116875) EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_AddMultipleChains_Success() (gas: 262922) EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_AddNewChain_Success() (gas: 93606) EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ApplyZeroUpdates_Success() (gas: 12376) @@ -128,32 +128,32 @@ EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChainPrevO EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChain_Success() (gas: 102139) EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ZeroOnRampAddress_Revert() (gas: 12465) EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ZeroSourceChainSelector_Revert() (gas: 12440) -EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsDifferentChains_Success() (gas: 278848) -EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSameChain_Success() (gas: 224198) -EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSkipDuplicate_Success() (gas: 149797) -EVM2EVMMultiOffRamp_batchExecute:test_OutOfBoundsGasLimitsAccess_Revert() (gas: 178986) -EVM2EVMMultiOffRamp_batchExecute:test_SingleReport_Success() (gas: 136134) -EVM2EVMMultiOffRamp_batchExecute:test_Unhealthy_Revert() (gas: 520534) -EVM2EVMMultiOffRamp_batchExecute:test_ZeroReports_Revert() (gas: 10465) +EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsDifferentChains_Success() (gas: 278602) +EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSameChain_Success() (gas: 223952) +EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSkipDuplicate_Success() (gas: 149563) +EVM2EVMMultiOffRamp_batchExecute:test_OutOfBoundsGasLimitsAccess_Revert() (gas: 178860) +EVM2EVMMultiOffRamp_batchExecute:test_SingleReport_Success() (gas: 136014) +EVM2EVMMultiOffRamp_batchExecute:test_Unhealthy_Revert() (gas: 518511) +EVM2EVMMultiOffRamp_batchExecute:test_ZeroReports_Revert() (gas: 10505) EVM2EVMMultiOffRamp_ccipReceive:test_Reverts() (gas: 17210) -EVM2EVMMultiOffRamp_commit:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 66076) -EVM2EVMMultiOffRamp_commit:test_InvalidInterval_Revert() (gas: 59726) -EVM2EVMMultiOffRamp_commit:test_InvalidRootRevert() (gas: 58806) -EVM2EVMMultiOffRamp_commit:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6568553) -EVM2EVMMultiOffRamp_commit:test_NoConfig_Revert() (gas: 6151804) +EVM2EVMMultiOffRamp_commit:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 65962) +EVM2EVMMultiOffRamp_commit:test_InvalidInterval_Revert() (gas: 59612) +EVM2EVMMultiOffRamp_commit:test_InvalidRootRevert() (gas: 58692) +EVM2EVMMultiOffRamp_commit:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6568439) +EVM2EVMMultiOffRamp_commit:test_NoConfig_Revert() (gas: 6151690) EVM2EVMMultiOffRamp_commit:test_OnlyGasPriceUpdates_Success() (gas: 108339) EVM2EVMMultiOffRamp_commit:test_OnlyPriceUpdateStaleReport_Revert() (gas: 118247) EVM2EVMMultiOffRamp_commit:test_OnlyTokenPriceUpdates_Success() (gas: 108382) EVM2EVMMultiOffRamp_commit:test_PriceSequenceNumberCleared_Success() (gas: 353651) -EVM2EVMMultiOffRamp_commit:test_ReportAndPriceUpdate_Success() (gas: 160194) -EVM2EVMMultiOffRamp_commit:test_ReportOnlyRootSuccess_gas() (gas: 135101) -EVM2EVMMultiOffRamp_commit:test_RootAlreadyCommitted_Revert() (gas: 136887) -EVM2EVMMultiOffRamp_commit:test_SourceChainNotEnabled_Revert() (gas: 59074) -EVM2EVMMultiOffRamp_commit:test_StaleReportWithRoot_Success() (gas: 225469) -EVM2EVMMultiOffRamp_commit:test_UnauthorizedTransmitter_Revert() (gas: 119710) -EVM2EVMMultiOffRamp_commit:test_Unhealthy_Revert() (gas: 77572) -EVM2EVMMultiOffRamp_commit:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 207989) -EVM2EVMMultiOffRamp_commit:test_WrongConfigWithoutSigners_Revert() (gas: 6562945) +EVM2EVMMultiOffRamp_commit:test_ReportAndPriceUpdate_Success() (gas: 160080) +EVM2EVMMultiOffRamp_commit:test_ReportOnlyRootSuccess_gas() (gas: 134987) +EVM2EVMMultiOffRamp_commit:test_RootAlreadyCommitted_Revert() (gas: 136659) +EVM2EVMMultiOffRamp_commit:test_SourceChainNotEnabled_Revert() (gas: 58960) +EVM2EVMMultiOffRamp_commit:test_StaleReportWithRoot_Success() (gas: 225241) +EVM2EVMMultiOffRamp_commit:test_UnauthorizedTransmitter_Revert() (gas: 119596) +EVM2EVMMultiOffRamp_commit:test_Unhealthy_Revert() (gas: 77519) +EVM2EVMMultiOffRamp_commit:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 207875) +EVM2EVMMultiOffRamp_commit:test_WrongConfigWithoutSigners_Revert() (gas: 6562831) EVM2EVMMultiOffRamp_commit:test_ZeroEpochAndRound_Revert() (gas: 47717) EVM2EVMMultiOffRamp_constructor:test_Constructor_Success() (gas: 6221393) EVM2EVMMultiOffRamp_constructor:test_SourceChainSelector_Revert() (gas: 100992) @@ -162,101 +162,101 @@ EVM2EVMMultiOffRamp_constructor:test_ZeroOnRampAddress_Revert() (gas: 101045) EVM2EVMMultiOffRamp_constructor:test_ZeroRMNProxy_Revert() (gas: 95693) EVM2EVMMultiOffRamp_constructor:test_ZeroTokenAdminRegistry_Revert() (gas: 95760) EVM2EVMMultiOffRamp_execute:test_IncorrectArrayType_Revert() (gas: 17299) -EVM2EVMMultiOffRamp_execute:test_LargeBatch_Success() (gas: 1493658) -EVM2EVMMultiOffRamp_execute:test_MultipleReportsWithPartialValidationFailures_Success() (gas: 330460) -EVM2EVMMultiOffRamp_execute:test_MultipleReports_Success() (gas: 247590) -EVM2EVMMultiOffRamp_execute:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6618993) -EVM2EVMMultiOffRamp_execute:test_NoConfig_Revert() (gas: 6201960) +EVM2EVMMultiOffRamp_execute:test_LargeBatch_Success() (gas: 1492338) +EVM2EVMMultiOffRamp_execute:test_MultipleReportsWithPartialValidationFailures_Success() (gas: 330226) +EVM2EVMMultiOffRamp_execute:test_MultipleReports_Success() (gas: 247344) +EVM2EVMMultiOffRamp_execute:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6618873) +EVM2EVMMultiOffRamp_execute:test_NoConfig_Revert() (gas: 6201840) EVM2EVMMultiOffRamp_execute:test_NonArray_Revert() (gas: 30077) -EVM2EVMMultiOffRamp_execute:test_SingleReport_Success() (gas: 156744) -EVM2EVMMultiOffRamp_execute:test_UnauthorizedTransmitter_Revert() (gas: 140692) -EVM2EVMMultiOffRamp_execute:test_WrongConfigWithSigners_Revert() (gas: 6981086) +EVM2EVMMultiOffRamp_execute:test_SingleReport_Success() (gas: 156624) +EVM2EVMMultiOffRamp_execute:test_UnauthorizedTransmitter_Revert() (gas: 140572) +EVM2EVMMultiOffRamp_execute:test_WrongConfigWithSigners_Revert() (gas: 6980966) EVM2EVMMultiOffRamp_execute:test_ZeroReports_Revert() (gas: 17174) EVM2EVMMultiOffRamp_executeSingleMessage:test_MessageSender_Revert() (gas: 20742) -EVM2EVMMultiOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 255884) +EVM2EVMMultiOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 255656) EVM2EVMMultiOffRamp_executeSingleMessage:test_NonContract_Success() (gas: 22893) -EVM2EVMMultiOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 208273) -EVM2EVMMultiOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 50981) -EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 50491) +EVM2EVMMultiOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 208045) +EVM2EVMMultiOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 50975) +EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 50485) EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidationNoRouterCall_Revert() (gas: 235475) EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidation_Revert() (gas: 91297) -EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 288124) -EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithValidation_Success() (gas: 95407) -EVM2EVMMultiOffRamp_executeSingleReport:test_DisabledSourceChain_Revert() (gas: 37461) -EVM2EVMMultiOffRamp_executeSingleReport:test_EmptyReport_Revert() (gas: 24043) -EVM2EVMMultiOffRamp_executeSingleReport:test_InvalidMessageId_Revert() (gas: 41937) -EVM2EVMMultiOffRamp_executeSingleReport:test_InvalidSourcePoolAddress_Success() (gas: 448890) -EVM2EVMMultiOffRamp_executeSingleReport:test_ManualExecutionNotYetEnabled_Revert() (gas: 53707) -EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingOnRampAddress_Revert() (gas: 44774) -EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingSourceChainSelector_Revert() (gas: 41829) -EVM2EVMMultiOffRamp_executeSingleReport:test_NonExistingSourceChain_Revert() (gas: 37691) -EVM2EVMMultiOffRamp_executeSingleReport:test_ReceiverError_Success() (gas: 170464) -EVM2EVMMultiOffRamp_executeSingleReport:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 182307) -EVM2EVMMultiOffRamp_executeSingleReport:test_RootNotCommitted_Revert() (gas: 47166) -EVM2EVMMultiOffRamp_executeSingleReport:test_RouterYULCall_Revert() (gas: 405979) -EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain_Success() (gas: 233227) -EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered_Success() (gas: 166280) -EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokens_Success() (gas: 180825) -EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver_Success() (gas: 251931) -EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 119123) -EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 383907) -EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonce_Success() (gas: 56119) -EVM2EVMMultiOffRamp_executeSingleReport:test_TokenDataMismatch_Revert() (gas: 51431) -EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE_Success() (gas: 528858) -EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 466470) -EVM2EVMMultiOffRamp_executeSingleReport:test_UnexpectedTokenData_Revert() (gas: 38166) -EVM2EVMMultiOffRamp_executeSingleReport:test_UnhealthySingleChainCurse_Revert() (gas: 519008) -EVM2EVMMultiOffRamp_executeSingleReport:test_Unhealthy_Revert() (gas: 516384) -EVM2EVMMultiOffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain_Success() (gas: 483511) -EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 127580) -EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 147874) -EVM2EVMMultiOffRamp_execute_upgrade:test_NoPrevOffRampForChain_Success() (gas: 239540) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedNonceNewSenderStartsAtZero_Success() (gas: 239421) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedNonceStartsAtV1Nonce_Success() (gas: 289916) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() (gas: 270592) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedSenderNoncesReadsPreviousRampTransitive_Success() (gas: 247698) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedSenderNoncesReadsPreviousRamp_Success() (gas: 235673) -EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedWithMultiRamp_Revert() (gas: 7153870) -EVM2EVMMultiOffRamp_execute_upgrade:test_Upgraded_Success() (gas: 136567) +EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 287890) +EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithValidation_Success() (gas: 95401) +EVM2EVMMultiOffRamp_executeSingleReport:test_DisabledSourceChain_Revert() (gas: 37347) +EVM2EVMMultiOffRamp_executeSingleReport:test_EmptyReport_Revert() (gas: 23929) +EVM2EVMMultiOffRamp_executeSingleReport:test_InvalidMessageId_Revert() (gas: 41823) +EVM2EVMMultiOffRamp_executeSingleReport:test_InvalidSourcePoolAddress_Success() (gas: 448428) +EVM2EVMMultiOffRamp_executeSingleReport:test_ManualExecutionNotYetEnabled_Revert() (gas: 53593) +EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingOnRampAddress_Revert() (gas: 44660) +EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingSourceChainSelector_Revert() (gas: 41715) +EVM2EVMMultiOffRamp_executeSingleReport:test_NonExistingSourceChain_Revert() (gas: 37577) +EVM2EVMMultiOffRamp_executeSingleReport:test_ReceiverError_Success() (gas: 170344) +EVM2EVMMultiOffRamp_executeSingleReport:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 182073) +EVM2EVMMultiOffRamp_executeSingleReport:test_RootNotCommitted_Revert() (gas: 47177) +EVM2EVMMultiOffRamp_executeSingleReport:test_RouterYULCall_Revert() (gas: 405859) +EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain_Success() (gas: 232987) +EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered_Success() (gas: 166040) +EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokens_Success() (gas: 180585) +EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver_Success() (gas: 251817) +EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 119003) +EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 383559) +EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonce_Success() (gas: 56005) +EVM2EVMMultiOffRamp_executeSingleReport:test_TokenDataMismatch_Revert() (gas: 51317) +EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE_Success() (gas: 528276) +EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 465888) +EVM2EVMMultiOffRamp_executeSingleReport:test_UnexpectedTokenData_Revert() (gas: 38052) +EVM2EVMMultiOffRamp_executeSingleReport:test_UnhealthySingleChainCurse_Revert() (gas: 516921) +EVM2EVMMultiOffRamp_executeSingleReport:test_Unhealthy_Revert() (gas: 514300) +EVM2EVMMultiOffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain_Success() (gas: 483010) +EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 127346) +EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 147640) +EVM2EVMMultiOffRamp_execute_upgrade:test_NoPrevOffRampForChain_Success() (gas: 239300) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedNonceNewSenderStartsAtZero_Success() (gas: 239181) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedNonceStartsAtV1Nonce_Success() (gas: 289556) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() (gas: 270238) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedSenderNoncesReadsPreviousRampTransitive_Success() (gas: 247338) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedSenderNoncesReadsPreviousRamp_Success() (gas: 235313) +EVM2EVMMultiOffRamp_execute_upgrade:test_UpgradedWithMultiRamp_Revert() (gas: 7153761) +EVM2EVMMultiOffRamp_execute_upgrade:test_Upgraded_Success() (gas: 136447) EVM2EVMMultiOffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3652910) EVM2EVMMultiOffRamp_getExecutionState:test_GetDifferentChainExecutionState_Success() (gas: 118102) EVM2EVMMultiOffRamp_getExecutionState:test_GetExecutionState_Success() (gas: 87240) EVM2EVMMultiOffRamp_manuallyExecute:test_ManualExecGasLimitMismatchSingleReport_Revert() (gas: 80095) EVM2EVMMultiOffRamp_manuallyExecute:test_ManualExecInvalidGasLimit_Revert() (gas: 28717) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 152385) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_FailedTx_Revert() (gas: 200013) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 152265) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_FailedTx_Revert() (gas: 199773) EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_ForkedChain_Revert() (gas: 28246) EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_GasLimitMismatchMultipleReports_Revert() (gas: 160817) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_LowGasLimit_Success() (gas: 497970) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_ReentrancyFails() (gas: 2371591) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_Success() (gas: 202168) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithGasOverride_Success() (gas: 202742) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithMultiReportGasOverride_Success() (gas: 652254) -EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithPartialMessages_Success() (gas: 287604) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_LowGasLimit_Success() (gas: 497730) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_ReentrancyFails() (gas: 2371243) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_Success() (gas: 201928) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithGasOverride_Success() (gas: 202502) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithMultiReportGasOverride_Success() (gas: 651738) +EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithPartialMessages_Success() (gas: 287352) EVM2EVMMultiOffRamp_metadataHash:test_MetadataHashChangesOnOnRampAddress_Success() (gas: 10983) EVM2EVMMultiOffRamp_metadataHash:test_MetadataHashChangesOnSourceChain_Success() (gas: 11029) EVM2EVMMultiOffRamp_metadataHash:test_MetadataHash_Success() (gas: 9135) -EVM2EVMMultiOffRamp_releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 165359) +EVM2EVMMultiOffRamp_releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 165131) EVM2EVMMultiOffRamp_releaseOrMintTokens:test__releaseOrMintTokens_PoolIsNotAPool_Reverts() (gas: 26919) EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() (gas: 63524) EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_InvalidEVMAddress_Revert() (gas: 44641) -EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_PoolDoesNotSupportDest_Reverts() (gas: 80662) -EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 185556) -EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 284012) +EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_PoolDoesNotSupportDest_Reverts() (gas: 80548) +EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 185328) +EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 283920) EVM2EVMMultiOffRamp_resetUnblessedRoots:test_OnlyOwner_Revert() (gas: 11420) -EVM2EVMMultiOffRamp_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 211875) +EVM2EVMMultiOffRamp_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 215133) EVM2EVMMultiOffRamp_setDynamicConfig:test_NonOwner_Revert() (gas: 14223) EVM2EVMMultiOffRamp_setDynamicConfig:test_PriceRegistryZeroAddress_Revert() (gas: 11729) EVM2EVMMultiOffRamp_setDynamicConfig:test_RouterZeroAddress_Revert() (gas: 13885) EVM2EVMMultiOffRamp_setDynamicConfig:test_SetDynamicConfigWithValidator_Success() (gas: 55589) EVM2EVMMultiOffRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 33599) -EVM2EVMMultiOffRamp_trialExecute:test_RateLimitError_Success() (gas: 243962) -EVM2EVMMultiOffRamp_trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 252619) -EVM2EVMMultiOffRamp_trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 306794) -EVM2EVMMultiOffRamp_trialExecute:test_trialExecute_Success() (gas: 286041) -EVM2EVMMultiOffRamp_verify:test_Blessed_Success() (gas: 176393) -EVM2EVMMultiOffRamp_verify:test_NotBlessedWrongChainSelector_Success() (gas: 178464) -EVM2EVMMultiOffRamp_verify:test_NotBlessed_Success() (gas: 138858) +EVM2EVMMultiOffRamp_trialExecute:test_RateLimitError_Success() (gas: 243734) +EVM2EVMMultiOffRamp_trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 252391) +EVM2EVMMultiOffRamp_trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 306560) +EVM2EVMMultiOffRamp_trialExecute:test_trialExecute_Success() (gas: 285807) +EVM2EVMMultiOffRamp_verify:test_Blessed_Success() (gas: 176503) +EVM2EVMMultiOffRamp_verify:test_NotBlessedWrongChainSelector_Success() (gas: 178574) +EVM2EVMMultiOffRamp_verify:test_NotBlessed_Success() (gas: 141432) EVM2EVMMultiOffRamp_verify:test_TooManyLeaves_Revert() (gas: 51501) EVM2EVMMultiOnRamp_applyDestChainConfigUpdates:test_InvalidDestBytesOverhead_Revert() (gas: 33833) EVM2EVMMultiOnRamp_applyDestChainConfigUpdates:test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() (gas: 16646) @@ -274,36 +274,36 @@ EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigNonceManagerEqAddre EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigRMNProxyEqAddressZero_Revert() (gas: 145314) EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigTokenAdminRegistryEqAddressZero_Revert() (gas: 140360) EVM2EVMMultiOnRamp_constructor:test_Constructor_Success() (gas: 4895426) -EVM2EVMMultiOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 96497) -EVM2EVMMultiOnRamp_forwardFromRouter:test_EnforceOutOfOrder_Revert() (gas: 102680) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 125959) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 156706) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 156217) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessEmptyExtraArgs() (gas: 156447) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 156472) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 155917) -EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidAddressEncodePacked_Revert() (gas: 35200) -EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidAddress_Revert() (gas: 35461) -EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidChainSelector_Revert() (gas: 28048) -EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 30027) -EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageGasLimitTooHigh_Revert() (gas: 31789) -EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageTooLarge_Revert() (gas: 110477) -EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageValidationError_Revert() (gas: 152652) -EVM2EVMMultiOnRamp_forwardFromRouter:test_MesssageFeeTooHigh_Revert() (gas: 34241) -EVM2EVMMultiOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 23151) -EVM2EVMMultiOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 41579) -EVM2EVMMultiOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 25996) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 205172) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 231448) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 142663) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 169604) -EVM2EVMMultiOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3779910) -EVM2EVMMultiOnRamp_forwardFromRouter:test_TooManyTokens_Revert() (gas: 32971) -EVM2EVMMultiOnRamp_forwardFromRouter:test_Unhealthy_Revert() (gas: 44263) -EVM2EVMMultiOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 135530) -EVM2EVMMultiOnRamp_forwardFromRouter:test_ZeroAddressReceiver_Revert() (gas: 282987) -EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 98591) -EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_WithValidation_Success() (gas: 275208) +EVM2EVMMultiOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 96383) +EVM2EVMMultiOnRamp_forwardFromRouter:test_EnforceOutOfOrder_Revert() (gas: 102566) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 125845) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 156592) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 156103) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessEmptyExtraArgs() (gas: 156333) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 156358) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 155803) +EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidAddressEncodePacked_Revert() (gas: 35086) +EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidAddress_Revert() (gas: 35347) +EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidChainSelector_Revert() (gas: 27934) +EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 29913) +EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageGasLimitTooHigh_Revert() (gas: 31675) +EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageTooLarge_Revert() (gas: 110363) +EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageValidationError_Revert() (gas: 152538) +EVM2EVMMultiOnRamp_forwardFromRouter:test_MesssageFeeTooHigh_Revert() (gas: 34127) +EVM2EVMMultiOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 23037) +EVM2EVMMultiOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 41465) +EVM2EVMMultiOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 25882) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 204830) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 231106) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 142549) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 169490) +EVM2EVMMultiOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3778770) +EVM2EVMMultiOnRamp_forwardFromRouter:test_TooManyTokens_Revert() (gas: 32857) +EVM2EVMMultiOnRamp_forwardFromRouter:test_Unhealthy_Revert() (gas: 44213) +EVM2EVMMultiOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 135416) +EVM2EVMMultiOnRamp_forwardFromRouter:test_ZeroAddressReceiver_Revert() (gas: 281847) +EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 98477) +EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_WithValidation_Success() (gas: 274980) EVM2EVMMultiOnRamp_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 124845) EVM2EVMMultiOnRamp_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCostUnsupportedDestChainSelector_Success() (gas: 11969) EVM2EVMMultiOnRamp_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 24662) @@ -337,77 +337,77 @@ EVM2EVMMultiOnRamp_setDynamicConfig:test_SetConfigOnlyOwner_Revert() (gas: 16243 EVM2EVMMultiOnRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 60038) EVM2EVMMultiOnRamp_withdrawFeeTokens:test_WithdrawFeeTokens_Success() (gas: 97129) EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_NotACompatiblePool_Revert() (gas: 38076) -EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_Success() (gas: 108365) -EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_TokenHandlingError_revert_Revert() (gas: 116906) -EVM2EVMOffRamp__releaseOrMintTokens:test_OverValueWithARLOff_Success() (gas: 392217) -EVM2EVMOffRamp__releaseOrMintTokens:test_PriceNotFoundForToken_Reverts() (gas: 145340) -EVM2EVMOffRamp__releaseOrMintTokens:test_RateLimitErrors_Reverts() (gas: 789345) -EVM2EVMOffRamp__releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 176477) +EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_Success() (gas: 108251) +EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_TokenHandlingError_revert_Revert() (gas: 116792) +EVM2EVMOffRamp__releaseOrMintTokens:test_OverValueWithARLOff_Success() (gas: 391761) +EVM2EVMOffRamp__releaseOrMintTokens:test_PriceNotFoundForToken_Reverts() (gas: 145226) +EVM2EVMOffRamp__releaseOrMintTokens:test_RateLimitErrors_Reverts() (gas: 788205) +EVM2EVMOffRamp__releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 176249) EVM2EVMOffRamp__releaseOrMintTokens:test__releaseOrMintTokens_NotACompatiblePool_Reverts() (gas: 29724) EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() (gas: 63379) EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_InvalidEVMAddress_Revert() (gas: 44501) -EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 214353) -EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 306982) -EVM2EVMOffRamp__report:test_Report_Success() (gas: 127824) -EVM2EVMOffRamp__trialExecute:test_RateLimitError_Success() (gas: 255301) -EVM2EVMOffRamp__trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 263892) -EVM2EVMOffRamp__trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 336088) -EVM2EVMOffRamp__trialExecute:test_trialExecute_Success() (gas: 314736) +EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 214125) +EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 306891) +EVM2EVMOffRamp__report:test_Report_Success() (gas: 127704) +EVM2EVMOffRamp__trialExecute:test_RateLimitError_Success() (gas: 255073) +EVM2EVMOffRamp__trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 263664) +EVM2EVMOffRamp__trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 335854) +EVM2EVMOffRamp__trialExecute:test_trialExecute_Success() (gas: 314502) EVM2EVMOffRamp_ccipReceive:test_Reverts() (gas: 17096) EVM2EVMOffRamp_constructor:test_CommitStoreAlreadyInUse_Revert() (gas: 153464) EVM2EVMOffRamp_constructor:test_Constructor_Success() (gas: 5491136) EVM2EVMOffRamp_constructor:test_ZeroOnRampAddress_Revert() (gas: 144220) -EVM2EVMOffRamp_execute:test_EmptyReport_Revert() (gas: 21459) -EVM2EVMOffRamp_execute:test_InvalidMessageId_Revert() (gas: 36556) -EVM2EVMOffRamp_execute:test_InvalidSourceChain_Revert() (gas: 51824) -EVM2EVMOffRamp_execute:test_InvalidSourcePoolAddress_Success() (gas: 474330) -EVM2EVMOffRamp_execute:test_ManualExecutionNotYetEnabled_Revert() (gas: 46537) -EVM2EVMOffRamp_execute:test_MessageTooLarge_Revert() (gas: 152576) -EVM2EVMOffRamp_execute:test_Paused_Revert() (gas: 101560) -EVM2EVMOffRamp_execute:test_ReceiverError_Success() (gas: 165312) -EVM2EVMOffRamp_execute:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 178182) -EVM2EVMOffRamp_execute:test_RootNotCommitted_Revert() (gas: 41431) -EVM2EVMOffRamp_execute:test_RouterYULCall_Revert() (gas: 402717) -EVM2EVMOffRamp_execute:test_SingleMessageNoTokensUnordered_Success() (gas: 160103) -EVM2EVMOffRamp_execute:test_SingleMessageNoTokens_Success() (gas: 175334) -EVM2EVMOffRamp_execute:test_SingleMessageToNonCCIPReceiver_Success() (gas: 248878) -EVM2EVMOffRamp_execute:test_SingleMessagesNoTokensSuccess_gas() (gas: 115349) -EVM2EVMOffRamp_execute:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 409892) -EVM2EVMOffRamp_execute:test_SkippedIncorrectNonce_Success() (gas: 54296) -EVM2EVMOffRamp_execute:test_StrictUntouchedToSuccess_Success() (gas: 132420) -EVM2EVMOffRamp_execute:test_TokenDataMismatch_Revert() (gas: 52323) -EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensAndGE_Success() (gas: 561156) -EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensSuccess_gas() (gas: 500392) -EVM2EVMOffRamp_execute:test_UnexpectedTokenData_Revert() (gas: 35556) -EVM2EVMOffRamp_execute:test_Unhealthy_Revert() (gas: 549423) -EVM2EVMOffRamp_execute:test_UnsupportedNumberOfTokens_Revert() (gas: 64168) -EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 123671) -EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 143834) +EVM2EVMOffRamp_execute:test_EmptyReport_Revert() (gas: 21345) +EVM2EVMOffRamp_execute:test_InvalidMessageId_Revert() (gas: 36442) +EVM2EVMOffRamp_execute:test_InvalidSourceChain_Revert() (gas: 51710) +EVM2EVMOffRamp_execute:test_InvalidSourcePoolAddress_Success() (gas: 473868) +EVM2EVMOffRamp_execute:test_ManualExecutionNotYetEnabled_Revert() (gas: 46423) +EVM2EVMOffRamp_execute:test_MessageTooLarge_Revert() (gas: 152462) +EVM2EVMOffRamp_execute:test_Paused_Revert() (gas: 101458) +EVM2EVMOffRamp_execute:test_ReceiverError_Success() (gas: 165192) +EVM2EVMOffRamp_execute:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 177948) +EVM2EVMOffRamp_execute:test_RootNotCommitted_Revert() (gas: 41317) +EVM2EVMOffRamp_execute:test_RouterYULCall_Revert() (gas: 402597) +EVM2EVMOffRamp_execute:test_SingleMessageNoTokensUnordered_Success() (gas: 159863) +EVM2EVMOffRamp_execute:test_SingleMessageNoTokens_Success() (gas: 175094) +EVM2EVMOffRamp_execute:test_SingleMessageToNonCCIPReceiver_Success() (gas: 248764) +EVM2EVMOffRamp_execute:test_SingleMessagesNoTokensSuccess_gas() (gas: 115229) +EVM2EVMOffRamp_execute:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 409544) +EVM2EVMOffRamp_execute:test_SkippedIncorrectNonce_Success() (gas: 54182) +EVM2EVMOffRamp_execute:test_StrictUntouchedToSuccess_Success() (gas: 132300) +EVM2EVMOffRamp_execute:test_TokenDataMismatch_Revert() (gas: 52209) +EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensAndGE_Success() (gas: 560574) +EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensSuccess_gas() (gas: 499810) +EVM2EVMOffRamp_execute:test_UnexpectedTokenData_Revert() (gas: 35442) +EVM2EVMOffRamp_execute:test_Unhealthy_Revert() (gas: 547373) +EVM2EVMOffRamp_execute:test_UnsupportedNumberOfTokens_Revert() (gas: 64054) +EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 123437) +EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 143600) EVM2EVMOffRamp_executeSingleMessage:test_MessageSender_Revert() (gas: 20615) -EVM2EVMOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 282106) +EVM2EVMOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 281878) EVM2EVMOffRamp_executeSingleMessage:test_NonContract_Success() (gas: 20264) -EVM2EVMOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 219510) -EVM2EVMOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 48753) -EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 48241) -EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 316806) -EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_ZeroGasZeroData_Success() (gas: 72643) -EVM2EVMOffRamp_execute_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 232046) -EVM2EVMOffRamp_execute_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 280987) -EVM2EVMOffRamp_execute_upgrade:test_V2OffRampNonceSkipsIfMsgInFlight_Success() (gas: 262028) -EVM2EVMOffRamp_execute_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 230529) -EVM2EVMOffRamp_execute_upgrade:test_V2_Success() (gas: 132026) +EVM2EVMOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 219282) +EVM2EVMOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 48747) +EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 48235) +EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 316572) +EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_ZeroGasZeroData_Success() (gas: 72637) +EVM2EVMOffRamp_execute_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 231806) +EVM2EVMOffRamp_execute_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 280627) +EVM2EVMOffRamp_execute_upgrade:test_V2OffRampNonceSkipsIfMsgInFlight_Success() (gas: 261674) +EVM2EVMOffRamp_execute_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 230169) +EVM2EVMOffRamp_execute_upgrade:test_V2_Success() (gas: 131906) EVM2EVMOffRamp_getAllRateLimitTokens:test_GetAllRateLimitTokens_Success() (gas: 38408) EVM2EVMOffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3213556) EVM2EVMOffRamp_getExecutionState:test_GetExecutionState_Success() (gas: 83091) -EVM2EVMOffRamp_manuallyExecute:test_LowGasLimitManualExec_Success() (gas: 484053) -EVM2EVMOffRamp_manuallyExecute:test_ManualExecFailedTx_Revert() (gas: 187049) +EVM2EVMOffRamp_manuallyExecute:test_LowGasLimitManualExec_Success() (gas: 483813) +EVM2EVMOffRamp_manuallyExecute:test_ManualExecFailedTx_Revert() (gas: 186809) EVM2EVMOffRamp_manuallyExecute:test_ManualExecForkedChain_Revert() (gas: 25894) EVM2EVMOffRamp_manuallyExecute:test_ManualExecGasLimitMismatch_Revert() (gas: 43519) EVM2EVMOffRamp_manuallyExecute:test_ManualExecInvalidGasLimit_Revert() (gas: 26009) -EVM2EVMOffRamp_manuallyExecute:test_ManualExecWithGasOverride_Success() (gas: 189243) -EVM2EVMOffRamp_manuallyExecute:test_ManualExec_Success() (gas: 188704) -EVM2EVMOffRamp_manuallyExecute:test_ReentrancyManualExecuteFails() (gas: 2028045) -EVM2EVMOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 144226) +EVM2EVMOffRamp_manuallyExecute:test_ManualExecWithGasOverride_Success() (gas: 189003) +EVM2EVMOffRamp_manuallyExecute:test_ManualExec_Success() (gas: 188464) +EVM2EVMOffRamp_manuallyExecute:test_ReentrancyManualExecuteFails() (gas: 2027697) +EVM2EVMOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 144106) EVM2EVMOffRamp_metadataHash:test_MetadataHash_Success() (gas: 8871) EVM2EVMOffRamp_setDynamicConfig:test_NonOwner_Revert() (gas: 40429) EVM2EVMOffRamp_setDynamicConfig:test_RouterZeroAddress_Revert() (gas: 38804) @@ -420,40 +420,40 @@ EVM2EVMOnRamp_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplier EVM2EVMOnRamp_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesSingleToken_Success() (gas: 44807) EVM2EVMOnRamp_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesZeroInput() (gas: 12324) EVM2EVMOnRamp_constructor:test_Constructor_Success() (gas: 5635586) -EVM2EVMOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 35902) -EVM2EVMOnRamp_forwardFromRouter:test_EnforceOutOfOrder_Revert() (gas: 99602) -EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 118721) -EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 118763) -EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 130499) -EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 139025) -EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 130179) -EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddressEncodePacked_Revert() (gas: 40605) -EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddress_Revert() (gas: 40800) -EVM2EVMOnRamp_forwardFromRouter:test_InvalidChainSelector_Revert() (gas: 25631) -EVM2EVMOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 25417) -EVM2EVMOnRamp_forwardFromRouter:test_MaxCapacityExceeded_Revert() (gas: 86092) -EVM2EVMOnRamp_forwardFromRouter:test_MaxFeeBalanceReached_Revert() (gas: 36581) -EVM2EVMOnRamp_forwardFromRouter:test_MessageGasLimitTooHigh_Revert() (gas: 29163) -EVM2EVMOnRamp_forwardFromRouter:test_MessageTooLarge_Revert() (gas: 107646) -EVM2EVMOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 22755) -EVM2EVMOnRamp_forwardFromRouter:test_OverValueWithARLOff_Success() (gas: 224149) -EVM2EVMOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 54055) -EVM2EVMOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 25601) -EVM2EVMOnRamp_forwardFromRouter:test_PriceNotFoundForToken_Revert() (gas: 59214) -EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 182848) -EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 178451) -EVM2EVMOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 137487) -EVM2EVMOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3735328) -EVM2EVMOnRamp_forwardFromRouter:test_TooManyTokens_Revert() (gas: 30307) -EVM2EVMOnRamp_forwardFromRouter:test_Unhealthy_Revert() (gas: 43356) -EVM2EVMOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 109493) -EVM2EVMOnRamp_forwardFromRouter:test_ZeroAddressReceiver_Revert() (gas: 336597) -EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_ShouldStoreLinkFees_Success() (gas: 112694) -EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 72556) -EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 148168) -EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 191115) -EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 122367) -EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2_Success() (gas: 95509) +EVM2EVMOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 35788) +EVM2EVMOnRamp_forwardFromRouter:test_EnforceOutOfOrder_Revert() (gas: 99488) +EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 118607) +EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 118649) +EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 130385) +EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 138911) +EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 130065) +EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddressEncodePacked_Revert() (gas: 40491) +EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddress_Revert() (gas: 40686) +EVM2EVMOnRamp_forwardFromRouter:test_InvalidChainSelector_Revert() (gas: 25517) +EVM2EVMOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 25303) +EVM2EVMOnRamp_forwardFromRouter:test_MaxCapacityExceeded_Revert() (gas: 85978) +EVM2EVMOnRamp_forwardFromRouter:test_MaxFeeBalanceReached_Revert() (gas: 36467) +EVM2EVMOnRamp_forwardFromRouter:test_MessageGasLimitTooHigh_Revert() (gas: 29049) +EVM2EVMOnRamp_forwardFromRouter:test_MessageTooLarge_Revert() (gas: 107532) +EVM2EVMOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 22641) +EVM2EVMOnRamp_forwardFromRouter:test_OverValueWithARLOff_Success() (gas: 223807) +EVM2EVMOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 53941) +EVM2EVMOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 25487) +EVM2EVMOnRamp_forwardFromRouter:test_PriceNotFoundForToken_Revert() (gas: 59100) +EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 182506) +EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 178109) +EVM2EVMOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 137373) +EVM2EVMOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3734188) +EVM2EVMOnRamp_forwardFromRouter:test_TooManyTokens_Revert() (gas: 30193) +EVM2EVMOnRamp_forwardFromRouter:test_Unhealthy_Revert() (gas: 43306) +EVM2EVMOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 109379) +EVM2EVMOnRamp_forwardFromRouter:test_ZeroAddressReceiver_Revert() (gas: 335457) +EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_ShouldStoreLinkFees_Success() (gas: 112580) +EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 72442) +EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 147940) +EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 190773) +EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 122025) +EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2_Success() (gas: 95395) EVM2EVMOnRamp_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 20760) EVM2EVMOnRamp_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 21128) EVM2EVMOnRamp_getFee:test_EmptyMessage_Success() (gas: 78194) @@ -486,7 +486,7 @@ EVM2EVMOnRamp_payNops:test_NoFeesToPay_Revert() (gas: 127459) EVM2EVMOnRamp_payNops:test_NoNopsToPay_Revert() (gas: 133360) EVM2EVMOnRamp_payNops:test_NopPayNops_Success() (gas: 146371) EVM2EVMOnRamp_payNops:test_OwnerPayNops_Success() (gas: 140962) -EVM2EVMOnRamp_payNops:test_PayNopsSuccessAfterSetNops() (gas: 297945) +EVM2EVMOnRamp_payNops:test_PayNopsSuccessAfterSetNops() (gas: 297831) EVM2EVMOnRamp_payNops:test_WrongPermissions_Revert() (gas: 15324) EVM2EVMOnRamp_setDynamicConfig:test_SetConfigInvalidConfig_Revert() (gas: 43376) EVM2EVMOnRamp_setDynamicConfig:test_SetConfigOnlyOwner_Revert() (gas: 21646) @@ -495,10 +495,10 @@ EVM2EVMOnRamp_setFeeTokenConfig:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 1 EVM2EVMOnRamp_setFeeTokenConfig:test_SetFeeTokenConfigByAdmin_Success() (gas: 16467) EVM2EVMOnRamp_setFeeTokenConfig:test_SetFeeTokenConfig_Success() (gas: 14020) EVM2EVMOnRamp_setNops:test_AdminCanSetNops_Success() (gas: 61788) -EVM2EVMOnRamp_setNops:test_IncludesPayment_Success() (gas: 469556) +EVM2EVMOnRamp_setNops:test_IncludesPayment_Success() (gas: 469442) EVM2EVMOnRamp_setNops:test_LinkTokenCannotBeNop_Revert() (gas: 57290) EVM2EVMOnRamp_setNops:test_NonOwnerOrAdmin_Revert() (gas: 14683) -EVM2EVMOnRamp_setNops:test_NotEnoughFundsForPayout_Revert() (gas: 84914) +EVM2EVMOnRamp_setNops:test_NotEnoughFundsForPayout_Revert() (gas: 84800) EVM2EVMOnRamp_setNops:test_SetNopsRemovesOldNopsCompletely_Success() (gas: 60696) EVM2EVMOnRamp_setNops:test_SetNops_Success() (gas: 173721) EVM2EVMOnRamp_setNops:test_TooManyNops_Revert() (gas: 190364) @@ -507,9 +507,9 @@ EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_InvalidD EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_OnlyCallableByOwnerOrAdmin_Revert() (gas: 14295) EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_Success() (gas: 84069) EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_byAdmin_Success() (gas: 17387) -EVM2EVMOnRamp_withdrawNonLinkFees:test_LinkBalanceNotSettled_Revert() (gas: 83375) +EVM2EVMOnRamp_withdrawNonLinkFees:test_LinkBalanceNotSettled_Revert() (gas: 83261) EVM2EVMOnRamp_withdrawNonLinkFees:test_NonOwnerOrAdmin_Revert() (gas: 15293) -EVM2EVMOnRamp_withdrawNonLinkFees:test_SettlingBalance_Success() (gas: 272352) +EVM2EVMOnRamp_withdrawNonLinkFees:test_SettlingBalance_Success() (gas: 272260) EVM2EVMOnRamp_withdrawNonLinkFees:test_WithdrawNonLinkFees_Success() (gas: 53472) EVM2EVMOnRamp_withdrawNonLinkFees:test_WithdrawToZeroAddress_Revert() (gas: 12856) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96729) @@ -547,14 +547,14 @@ LockReleaseTokenPoolPoolAndProxy_supportsInterface:test_SupportsInterface_Succes LockReleaseTokenPoolPoolAndProxy_withdrawalLiquidity:test_InsufficientLiquidity_Revert() (gas: 60043) LockReleaseTokenPoolPoolAndProxy_withdrawalLiquidity:test_Unauthorized_Revert() (gas: 11355) LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 3068883) -LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30068) -LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Success() (gas: 80096) -LockReleaseTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 59514) +LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 29954) +LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Success() (gas: 79868) +LockReleaseTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 59464) LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 3065325) LockReleaseTokenPool_provideLiquidity:test_Unauthorized_Revert() (gas: 11380) -LockReleaseTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 72753) -LockReleaseTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 56181) -LockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_Success() (gas: 238764) +LockReleaseTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 72662) +LockReleaseTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 56131) +LockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_Success() (gas: 238673) LockReleaseTokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17102) LockReleaseTokenPool_setChainRateLimiterConfig:test_OnlyOwnerOrRateLimitAdmin_Revert() (gas: 69075) LockReleaseTokenPool_setChainRateLimiterConfig:test_OnlyOwner_Revert() (gas: 17297) @@ -650,16 +650,16 @@ MultiOCR3Base_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 24191) MultiOCR3Base_transmit:test_UnauthorizedSigner_Revert() (gas: 61409) MultiOCR3Base_transmit:test_UnconfiguredPlugin_Revert() (gas: 39890) MultiOCR3Base_transmit:test_ZeroSignatures_Revert() (gas: 32973) -MultiRampsE2E:test_E2E_3MessagesSuccess_gas() (gas: 1412650) +MultiRampsE2E:test_E2E_3MessagesSuccess_gas() (gas: 1411191) NonceManagerTest_getIncrementedOutboundNonce:test_getIncrementedOutboundNonce_Success() (gas: 40392) NonceManager_applyPreviousRampsUpdates:test_MultipleRampsUpdates() (gas: 68922) NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOnRamp_Revert() (gas: 38712) NonceManager_applyPreviousRampsUpdates:test_SingleRampUpdate() (gas: 39539) NonceManager_applyPreviousRampsUpdates:test_ZeroInput() (gas: 12007) -NonceManager_onRampUpgrade:test_UpgradeNonceNewSenderStartsAtZero_Success() (gas: 173566) -NonceManager_onRampUpgrade:test_UpgradeNonceStartsAtV1Nonce_Success() (gas: 217628) -NonceManager_onRampUpgrade:test_UpgradeSenderNoncesReadsPreviousRamp_Success() (gas: 125961) -NonceManager_onRampUpgrade:test_Upgrade_Success() (gas: 120933) +NonceManager_onRampUpgrade:test_UpgradeNonceNewSenderStartsAtZero_Success() (gas: 173338) +NonceManager_onRampUpgrade:test_UpgradeNonceStartsAtV1Nonce_Success() (gas: 217286) +NonceManager_onRampUpgrade:test_UpgradeSenderNoncesReadsPreviousRamp_Success() (gas: 125619) +NonceManager_onRampUpgrade:test_Upgrade_Success() (gas: 120819) OCR2BaseNoChecks_setOCR2Config:test_FMustBePositive_Revert() (gas: 12171) OCR2BaseNoChecks_setOCR2Config:test_RepeatAddress_Revert() (gas: 42233) OCR2BaseNoChecks_setOCR2Config:test_SetConfigSuccess_gas() (gas: 84124) @@ -685,10 +685,10 @@ OCR2Base_transmit:test_Transmit2SignersSuccess_gas() (gas: 51686) OCR2Base_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 23484) OCR2Base_transmit:test_UnauthorizedSigner_Revert() (gas: 39665) OCR2Base_transmit:test_WrongNumberOfSignatures_Revert() (gas: 20557) -OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 380951) -PingPong_ccipReceive:test_CcipReceive_Success() (gas: 148731) +OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 380711) +PingPong_ccipReceive:test_CcipReceive_Success() (gas: 148611) PingPong_plumbing:test_Pausing_Success() (gas: 17803) -PingPong_startPingPong:test_StartPingPong_Success() (gas: 178667) +PingPong_startPingPong:test_StartPingPong_Success() (gas: 178547) PriceRegistry_applyFeeTokensUpdates:test_ApplyFeeTokensUpdates_Success() (gas: 79823) PriceRegistry_applyFeeTokensUpdates:test_OnlyCallableByOwner_Revert() (gas: 12580) PriceRegistry_constructor:test_InvalidStalenessThreshold_Revert() (gas: 67418) @@ -726,40 +726,62 @@ PriceRegistry_updateTokenPriceFeeds:test_FeedUpdatedByNonOwner_Revert() (gas: 19 PriceRegistry_updateTokenPriceFeeds:test_MultipleFeedUpdate_Success() (gas: 88796) PriceRegistry_updateTokenPriceFeeds:test_SingleFeedUpdate_Success() (gas: 50733) PriceRegistry_updateTokenPriceFeeds:test_ZeroFeeds_Success() (gas: 12296) -RMN_constructor:test_Constructor_Success() (gas: 58091) -RMN_ownerUnbless:test_Unbless_Success() (gas: 71926) -RMN_ownerUnvoteToCurse:test_CanBlessAndCurseAfterRecovery() (gas: 236626) -RMN_ownerUnvoteToCurse:test_IsIdempotent() (gas: 198633) -RMN_ownerUnvoteToCurse:test_NonOwner_Revert() (gas: 14981) -RMN_ownerUnvoteToCurse:test_OwnerUnvoteToCurseSuccess_gas() (gas: 179810) -RMN_setConfig:test_BlessVoterIsZeroAddress_Revert() (gas: 17975) -RMN_setConfig:test_EitherThresholdIsZero_Revert() (gas: 25955) -RMN_setConfig:test_NonOwner_Revert() (gas: 15063) -RMN_setConfig:test_RepeatedAddress_Revert() (gas: 21309) -RMN_setConfig:test_SetConfigSuccess_gas() (gas: 111473) -RMN_setConfig:test_TotalWeightsSmallerThanEachThreshold_Revert() (gas: 39589) -RMN_setConfig:test_VoteToBlessByEjectedVoter_Revert() (gas: 142372) -RMN_setConfig:test_VotersLengthIsZero_Revert() (gas: 14272) -RMN_setConfig:test_WeightIsZeroAddress_Revert() (gas: 18174) -RMN_unvoteToCurse:test_InvalidCurseState_Revert() (gas: 18158) -RMN_unvoteToCurse:test_InvalidCursesHash() (gas: 23200) -RMN_unvoteToCurse:test_InvalidVoter() (gas: 86794) -RMN_unvoteToCurse:test_OwnerSkips() (gas: 29220) -RMN_unvoteToCurse:test_OwnerSucceeds() (gas: 26951) -RMN_unvoteToCurse:test_ValidCursesHash() (gas: 31510) -RMN_voteToBlessRoots:test_1RootSuccess_gas() (gas: 45454) -RMN_voteToBlessRoots:test_3RootSuccess_gas() (gas: 99549) -RMN_voteToBlessRoots:test_5RootSuccess_gas() (gas: 153757) -RMN_voteToBlessRoots:test_Curse_Revert() (gas: 244265) -RMN_voteToBlessRoots:test_InvalidVoter_Revert() (gas: 17029) -RMN_voteToBlessRoots:test_IsAlreadyBlessedIgnored_Success() (gas: 124904) -RMN_voteToBlessRoots:test_SenderAlreadyVotedIgnored_Success() (gas: 114423) -RMN_voteToCurse:test_AlreadyVoted_Revert() (gas: 74738) -RMN_voteToCurse:test_EmitCurse_Success() (gas: 243463) -RMN_voteToCurse:test_EvenIfAlreadyCursed_Success() (gas: 275806) -RMN_voteToCurse:test_InvalidVoter_Revert() (gas: 13671) -RMN_voteToCurse:test_OwnerCanCurseAndUncurse() (gas: 194255) -RMN_voteToCurse:test_VoteToCurseSuccess_gas() (gas: 70265) +RMN_constructor:test_Constructor_Success() (gas: 48838) +RMN_getRecordedCurseRelatedOps:test_OpsPostDeployment() (gas: 19666) +RMN_lazyVoteToCurseUpdate_Benchmark:test_VoteToCurseLazilyRetain3VotersUponConfigChange_gas() (gas: 152152) +RMN_ownerUnbless:test_Unbless_Success() (gas: 74699) +RMN_ownerUnvoteToCurse:test_CanBlessAndCurseAfterGlobalCurseIsLifted() (gas: 470965) +RMN_ownerUnvoteToCurse:test_IsIdempotent() (gas: 397532) +RMN_ownerUnvoteToCurse:test_NonOwner_Revert() (gas: 18591) +RMN_ownerUnvoteToCurse:test_OwnerUnvoteToCurseSuccess_gas() (gas: 357403) +RMN_ownerUnvoteToCurse:test_UnknownVoter_Revert() (gas: 32980) +RMN_ownerUnvoteToCurse_Benchmark:test_OwnerUnvoteToCurse_1Voter_LiftsCurse_gas() (gas: 261985) +RMN_permaBlessing:test_PermaBlessing() (gas: 202686) +RMN_setConfig:test_BlessVoterIsZeroAddress_Revert() (gas: 15494) +RMN_setConfig:test_EitherThresholdIsZero_Revert() (gas: 21095) +RMN_setConfig:test_NonOwner_Revert() (gas: 14713) +RMN_setConfig:test_RepeatedAddress_Revert() (gas: 18213) +RMN_setConfig:test_SetConfigSuccess_gas() (gas: 104204) +RMN_setConfig:test_TotalWeightsSmallerThanEachThreshold_Revert() (gas: 30173) +RMN_setConfig:test_VoteToBlessByEjectedVoter_Revert() (gas: 130303) +RMN_setConfig:test_VotersLengthIsZero_Revert() (gas: 12128) +RMN_setConfig:test_WeightIsZeroAddress_Revert() (gas: 15734) +RMN_setConfig_Benchmark_1:test_SetConfig_7Voters_gas() (gas: 659123) +RMN_setConfig_Benchmark_2:test_ResetConfig_7Voters_gas() (gas: 212156) +RMN_unvoteToCurse:test_InvalidCursesHash() (gas: 26364) +RMN_unvoteToCurse:test_OwnerSkips() (gas: 33753) +RMN_unvoteToCurse:test_OwnerSucceeds() (gas: 63909) +RMN_unvoteToCurse:test_UnauthorizedVoter() (gas: 47478) +RMN_unvoteToCurse:test_ValidCursesHash() (gas: 61067) +RMN_unvoteToCurse:test_VotersCantLiftCurseButOwnerCan() (gas: 627750) +RMN_voteToBless:test_Curse_Revert() (gas: 472823) +RMN_voteToBless:test_IsAlreadyBlessed_Revert() (gas: 114829) +RMN_voteToBless:test_RootSuccess() (gas: 555559) +RMN_voteToBless:test_SenderAlreadyVoted_Revert() (gas: 96730) +RMN_voteToBless:test_UnauthorizedVoter_Revert() (gas: 17087) +RMN_voteToBless_Benchmark:test_1RootSuccess_gas() (gas: 44667) +RMN_voteToBless_Benchmark:test_3RootSuccess_gas() (gas: 98565) +RMN_voteToBless_Benchmark:test_5RootSuccess_gas() (gas: 152401) +RMN_voteToBless_Blessed_Benchmark:test_1RootSuccessBecameBlessed_gas() (gas: 29619) +RMN_voteToBless_Blessed_Benchmark:test_1RootSuccess_gas() (gas: 27565) +RMN_voteToBless_Blessed_Benchmark:test_3RootSuccess_gas() (gas: 81485) +RMN_voteToBless_Blessed_Benchmark:test_5RootSuccess_gas() (gas: 135299) +RMN_voteToCurse:test_CurseOnlyWhenThresholdReached_Success() (gas: 1648701) +RMN_voteToCurse:test_EmptySubjects_Revert() (gas: 14019) +RMN_voteToCurse:test_EvenIfAlreadyCursed_Success() (gas: 534332) +RMN_voteToCurse:test_OwnerCanCurseAndUncurse() (gas: 399001) +RMN_voteToCurse:test_RepeatedSubject_Revert() (gas: 144225) +RMN_voteToCurse:test_ReusedCurseId_Revert() (gas: 146738) +RMN_voteToCurse:test_UnauthorizedVoter_Revert() (gas: 12600) +RMN_voteToCurse:test_VoteToCurse_NoCurse_Success() (gas: 187244) +RMN_voteToCurse:test_VoteToCurse_YesCurse_Success() (gas: 472452) +RMN_voteToCurse_2:test_VotesAreDroppedIfSubjectIsNotCursedDuringConfigChange() (gas: 370468) +RMN_voteToCurse_2:test_VotesAreRetainedIfSubjectIsCursedDuringConfigChange() (gas: 1151909) +RMN_voteToCurse_Benchmark_1:test_VoteToCurse_NewSubject_NewVoter_NoCurse_gas() (gas: 140968) +RMN_voteToCurse_Benchmark_1:test_VoteToCurse_NewSubject_NewVoter_YesCurse_gas() (gas: 165087) +RMN_voteToCurse_Benchmark_2:test_VoteToCurse_OldSubject_NewVoter_NoCurse_gas() (gas: 121305) +RMN_voteToCurse_Benchmark_2:test_VoteToCurse_OldSubject_OldVoter_NoCurse_gas() (gas: 98247) +RMN_voteToCurse_Benchmark_3:test_VoteToCurse_OldSubject_NewVoter_YesCurse_gas() (gas: 145631) RateLimiter_constructor:test_Constructor_Success() (gas: 19650) RateLimiter_consume:test_AggregateValueMaxCapacityExceeded_Revert() (gas: 15916) RateLimiter_consume:test_AggregateValueRateLimitReached_Revert() (gas: 22222) @@ -779,24 +801,24 @@ RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetC RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Revert() (gas: 19451) RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Success() (gas: 129731) Router_applyRampUpdates:test_OffRampMismatch_Revert() (gas: 89288) -Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10643448) +Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10642128) Router_applyRampUpdates:test_OnRampDisable() (gas: 55913) Router_applyRampUpdates:test_OnlyOwner_Revert() (gas: 12311) -Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 114212) -Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 201163) -Router_ccipSend:test_CCIPSendNativeFeeNoTokenSuccess_gas() (gas: 128820) -Router_ccipSend:test_CCIPSendNativeFeeOneTokenSuccess_gas() (gas: 215773) -Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 66257) -Router_ccipSend:test_InvalidMsgValue() (gas: 31969) -Router_ccipSend:test_NativeFeeTokenInsufficientValue() (gas: 68693) -Router_ccipSend:test_NativeFeeTokenOverpay_Success() (gas: 173893) -Router_ccipSend:test_NativeFeeTokenZeroValue() (gas: 56019) -Router_ccipSend:test_NativeFeeToken_Success() (gas: 172487) -Router_ccipSend:test_NonLinkFeeToken_Success() (gas: 243022) -Router_ccipSend:test_UnsupportedDestinationChain_Revert() (gas: 24755) -Router_ccipSend:test_WhenNotHealthy_Revert() (gas: 44669) -Router_ccipSend:test_WrappedNativeFeeToken_Success() (gas: 174703) -Router_ccipSend:test_ZeroFeeAndGasPrice_Success() (gas: 243269) +Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 114092) +Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 200929) +Router_ccipSend:test_CCIPSendNativeFeeNoTokenSuccess_gas() (gas: 128700) +Router_ccipSend:test_CCIPSendNativeFeeOneTokenSuccess_gas() (gas: 215539) +Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 66251) +Router_ccipSend:test_InvalidMsgValue() (gas: 31963) +Router_ccipSend:test_NativeFeeTokenInsufficientValue() (gas: 68687) +Router_ccipSend:test_NativeFeeTokenOverpay_Success() (gas: 173773) +Router_ccipSend:test_NativeFeeTokenZeroValue() (gas: 56013) +Router_ccipSend:test_NativeFeeToken_Success() (gas: 172367) +Router_ccipSend:test_NonLinkFeeToken_Success() (gas: 242902) +Router_ccipSend:test_UnsupportedDestinationChain_Revert() (gas: 24749) +Router_ccipSend:test_WhenNotHealthy_Revert() (gas: 44724) +Router_ccipSend:test_WrappedNativeFeeToken_Success() (gas: 174583) +Router_ccipSend:test_ZeroFeeAndGasPrice_Success() (gas: 243149) Router_constructor:test_Constructor_Success() (gas: 13074) Router_getArmProxy:test_getArmProxy() (gas: 10561) Router_getFee:test_GetFeeSupportedChain_Success() (gas: 46440) @@ -807,14 +829,14 @@ Router_recoverTokens:test_RecoverTokensNoFunds_Revert() (gas: 17761) Router_recoverTokens:test_RecoverTokensNonOwner_Revert() (gas: 11159) Router_recoverTokens:test_RecoverTokensValueReceiver_Revert() (gas: 422138) Router_recoverTokens:test_RecoverTokens_Success() (gas: 50437) -Router_routeMessage:test_AutoExec_Success() (gas: 42696) -Router_routeMessage:test_ExecutionEvent_Success() (gas: 158020) -Router_routeMessage:test_ManualExec_Success() (gas: 35387) -Router_routeMessage:test_OnlyOffRamp_Revert() (gas: 25122) -Router_routeMessage:test_WhenNotHealthy_Revert() (gas: 44669) +Router_routeMessage:test_AutoExec_Success() (gas: 42684) +Router_routeMessage:test_ExecutionEvent_Success() (gas: 158002) +Router_routeMessage:test_ManualExec_Success() (gas: 35381) +Router_routeMessage:test_OnlyOffRamp_Revert() (gas: 25116) +Router_routeMessage:test_WhenNotHealthy_Revert() (gas: 44724) Router_setWrappedNative:test_OnlyOwner_Revert() (gas: 10985) SelfFundedPingPong_ccipReceive:test_FundingIfNotANop_Revert() (gas: 53600) -SelfFundedPingPong_ccipReceive:test_Funding_Success() (gas: 418951) +SelfFundedPingPong_ccipReceive:test_Funding_Success() (gas: 418231) SelfFundedPingPong_setCountIncrBeforeFunding:test_setCountIncrBeforeFunding() (gas: 20157) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_OnlyPendingAdministrator_Revert() (gas: 51085) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_Success() (gas: 43947) @@ -838,10 +860,10 @@ TokenAdminRegistry_setPool:test_setPool_Success() (gas: 35943) TokenAdminRegistry_setPool:test_setPool_ZeroAddressRemovesPool_Success() (gas: 30617) TokenAdminRegistry_transferAdminRole:test_transferAdminRole_OnlyAdministrator_Revert() (gas: 18043) TokenAdminRegistry_transferAdminRole:test_transferAdminRole_Success() (gas: 49390) -TokenPoolAndProxy:test_lockOrBurn_burnMint_Success() (gas: 6038283) -TokenPoolAndProxy:test_lockOrBurn_lockRelease_Success() (gas: 6284039) -TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_2() (gas: 6886284) -TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_4() (gas: 7070387) +TokenPoolAndProxy:test_lockOrBurn_burnMint_Success() (gas: 6037815) +TokenPoolAndProxy:test_lockOrBurn_lockRelease_Success() (gas: 6283571) +TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_2() (gas: 6885180) +TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_4() (gas: 7069295) TokenPoolWithAllowList_applyAllowListUpdates:test_AllowListNotEnabled_Revert() (gas: 2169749) TokenPoolWithAllowList_applyAllowListUpdates:test_OnlyOwner_Revert() (gas: 12089) TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowListSkipsZero_Success() (gas: 23280) @@ -872,23 +894,23 @@ TokenPool_setRemotePool:test_setRemotePool_Success() (gas: 281890) TokenProxy_ccipSend:test_CcipSendGasShouldBeZero_Revert() (gas: 17109) TokenProxy_ccipSend:test_CcipSendInsufficientAllowance_Revert() (gas: 136327) TokenProxy_ccipSend:test_CcipSendInvalidToken_Revert() (gas: 15919) -TokenProxy_ccipSend:test_CcipSendNative_Success() (gas: 244973) +TokenProxy_ccipSend:test_CcipSendNative_Success() (gas: 244739) TokenProxy_ccipSend:test_CcipSendNoDataAllowed_Revert() (gas: 16303) -TokenProxy_ccipSend:test_CcipSend_Success() (gas: 261504) +TokenProxy_ccipSend:test_CcipSend_Success() (gas: 261316) TokenProxy_constructor:test_Constructor() (gas: 13812) TokenProxy_getFee:test_GetFeeGasShouldBeZero_Revert() (gas: 16827) TokenProxy_getFee:test_GetFeeInvalidToken_Revert() (gas: 12658) TokenProxy_getFee:test_GetFeeNoDataAllowed_Revert() (gas: 15849) TokenProxy_getFee:test_GetFee_Success() (gas: 86900) USDCTokenPool__validateMessage:test_ValidateInvalidMessage_Revert() (gas: 24960) -USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35446) -USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30189) -USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 132972) -USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 477343) -USDCTokenPool_lockOrBurn:test_lockOrBurn_InvalidReceiver_Revert() (gas: 52740) -USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 289360) -USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 50796) -USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 119299) +USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35332) +USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30075) +USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 132880) +USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 477229) +USDCTokenPool_lockOrBurn:test_lockOrBurn_InvalidReceiver_Revert() (gas: 52626) +USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 289268) +USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 50682) +USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 119185) USDCTokenPool_setDomains:test_InvalidDomain_Revert() (gas: 66150) USDCTokenPool_setDomains:test_OnlyOwner_Revert() (gas: 11339) USDCTokenPool_supportsInterface:test_SupportsInterface_Success() (gas: 9876) \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_ccip b/contracts/scripts/native_solc_compile_all_ccip index 4c73cc552a..63ffdca7f6 100755 --- a/contracts/scripts/native_solc_compile_all_ccip +++ b/contracts/scripts/native_solc_compile_all_ccip @@ -82,7 +82,7 @@ compileContract ccip/test/helpers/BurnMintERC677Helper.sol compileContract ccip/test/helpers/CommitStoreHelper.sol compileContract ccip/test/helpers/MessageHasher.sol compileContract ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol -compileContract ccip/test/mocks/MockRMN.sol +compileContract ccip/test/mocks/MockRMN1_0.sol compileContract ccip/test/mocks/MockE2EUSDCTokenMessenger.sol compileContract ccip/test/mocks/MockE2EUSDCTransmitter.sol compileContract ccip/test/WETH9.sol diff --git a/contracts/src/v0.8/ccip/RMN.sol b/contracts/src/v0.8/ccip/RMN.sol index ec11aa4816..09dde65945 100644 --- a/contracts/src/v0.8/ccip/RMN.sol +++ b/contracts/src/v0.8/ccip/RMN.sol @@ -6,23 +6,48 @@ import {IRMN} from "./interfaces/IRMN.sol"; import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol"; +import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; + +// An active curse on this subject will cause isCursed() to return true. Use this subject if there is an issue with a +// remote chain, for which there exists a legacy lane contract deployed on the same chain as this RMN contract is +// deployed, relying on isCursed(). +bytes16 constant LEGACY_CURSE_SUBJECT = 0x01000000000000000000000000000000; + +// An active curse on this subject will cause isCursed() and isCursed(bytes32) to return true. Use this subject for +// issues affecting all of CCIP chains, or pertaining to the chain that this contract is deployed on, instead of using +// the local chain selector as a subject. +bytes16 constant GLOBAL_CURSE_SUBJECT = 0x01000000000000000000000000000001; + +// The curse vote address representing the owner in data structures, events and recorded votes. Remains constant, even +// if the owner changes. +address constant OWNER_CURSE_VOTE_ADDR = address(~uint160(0)); // 0xff...ff + +// The curse vote address used in an OwnerUnvoteToCurseRequest to lift a curse, if there is no active curse votes for +// the subject that we are able to unvote, but the conditions for an active curse no longer hold. +address constant LIFT_CURSE_VOTE_ADDR = address(0); + /// @dev This contract is owned by RMN, if changing, please notify the RMN maintainers. // solhint-disable chainlink-solidity/explicit-returns contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { + using EnumerableSet for EnumerableSet.AddressSet; + // STATIC CONFIG string public constant override typeAndVersion = "RMN 1.5.0-dev"; - uint256 private constant MAX_NUM_VOTERS = 128; + uint256 private constant MAX_NUM_VOTERS = 16; + + // MAGIC VALUES + bytes28 private constant NO_VOTES_CURSES_HASH = bytes28(0); // DYNAMIC CONFIG - //solhint-disable gas-struct-packing + /// @notice blessVoteAddr and curseVoteAddr can't be 0. Additionally curseVoteAddr can't be LIFT_CURSE_VOTE_ADDR or + /// OWNER_CURSE_VOTE_ADDR. At least one of blessWeight & curseWeight must be non-zero, i.e., a voter could only vote + /// to bless, or only vote to curse, or both vote to bless and vote to curse. struct Voter { // This is the address the voter should use to call voteToBless. address blessVoteAddr; // This is the address the voter should use to call voteToCurse. address curseVoteAddr; - // This is the address the voter should use to call unvoteToCurse. - address curseUnvoteAddr; // The weight of this voter's vote for blessing. uint8 blessWeight; // The weight of this voter's vote for cursing. @@ -34,8 +59,8 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { // When the total weight of voters that have voted to bless a tagged root reaches // or exceeds blessWeightThreshold, the tagged root becomes blessed. uint16 blessWeightThreshold; - // When the total weight of voters that have voted to curse reaches or - // exceeds curseWeightThreshold, the RMN enters the cursed state. + // When the total weight of voters that have voted to curse a subject reaches or + // exceeds curseWeightThreshold, the subject becomes cursed. uint16 curseWeightThreshold; } @@ -65,58 +90,154 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { mapping(address blessVoteAddr => BlesserRecord blesserRecord) private s_blesserRecords; struct BlessVoteProgress { + // This particular ordering saves us ~400 gas per voteToBless call, compared to the bool being at the bottom, even + // though the size of the struct is the same. + bool weightThresholdMet; // A BlessVoteProgress is considered invalid if weightThresholdMet is false when // s_versionedConfig.configVersion changes. we don't want old in-progress // votes to continue when we set a new config! // The config version at which the bless vote for a tagged root was initiated. uint32 configVersion; uint16 accumulatedWeight; - // Care must be taken that the bitmap has as many bits as MAX_NUM_VOTERS. - uint128 voterBitmap; - bool weightThresholdMet; + // Care must be taken that the bitmap has at least as many bits as MAX_NUM_VOTERS. + // uint200 is much larger than we need, but it saves us ~100 gas per voteToBless call to fill the word instead of + // using a smaller type. + uint200 voterBitmap; } mapping(bytes32 taggedRootHash => BlessVoteProgress blessVoteProgress) private s_blessVoteProgressByTaggedRootHash; - // voteCount and cursesHash can be reset through unvoteToCurse, and ownerUnvoteToCurse, and may be reset through - // setConfig if the curser is not part of the new config. + // Any tagged root with a commit store included in s_permaBlessedCommitStores will be considered automatically + // blessed. + EnumerableSet.AddressSet private s_permaBlessedCommitStores; + struct CurserRecord { bool active; uint8 weight; - uint32 voteCount; - address curseUnvoteAddr; - bytes32 cursesHash; + mapping(bytes16 curseId => bool used) usedCurseIds; // retained across config changes } mapping(address curseVoteAddr => CurserRecord curserRecord) private s_curserRecords; - // Maintains a per-curser set of curseIds. Entries from this mapping are - // never cleared. Once a curseId is used it can never be reused, even after - // an unvoteToCurse or ownerUnvoteToCurse. This is to prevent accidental - // re-votes to curse, e.g. caused by TOCTOU issues. - mapping(address curseVoteAddr => mapping(bytes32 curseId => bool voted)) private s_curseVotes; + struct ConfigVersionAndCursesHash { + uint32 configVersion; // configVersion != s_versionedConfig.configVersion means no active vote + bytes28 cursesHash; // bytes28(0) means no active vote; truncated so that ConfigVersionAndCursesHash fits in a word + } struct CurseVoteProgress { - uint16 curseWeightThreshold; - uint16 accumulatedWeight; - // A curse becomes active after: - // - accumulatedWeight becomes greater or equal than curseWeightThreshold; or - // - the owner curses. + uint32 configVersion; // upon config change, lazy set to new config version + uint16 curseWeightThreshold; // upon config change, lazy set to new config value + uint16 accumulatedWeight; // upon config change, lazy set to 0 + // A curse becomes active after either: + // - sum([voter.weight for voter who voted in current config]) >= curseWeightThreshold + // - ownerCurse is invoked // Once a curse is active, only the owner can lift it. - bool curseActive; + bool curseActive; // retained across config changes + mapping(address => ConfigVersionAndCursesHash) latestVoteToCurseByCurseVoteAddr; // retained across config changes } - CurseVoteProgress private s_curseVoteProgress; + mapping(bytes16 subject => CurseVoteProgress curseVoteProgress) private + s_potentiallyOutdatedCurseVoteProgressBySubject; - // AUXILLARY STRUCTS - //solhint-disable gas-struct-packing - struct UnvoteToCurseRecord { - address curseVoteAddr; - bytes32 cursesHash; - bool forceUnvote; + struct CurseHotVars { + uint64 numSubjectsCursed; // incremented by voteToCurse, ownerCurse; decremented by ownerUnvoteToCurse + } + + CurseHotVars private s_curseHotVars; + + enum RecordedCurseRelatedOpTag { + // A vote to curse, through either voteToCurse or ownerCurse. + VoteToCurse, + // An unvote to curse, through unvoteToCurse. + UnvoteToCurse, + // An unvote to curse, through ownerUnvoteToCurse, which was not forced (forceUnvote=false). + OwnerUnvoteToCurseUnforced, + // An unvote to curse, through ownerUnvoteToCurse, which was forced (forceUnvote=true). + OwnerUnvoteToCurseForced, + // A configuration change. + // + // For subjects that are not cursed when this happens, past votes do not get accounted for in the new configuration. + // If a voter votes during the new configuration, their curses hash will restart from NO_VOTES_CURSES_HASH. + // + // For subjects that are cursed when this happens, past votes get accounted for. + // If a voter votes during the new configuration, their curses hash will continue from its old value. + SetConfig + } + + /// @notice Provides the ability to quickly reconstruct the curse-related state of the contract offchain, without + /// having to replay all past events. Replaying past events often takes long, and in some cases might even be + /// infeasible due to log pruning. + /// + /// @dev We could save some gas by omitting some fields and instead using them as mapping keys, but we would lose the + /// cross-voter ordering, or cross-subject ordering, or cross-vote/unvote ordering. + struct RecordedCurseRelatedOp { + RecordedCurseRelatedOpTag tag; + uint64 blockTimestamp; + bool cursed; // whether the subject is cursed after this op; if tag in {SetConfig}, will be false + address curseVoteAddr; // if tag in {SetConfig}, will be address(0) + bytes16 subject; // if tag in {SetConfig}, will be bytes16(0) + bytes16 curseId; // if tag in {SetConfig, UnvoteToCurse, OwnerUnvoteToCurseUnforced, OwnerUnvoteToCurseForced}, will be bytes16(0) + } + + RecordedCurseRelatedOp[] private s_recordedCurseRelatedOps; + + /// @dev This function is to _ONLY_ be called in order to determine if a curse should become active upon a + /// vote-to-curse, or a curse should be deactivated upon an owner-unvote-to-curse. + /// Other reasons for a curse to be active, which are not covered here: + /// 1. Cursedness is retained from a prior config. + /// 2. The curse weight threshold was met at some point, which activated a curse, and enough voters unvoted to curse + /// such that the curse weight threshold is no longer met. + function _shouldCurseBeActive(CurseVoteProgress storage sptr_upToDateCurseVoteProgress) internal view returns (bool) { + return sptr_upToDateCurseVoteProgress.latestVoteToCurseByCurseVoteAddr[OWNER_CURSE_VOTE_ADDR].cursesHash + != NO_VOTES_CURSES_HASH + || sptr_upToDateCurseVoteProgress.accumulatedWeight >= sptr_upToDateCurseVoteProgress.curseWeightThreshold; + } + + /// @dev It might be the case that due to the lazy update of curseVoteProgress, a curse is active even though + /// _shouldCurseBeActive(curseVoteProgress) is false, i.e., the owner has no active vote to curse and the curse + /// weight threshold has not been met. + function _getUpToDateCurseVoteProgress( + uint32 configVersion, + bytes16 subject + ) internal returns (CurseVoteProgress storage) { + CurseVoteProgress storage sptr_curseVoteProgress = s_potentiallyOutdatedCurseVoteProgressBySubject[subject]; + if (configVersion != sptr_curseVoteProgress.configVersion) { + sptr_curseVoteProgress.configVersion = configVersion; + sptr_curseVoteProgress.curseWeightThreshold = s_versionedConfig.config.curseWeightThreshold; + sptr_curseVoteProgress.accumulatedWeight = 0; + + if (sptr_curseVoteProgress.curseActive) { + // If a curse was active, count past votes to curse and retain the curses hash for cursers who are part of the + // new config. + Config storage sptr_config = s_versionedConfig.config; + for (uint256 i = 0; i < sptr_config.voters.length; ++i) { + Voter storage sptr_voter = sptr_config.voters[i]; + ConfigVersionAndCursesHash storage sptr_cvch = + sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[sptr_voter.curseVoteAddr]; + if (sptr_cvch.configVersion < configVersion && sptr_cvch.cursesHash != NO_VOTES_CURSES_HASH) { + // `< configVersion` instead of `== configVersion-1`, because there might have been multiple config changes + // without a lazy update of our subject. This has the side effect of retaining votes from very old configs + // that we might not really intend to retain, but these can be removed by the owner later. + sptr_cvch.configVersion = configVersion; + sptr_curseVoteProgress.accumulatedWeight += sptr_voter.curseWeight; + } + } + // We don't need to think about OWNER_CURSE_VOTE_ADDR here, because its ConfigVersionAndCursesHash counts even + // if the configVersion is not the current config version, in contrast to regular voters. + // It's an irregularity, but it saves us > 5k gas (if the owner had previously voted) for the unlucky voter who + // enters this branch. + } else { + // If a curse was not active, we don't count past votes to curse for voters who are part of the new config. + // Their curses hash will be restart from NO_VOTES_CURSES_HASH when they vote to curse again. + // We expect that the offchain code will revote to curse in case it voted to curse, and the vote to curse was + // lost due to any reason, including a config change when the curse was not yet active. + } + } + return sptr_curseVoteProgress; } // EVENTS, ERRORS + event ConfigSet(uint32 indexed configVersion, Config config); error InvalidConfig(); @@ -128,62 +249,72 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { event VotedToCurse( uint32 indexed configVersion, address indexed voter, + bytes16 subject, + bytes16 curseId, uint8 weight, - uint32 voteCount, - bytes32 curseId, - bytes32 cursesHash, + uint64 blockTimestamp, + bytes28 cursesHash, uint16 accumulatedWeight ); - event ReusedVotesToCurse( + event UnvotedToCurse( uint32 indexed configVersion, address indexed voter, + bytes16 subject, uint8 weight, - uint32 voteCount, - bytes32 cursesHash, - uint16 accumulatedWeight + bytes28 cursesHash, + uint16 remainingAccumulatedWeight ); - event UnvotedToCurse( - uint32 indexed configVersion, address indexed voter, uint8 weight, uint32 voteCount, bytes32 cursesHash - ); - event SkippedUnvoteToCurse(address indexed voter, bytes32 expectedCursesHash, bytes32 actualCursesHash); - event OwnerCursed(uint256 timestamp); - event Cursed(uint32 indexed configVersion, uint256 timestamp); + event SkippedUnvoteToCurse(address indexed voter, bytes16 subject, bytes28 onchainCursesHash, bytes28 cursesHash); + event Cursed(uint32 indexed configVersion, bytes16 subject, uint64 blockTimestamp); + event CurseLifted(bytes16 subject); // These events make it easier for offchain logic to discover that it performs // the same actions multiple times. event AlreadyVotedToBless(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot); event AlreadyBlessed(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot); - event RecoveredFromCurse(); + // Emitted by ownerRemoveThenAddPermaBlessedCommitStores. + event PermaBlessedCommitStoreAdded(address commitStore); + event PermaBlessedCommitStoreRemoved(address commitStore); + + error ReusedCurseId(address voter, bytes16 curseId); + error UnauthorizedVoter(address voter); + error VoteToBlessNoop(); + error VoteToCurseNoop(); + error UnvoteToCurseNoop(); + error VoteToBlessForbiddenDuringActiveGlobalCurse(); - error AlreadyVotedToCurse(address voter, bytes32 curseId); - error InvalidVoter(address voter); - error InvalidCurseState(); - error InvalidCursesHash(bytes32 expectedCursesHash, bytes32 actualCursesHash); - error MustRecoverFromCurse(); + /// @notice Thrown when subjects are not a strictly increasing monotone sequence. + // Prevents a subject from receiving multiple votes to curse with the same curse id. + error SubjectsMustBeStrictlyIncreasing(); constructor(Config memory config) { { // Ensure that the bitmap is large enough to hold MAX_NUM_VOTERS. // We do this in the constructor because MAX_NUM_VOTERS is constant. - BlessVoteProgress memory vp; - vp.voterBitmap = ~uint128(0); + BlessVoteProgress memory vp = BlessVoteProgress({ + configVersion: 0, + voterBitmap: type(uint200).max, // will not compile if it doesn't fit + accumulatedWeight: 0, + weightThresholdMet: false + }); assert(vp.voterBitmap >> (MAX_NUM_VOTERS - 1) >= 1); } _setConfig(config); } - function _bitmapGet(uint128 bitmap, uint8 index) internal pure returns (bool) { + function _bitmapGet(uint200 bitmap, uint8 index) internal pure returns (bool) { assert(index < MAX_NUM_VOTERS); - return bitmap & (uint128(1) << index) != 0; + return bitmap & (uint200(1) << index) != 0; } - function _bitmapSet(uint128 bitmap, uint8 index) internal pure returns (uint128) { + function _bitmapSet(uint200 bitmap, uint8 index) internal pure returns (uint200) { assert(index < MAX_NUM_VOTERS); - return bitmap | (uint128(1) << index); + return bitmap | (uint200(1) << index); } - function _bitmapCount(uint128 bitmap) internal pure returns (uint8 oneBits) { + function _bitmapCount(uint200 bitmap) internal pure returns (uint8 oneBits) { + assert(bitmap < 1 << MAX_NUM_VOTERS); // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan for (; bitmap != 0; ++oneBits) { bitmap &= bitmap - 1; @@ -194,18 +325,29 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { return keccak256(abi.encode(taggedRoot.commitStore, taggedRoot.root)); } + function _cursesHash(bytes28 prevCursesHash, bytes16 curseId) internal pure returns (bytes28) { + return bytes28(keccak256(abi.encode(prevCursesHash, curseId))); + } + + function _blockTimestamp() internal view returns (uint64) { + return uint64(block.timestamp); + } + /// @param taggedRoots A tagged root is hashed as `keccak256(abi.encode(taggedRoot.commitStore /// /* address */, taggedRoot.root /* bytes32 */))`. + /// @notice Tagged roots which are already (voted to be) blessed are skipped and emit corresponding events. In case + /// the call has no effect, i.e., all passed tagged roots are skipped, the function reverts with a `VoteToBlessNoop`. function voteToBless(IRMN.TaggedRoot[] calldata taggedRoots) external { - // If we have an active curse, something is really wrong. Let's err on the + // If we have an active global curse, something is really wrong. Let's err on the // side of caution and not accept further blessings during this time of // uncertainty. - if (isCursed()) revert MustRecoverFromCurse(); + if (isCursed(GLOBAL_CURSE_SUBJECT)) revert VoteToBlessForbiddenDuringActiveGlobalCurse(); uint32 configVersion = s_versionedConfig.configVersion; BlesserRecord memory blesserRecord = s_blesserRecords[msg.sender]; - if (blesserRecord.configVersion != configVersion) revert InvalidVoter(msg.sender); + if (blesserRecord.configVersion != configVersion) revert UnauthorizedVoter(msg.sender); + bool noop = true; for (uint256 i = 0; i < taggedRoots.length; ++i) { IRMN.TaggedRoot memory taggedRoot = taggedRoots[i]; bytes32 taggedRootHash = _taggedRootHash(taggedRoot); @@ -219,8 +361,7 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { // count, and we want to allow that to happen. emit AlreadyBlessed(configVersion, msg.sender, taggedRoot); continue; - } - if (voteProgress.configVersion != configVersion) { + } else if (voteProgress.configVersion != configVersion) { // Note that voteProgress.weightThresholdMet must be false at this point // If votes were received while an older config was in effect, @@ -232,13 +373,13 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { accumulatedWeight: 0, weightThresholdMet: false }); - } - if (_bitmapGet(voteProgress.voterBitmap, blesserRecord.index)) { + } else if (_bitmapGet(voteProgress.voterBitmap, blesserRecord.index)) { // We don't revert here because there might be other tagged roots for // which votes might count, and we want to allow that to happen. emit AlreadyVotedToBless(configVersion, msg.sender, taggedRoot); continue; } + noop = false; voteProgress.voterBitmap = _bitmapSet(voteProgress.voterBitmap, blesserRecord.index); voteProgress.accumulatedWeight += blesserRecord.weight; emit VotedToBless(configVersion, msg.sender, taggedRoot, blesserRecord.weight); @@ -248,6 +389,10 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { } s_blessVoteProgressByTaggedRootHash[taggedRootHash] = voteProgress; } + + if (noop) { + revert VoteToBlessNoop(); + } } /// @notice Can be called by the owner to remove unintentionally voted or even blessed tagged roots in a recovery @@ -268,145 +413,312 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { } } + struct UnvoteToCurseRequest { + bytes16 subject; + bytes28 cursesHash; + } + + // For use in internal calls. + enum Privilege { + Owner, + Voter + } + + function _authorizedUnvoteToCurse( + Privilege priv, // Privilege.Owner during an ownerUnvoteToCurse call, Privilege.Voter during a unvoteToCurse call + uint32 configVersion, + address curseVoteAddr, + UnvoteToCurseRequest memory req, + bool forceUnvote, // true only during an ownerUnvoteToCurse call, when OwnerUnvoteToCurseRequest.forceUnvote is true + CurserRecord storage sptr_curserRecord, + CurseVoteProgress storage sptr_curseVoteProgress + ) internal returns (bool unvoted, bool curseLifted) { + { + assert(priv == Privilege.Voter || priv == Privilege.Owner); // sanity check + // Check that the supplied arguments are feasible for our privilege. + if (forceUnvote || curseVoteAddr == OWNER_CURSE_VOTE_ADDR || curseVoteAddr == LIFT_CURSE_VOTE_ADDR) { + assert(priv == Privilege.Owner); + } + } + + ConfigVersionAndCursesHash memory cvch = sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr]; + + // First, try to unvote. + if ( + sptr_curserRecord.active && (curseVoteAddr == OWNER_CURSE_VOTE_ADDR || cvch.configVersion == configVersion) + && cvch.cursesHash != NO_VOTES_CURSES_HASH && (cvch.cursesHash == req.cursesHash || forceUnvote) + ) { + unvoted = true; + delete sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr]; + // Assumes: s_curserRecords[OWNER_CURSE_VOTE_ADDR].weight == 0, enforced by _setConfig + sptr_curseVoteProgress.accumulatedWeight -= sptr_curserRecord.weight; + + emit UnvotedToCurse( + configVersion, + curseVoteAddr, + req.subject, + sptr_curserRecord.weight, + req.cursesHash, + sptr_curseVoteProgress.accumulatedWeight + ); + } + + // If we have owner privilege, and the conditions for the curse to be active no longer hold, we are able to lift the + // curse. + bool shouldTryToLiftCurse = priv == Privilege.Owner && (unvoted || curseVoteAddr == LIFT_CURSE_VOTE_ADDR); + + if (shouldTryToLiftCurse && sptr_curseVoteProgress.curseActive && !_shouldCurseBeActive(sptr_curseVoteProgress)) { + curseLifted = true; + sptr_curseVoteProgress.curseActive = false; + --s_curseHotVars.numSubjectsCursed; + emit CurseLifted(req.subject); + } + + if (unvoted || curseLifted) { + RecordedCurseRelatedOpTag tag; + if (priv == Privilege.Owner) { + if (forceUnvote) { + tag = RecordedCurseRelatedOpTag.OwnerUnvoteToCurseForced; + } else { + tag = RecordedCurseRelatedOpTag.OwnerUnvoteToCurseUnforced; + } + } else if (priv == Privilege.Voter) { + tag = RecordedCurseRelatedOpTag.UnvoteToCurse; + } else { + // solhint-disable-next-line gas-custom-errors, reason-string + revert(); // assumption violation + } + s_recordedCurseRelatedOps.push( + RecordedCurseRelatedOp({ + tag: tag, + cursed: sptr_curseVoteProgress.curseActive, + curseVoteAddr: curseVoteAddr, + curseId: bytes16(0), + subject: req.subject, + blockTimestamp: _blockTimestamp() + }) + ); + } else { + emit SkippedUnvoteToCurse(curseVoteAddr, req.subject, cvch.cursesHash, req.cursesHash); + } + } + /// @notice Can be called by a curser to remove unintentional votes to curse. /// We expect this to be called very rarely, e.g. in case of a bug in the /// offchain code causing false voteToCurse calls. - /// @notice Should be called from curser's corresponding curseUnvoteAddr. - function unvoteToCurse(address curseVoteAddr, bytes32 cursesHash) external { - CurserRecord memory curserRecord = s_curserRecords[curseVoteAddr]; - - // If a curse is active, only the owner is allowed to lift it. - if (isCursed()) revert MustRecoverFromCurse(); + /// @notice Should be called from curser's corresponding curseVoteAddr. + function unvoteToCurse(UnvoteToCurseRequest[] memory unvoteToCurseRequests) external { + address curseVoteAddr = msg.sender; + CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr]; - if (msg.sender != curserRecord.curseUnvoteAddr) revert InvalidVoter(msg.sender); + if (!sptr_curserRecord.active) revert UnauthorizedVoter(curseVoteAddr); - if (!curserRecord.active || curserRecord.voteCount == 0) revert InvalidCurseState(); - if (curserRecord.cursesHash != cursesHash) revert InvalidCursesHash(curserRecord.cursesHash, cursesHash); + uint32 configVersion = s_versionedConfig.configVersion; + bool anyVoteWasUnvoted = false; + for (uint256 i = 0; i < unvoteToCurseRequests.length; ++i) { + UnvoteToCurseRequest memory req = unvoteToCurseRequests[i]; + CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, req.subject); + (bool unvoted, bool curseLifted) = _authorizedUnvoteToCurse( + Privilege.Voter, configVersion, curseVoteAddr, req, false, sptr_curserRecord, sptr_curseVoteProgress + ); + assert(!curseLifted); // assumption violation: voters can't lift curses + anyVoteWasUnvoted = anyVoteWasUnvoted || unvoted; + } - emit UnvotedToCurse( - s_versionedConfig.configVersion, curseVoteAddr, curserRecord.weight, curserRecord.voteCount, cursesHash - ); - curserRecord.voteCount = 0; - curserRecord.cursesHash = 0; - s_curserRecords[curseVoteAddr] = curserRecord; - s_curseVoteProgress.accumulatedWeight -= curserRecord.weight; + if (!anyVoteWasUnvoted) { + revert UnvoteToCurseNoop(); + } } /// @notice A vote to curse is appropriate during unhealthy blockchain conditions /// (eg. finality violations). - function voteToCurse(bytes32 curseId) external { - CurserRecord memory curserRecord = s_curserRecords[msg.sender]; - if (!curserRecord.active) revert InvalidVoter(msg.sender); - if (s_curseVotes[msg.sender][curseId]) revert AlreadyVotedToCurse(msg.sender, curseId); - s_curseVotes[msg.sender][curseId] = true; - ++curserRecord.voteCount; - curserRecord.cursesHash = keccak256(abi.encode(curserRecord.cursesHash, curseId)); - s_curserRecords[msg.sender] = curserRecord; - - CurseVoteProgress memory curseVoteProgress = s_curseVoteProgress; - - if (curserRecord.voteCount == 1) { - curseVoteProgress.accumulatedWeight += curserRecord.weight; - } + function voteToCurse(bytes16 curseId, bytes16[] memory subjects) external { + address curseVoteAddr = msg.sender; + assert(curseVoteAddr != OWNER_CURSE_VOTE_ADDR); + CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr]; + if (!sptr_curserRecord.active) revert UnauthorizedVoter(curseVoteAddr); + _authorizedVoteToCurse(curseVoteAddr, curseId, subjects, sptr_curserRecord); + } + + function _authorizedVoteToCurse( + address curseVoteAddr, + bytes16 curseId, + bytes16[] memory subjects, + CurserRecord storage sptr_curserRecord + ) internal { + if (subjects.length == 0) revert VoteToCurseNoop(); + + if (sptr_curserRecord.usedCurseIds[curseId]) revert ReusedCurseId(curseVoteAddr, curseId); + sptr_curserRecord.usedCurseIds[curseId] = true; // NOTE: We could pack configVersion into CurserRecord that we already load in the beginning of this function to // avoid the following extra storage read for it, but since voteToCurse is not on the hot path we'd rather keep // things simple. uint32 configVersion = s_versionedConfig.configVersion; - emit VotedToCurse( - configVersion, - msg.sender, - curserRecord.weight, - curserRecord.voteCount, - curseId, - curserRecord.cursesHash, - curseVoteProgress.accumulatedWeight - ); - if (!curseVoteProgress.curseActive && curseVoteProgress.accumulatedWeight >= curseVoteProgress.curseWeightThreshold) - { - curseVoteProgress.curseActive = true; - emit Cursed(configVersion, block.timestamp); + for (uint256 i = 0; i < subjects.length; ++i) { + if (i >= 1 && !(subjects[i - 1] < subjects[i])) { + // Prevents a subject from receiving multiple votes to curse with the same curse id. + revert SubjectsMustBeStrictlyIncreasing(); + } + + bytes16 subject = subjects[i]; + CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, subject); + ConfigVersionAndCursesHash memory cvch = sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr]; + bytes28 prevCursesHash; + if ( + (curseVoteAddr != OWNER_CURSE_VOTE_ADDR && cvch.configVersion < configVersion) + || cvch.cursesHash == NO_VOTES_CURSES_HASH + ) { + // if owner's first vote, or if voter's first vote in this config version + prevCursesHash = NO_VOTES_CURSES_HASH; // start hashchain from scratch, explicit + sptr_curseVoteProgress.accumulatedWeight += sptr_curserRecord.weight; + } else { + // we've already accounted for the weight + prevCursesHash = cvch.cursesHash; + } + sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr] = cvch = + ConfigVersionAndCursesHash({configVersion: configVersion, cursesHash: _cursesHash(prevCursesHash, curseId)}); + emit VotedToCurse( + configVersion, + curseVoteAddr, + subject, + curseId, + sptr_curserRecord.weight, + _blockTimestamp(), + cvch.cursesHash, + sptr_curseVoteProgress.accumulatedWeight + ); + + if ( + prevCursesHash == NO_VOTES_CURSES_HASH && !sptr_curseVoteProgress.curseActive + && _shouldCurseBeActive(sptr_curseVoteProgress) + ) { + sptr_curseVoteProgress.curseActive = true; + ++s_curseHotVars.numSubjectsCursed; + emit Cursed(configVersion, subject, _blockTimestamp()); + } + + s_recordedCurseRelatedOps.push( + RecordedCurseRelatedOp({ + tag: RecordedCurseRelatedOpTag.VoteToCurse, + cursed: sptr_curseVoteProgress.curseActive, + curseVoteAddr: curseVoteAddr, + curseId: curseId, + subject: subject, + blockTimestamp: _blockTimestamp() + }) + ); } - s_curseVoteProgress = curseVoteProgress; } /// @notice Enables the owner to immediately have the system enter the cursed state. - function ownerCurse() external onlyOwner { - emit OwnerCursed(block.timestamp); - if (!s_curseVoteProgress.curseActive) { - s_curseVoteProgress.curseActive = true; - emit Cursed(s_versionedConfig.configVersion, block.timestamp); - } + function ownerCurse(bytes16 curseId, bytes16[] memory subjects) external onlyOwner { + address curseVoteAddr = OWNER_CURSE_VOTE_ADDR; + CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr]; + // no need to check if sptr_curserRecord.active, we must have the onlyOwner modifier + _authorizedVoteToCurse(curseVoteAddr, curseId, subjects, sptr_curserRecord); + } + + // Set curseVoteAddr=LIFT_CURSE_VOTE_ADDR, cursesHash=bytes28(0), to reset curseActive if it can be reset. Useful if + // all voters have unvoted to curse on their own and the curse can now be lifted without any individual votes that can + // be unvoted. + // solhint-disable-next-line gas-struct-packing + struct OwnerUnvoteToCurseRequest { + address curseVoteAddr; + UnvoteToCurseRequest unit; + bool forceUnvote; } /// @notice Enables the owner to remove curse votes. After the curse votes are removed, /// this function will check whether the curse is still valid and restore the uncursed state if possible. /// This function also enables the owner to lift a curse created through ownerCurse. - function ownerUnvoteToCurse(UnvoteToCurseRecord[] calldata unvoteRecords) external onlyOwner { - for (uint256 i = 0; i < unvoteRecords.length; ++i) { - UnvoteToCurseRecord memory unvoteRecord = unvoteRecords[i]; - CurserRecord memory curserRecord = s_curserRecords[unvoteRecord.curseVoteAddr]; - // Owner can avoid the curses hash check by setting forceUnvote to true, in case - // a malicious curser is flooding the system with votes to curse with the - // intention to disallow the owner to clear their curse. - if (!unvoteRecord.forceUnvote && curserRecord.cursesHash != unvoteRecord.cursesHash) { - emit SkippedUnvoteToCurse(unvoteRecord.curseVoteAddr, curserRecord.cursesHash, unvoteRecord.cursesHash); - continue; - } - - if (!curserRecord.active || curserRecord.voteCount == 0) continue; - - emit UnvotedToCurse( - s_versionedConfig.configVersion, - unvoteRecord.curseVoteAddr, - curserRecord.weight, - curserRecord.voteCount, - curserRecord.cursesHash + function ownerUnvoteToCurse(OwnerUnvoteToCurseRequest[] memory ownerUnvoteToCurseRequests) external onlyOwner { + bool anyCurseWasLifted = false; + bool anyVoteWasUnvoted = false; + uint32 configVersion = s_versionedConfig.configVersion; + for (uint256 i = 0; i < ownerUnvoteToCurseRequests.length; ++i) { + OwnerUnvoteToCurseRequest memory req = ownerUnvoteToCurseRequests[i]; + CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, req.unit.subject); + (bool unvoted, bool curseLifted) = _authorizedUnvoteToCurse( + Privilege.Owner, + configVersion, + req.curseVoteAddr, + req.unit, + req.forceUnvote, + s_curserRecords[req.curseVoteAddr], + sptr_curseVoteProgress ); - curserRecord.voteCount = 0; - curserRecord.cursesHash = 0; - s_curserRecords[unvoteRecord.curseVoteAddr] = curserRecord; - s_curseVoteProgress.accumulatedWeight -= curserRecord.weight; + anyVoteWasUnvoted = anyVoteWasUnvoted || unvoted; + anyCurseWasLifted = anyCurseWasLifted || curseLifted; } - if ( - s_curseVoteProgress.curseActive - && s_curseVoteProgress.accumulatedWeight < s_curseVoteProgress.curseWeightThreshold - ) { - s_curseVoteProgress.curseActive = false; - emit RecoveredFromCurse(); - // Invalidate all in-progress votes to bless by bumping the config version. + if (anyCurseWasLifted) { + // Invalidate all in-progress votes to bless or curse by bumping the config version. // They might have been based on false information about the source chain // (e.g. in case of a finality violation). _setConfig(s_versionedConfig.config); } + + if (!(anyVoteWasUnvoted || anyCurseWasLifted)) { + revert UnvoteToCurseNoop(); + } } - /// @notice Will revert in case a curse is active. To avoid accidentally invalidating an in-progress curse vote, it - /// may be advisable to remove voters one-by-one over time, rather than many at once. - /// @dev The gas use of this function varies depending on the number of curse votes that are active. When calling this - /// function, be sure to include a gas cushion to account for curse votes that may occur between your transaction - /// being sent and mined. function setConfig(Config memory config) external onlyOwner { _setConfig(config); } + /// @notice Any tagged root with a commit store included in this array will be considered automatically blessed. + function getPermaBlessedCommitStores() external view returns (address[] memory) { + return s_permaBlessedCommitStores.values(); + } + + /// @notice The ordering of parameters is important. First come the commit stores to remove, then the commit stores to + /// add. + function ownerRemoveThenAddPermaBlessedCommitStores( + address[] memory removes, + address[] memory adds + ) external onlyOwner { + for (uint256 i = 0; i < removes.length; ++i) { + if (s_permaBlessedCommitStores.remove(removes[i])) { + emit PermaBlessedCommitStoreRemoved(removes[i]); + } + } + for (uint256 i = 0; i < adds.length; ++i) { + if (s_permaBlessedCommitStores.add(adds[i])) { + emit PermaBlessedCommitStoreAdded(adds[i]); + } + } + } + /// @inheritdoc IRMN - function isBlessed(IRMN.TaggedRoot calldata taggedRoot) external view override returns (bool) { - return s_blessVoteProgressByTaggedRootHash[_taggedRootHash(taggedRoot)].weightThresholdMet; + function isBlessed(IRMN.TaggedRoot calldata taggedRoot) external view returns (bool) { + return s_blessVoteProgressByTaggedRootHash[_taggedRootHash(taggedRoot)].weightThresholdMet + || s_permaBlessedCommitStores.contains(taggedRoot.commitStore); } /// @inheritdoc IRMN - function isCursed() public view override returns (bool) { - return s_curseVoteProgress.curseActive; + function isCursed() external view returns (bool) { + if (s_curseHotVars.numSubjectsCursed == 0) { + return false; // happy path costs a single SLOAD + } else { + return s_potentiallyOutdatedCurseVoteProgressBySubject[GLOBAL_CURSE_SUBJECT].curseActive + || s_potentiallyOutdatedCurseVoteProgressBySubject[LEGACY_CURSE_SUBJECT].curseActive; + } } - function isCursed(bytes16) external view override returns (bool) { - return s_curseVoteProgress.curseActive; + /// @inheritdoc IRMN + function isCursed(bytes16 subject) public view returns (bool) { + if (s_curseHotVars.numSubjectsCursed == 0) { + return false; // happy path costs a single SLOAD + } else { + return s_potentiallyOutdatedCurseVoteProgressBySubject[GLOBAL_CURSE_SUBJECT].curseActive + || s_potentiallyOutdatedCurseVoteProgressBySubject[subject].curseActive; + } } /// @notice Config version might be incremented for many reasons, including - /// recovery from a curse and a regular config change. + /// the lifting of a curse, or a regular config change. function getConfigDetails() external view returns (uint32 version, uint32 blockNumber, Config memory config) { version = s_versionedConfig.configVersion; blockNumber = s_versionedConfig.blockNumber; @@ -427,12 +739,12 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { blessed = progress.weightThresholdMet; if (progress.configVersion == s_versionedConfig.configVersion) { accumulatedWeight = progress.accumulatedWeight; - uint128 bitmap = progress.voterBitmap; + uint200 bitmap = progress.voterBitmap; blessVoteAddrs = new address[](_bitmapCount(bitmap)); Voter[] memory voters = s_versionedConfig.config.voters; uint256 j = 0; - for (uint256 i = 0; i < voters.length; ++i) { - if (_bitmapGet(bitmap, s_blesserRecords[voters[i].blessVoteAddr].index)) { + for (uint8 i = 0; i < voters.length; ++i) { + if (_bitmapGet(bitmap, i)) { blessVoteAddrs[j] = voters[i].blessVoteAddr; ++j; } @@ -441,43 +753,108 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { } /// @dev This is a helper method for offchain code so efficiency is not really a concern. - function getCurseProgress() + function getCurseProgress(bytes16 subject) external view - returns ( - address[] memory curseVoteAddrs, - uint32[] memory voteCounts, - bytes32[] memory cursesHashes, - uint16 accumulatedWeight, - bool cursed - ) + returns (address[] memory curseVoteAddrs, bytes28[] memory cursesHashes, uint16 accumulatedWeight, bool cursed) { - accumulatedWeight = s_curseVoteProgress.accumulatedWeight; - cursed = s_curseVoteProgress.curseActive; - uint256 numCursers; - Voter[] memory voters = s_versionedConfig.config.voters; - for (uint256 i = 0; i < voters.length; ++i) { - CurserRecord memory curserRecord = s_curserRecords[voters[i].curseVoteAddr]; - if (curserRecord.voteCount > 0) { - ++numCursers; + uint32 configVersion = s_versionedConfig.configVersion; + Config memory config = s_versionedConfig.config; + // Can't use _getUpToDateCurseVoteProgress here because we can't call a non-view function from within a view. + // So we get to repeat some accounting. + CurseVoteProgress storage outdatedCurseVoteProgress = s_potentiallyOutdatedCurseVoteProgressBySubject[subject]; + + cursed = outdatedCurseVoteProgress.curseActive; + + // See _getUpToDateCurseVoteProgress for more context. + bool shouldCountVotesFromOlderConfigs = outdatedCurseVoteProgress.configVersion < configVersion && cursed; + + // A play in two acts, because we can't push to arrays in memory, so we need to precompute the array's length. + // First act: we count the number of cursers, i.e., voters with active vote. + // Second act: push the cursers to the arrays, sum their weights. + + uint256 numCursers = 0; // we reuse this variable for writing to perserve stack space + accumulatedWeight = 0; + for (uint256 act = 1; act <= 2; ++act) { + uint256 i = config.voters.length; // not config.voters.length-1 to account for the owner + while (true) { + address curseVoteAddr; + uint8 weight; + if (i < config.voters.length) { + curseVoteAddr = config.voters[i].curseVoteAddr; + weight = config.voters[i].curseWeight; + } else { + // Allows us to include the owner's vote and curses hash in the result. + curseVoteAddr = OWNER_CURSE_VOTE_ADDR; + weight = 0; + } + + ConfigVersionAndCursesHash memory cvch = + outdatedCurseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr]; + bool hasActiveVote = ( + shouldCountVotesFromOlderConfigs || cvch.configVersion == configVersion + || curseVoteAddr == OWNER_CURSE_VOTE_ADDR + ) && cvch.cursesHash != NO_VOTES_CURSES_HASH; + if (hasActiveVote) { + if (act == 1) { + ++numCursers; + } else if (act == 2) { + accumulatedWeight += weight; + --numCursers; + curseVoteAddrs[numCursers] = curseVoteAddr; + cursesHashes[numCursers] = cvch.cursesHash; + } else { + // solhint-disable-next-line gas-custom-errors, reason-string + revert(); // assumption violation + } + } + + if (i > 0) { + --i; + } else { + break; + } } - } - curseVoteAddrs = new address[](numCursers); - voteCounts = new uint32[](numCursers); - cursesHashes = new bytes32[](numCursers); - uint256 j = 0; - for (uint256 i = 0; i < voters.length; ++i) { - address curseVoteAddr = voters[i].curseVoteAddr; - CurserRecord memory curserRecord = s_curserRecords[curseVoteAddr]; - if (curserRecord.voteCount > 0) { - curseVoteAddrs[j] = curseVoteAddr; - voteCounts[j] = curserRecord.voteCount; - cursesHashes[j] = curserRecord.cursesHash; - ++j; + + if (act == 1) { + // We are done counting at this point, initialize the arrays for the second act that follows immediately after. + curseVoteAddrs = new address[](numCursers); + cursesHashes = new bytes28[](numCursers); } } } + /// @notice Returns the number of subjects that are currently cursed. + function getCursedSubjectsCount() external view returns (uint256) { + return s_curseHotVars.numSubjectsCursed; + } + + /// @dev This is a helper method for offchain code to know what arguments to use for getRecordedCurseRelatedOps. + function getRecordedCurseRelatedOpsCount() external view returns (uint256) { + return s_recordedCurseRelatedOps.length; + } + + /// @dev This is a helper method for offchain code so efficiency is not really a concern. + /// @dev Returns s_recordedCurseRelatedOps[offset:offset+limit]. + function getRecordedCurseRelatedOps( + uint256 offset, + uint256 limit + ) external view returns (RecordedCurseRelatedOp[] memory) { + uint256 pageLen; + if (offset + limit <= s_recordedCurseRelatedOps.length) { + pageLen = limit; + } else if (offset < s_recordedCurseRelatedOps.length) { + pageLen = s_recordedCurseRelatedOps.length - offset; + } else { + pageLen = 0; + } + RecordedCurseRelatedOp[] memory page = new RecordedCurseRelatedOp[](pageLen); + for (uint256 i = 0; i < pageLen; ++i) { + page[i] = s_recordedCurseRelatedOps[offset + i]; + } + return page; + } + function _validateConfig(Config memory config) internal pure returns (bool) { if ( config.voters.length == 0 || config.voters.length > MAX_NUM_VOTERS || config.blessWeightThreshold == 0 @@ -488,18 +865,18 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { uint256 totalBlessWeight = 0; uint256 totalCurseWeight = 0; - address[] memory allAddrs = new address[](3 * config.voters.length); + address[] memory allAddrs = new address[](2 * config.voters.length); for (uint256 i = 0; i < config.voters.length; ++i) { Voter memory voter = config.voters[i]; if ( - voter.blessVoteAddr == address(0) || voter.curseVoteAddr == address(0) || voter.curseUnvoteAddr == address(0) + voter.blessVoteAddr == address(0) || voter.curseVoteAddr == address(0) + || voter.curseVoteAddr == LIFT_CURSE_VOTE_ADDR || voter.curseVoteAddr == OWNER_CURSE_VOTE_ADDR || (voter.blessWeight == 0 && voter.curseWeight == 0) ) { return false; } - allAddrs[3 * i + 0] = voter.blessVoteAddr; - allAddrs[3 * i + 1] = voter.curseVoteAddr; - allAddrs[3 * i + 2] = voter.curseUnvoteAddr; + allAddrs[2 * i + 0] = voter.blessVoteAddr; + allAddrs[2 * i + 1] = voter.curseVoteAddr; totalBlessWeight += voter.blessWeight; totalCurseWeight += voter.curseWeight; } @@ -516,11 +893,8 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { } function _setConfig(Config memory config) private { - if (isCursed()) revert MustRecoverFromCurse(); if (!_validateConfig(config)) revert InvalidConfig(); - Config memory oldConfig = s_versionedConfig.config; - // We can't directly assign s_versionedConfig.config to config // because copying a memory array into storage is not supported. { @@ -529,7 +903,7 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { while (s_versionedConfig.config.voters.length != 0) { Voter memory voter = s_versionedConfig.config.voters[s_versionedConfig.config.voters.length - 1]; delete s_blesserRecords[voter.blessVoteAddr]; - s_curserRecords[voter.curseVoteAddr].active = false; + delete s_curserRecords[voter.curseVoteAddr]; // usedCurseIds mapping is retained, as intended s_versionedConfig.config.voters.pop(); } for (uint256 i = 0; i < config.voters.length; ++i) { @@ -544,45 +918,30 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion { Voter memory voter = config.voters[i]; s_blesserRecords[voter.blessVoteAddr] = BlesserRecord({configVersion: configVersion, index: i, weight: voter.blessWeight}); - s_curserRecords[voter.curseVoteAddr] = CurserRecord({ - active: true, - weight: voter.curseWeight, - curseUnvoteAddr: voter.curseUnvoteAddr, - voteCount: s_curserRecords[voter.curseVoteAddr].voteCount, - cursesHash: s_curserRecords[voter.curseVoteAddr].cursesHash - }); + { + CurserRecord storage sptr_curserRecord = s_curserRecords[voter.curseVoteAddr]; + // Solidity will not let us initialize as CurserRecord({...}) due to the nested mapping + sptr_curserRecord.active = true; + sptr_curserRecord.weight = voter.curseWeight; + } + } + { + CurserRecord storage sptr_ownerCurserRecord = s_curserRecords[OWNER_CURSE_VOTE_ADDR]; + sptr_ownerCurserRecord.active = true; + sptr_ownerCurserRecord.weight = 0; // pseudo voter } s_versionedConfig.blockNumber = uint32(block.number); emit ConfigSet(configVersion, config); - CurseVoteProgress memory newCurseVoteProgress = - CurseVoteProgress({curseWeightThreshold: config.curseWeightThreshold, accumulatedWeight: 0, curseActive: false}); - - // Retain votes for the cursers who are still part of the new config and delete records for the cursers who are not. - for (uint8 i = 0; i < oldConfig.voters.length; ++i) { - // We could be more efficient with this but since this is only for - // setConfig it will do for now. - address curseVoteAddr = oldConfig.voters[i].curseVoteAddr; - CurserRecord memory curserRecord = s_curserRecords[curseVoteAddr]; - if (!curserRecord.active) { - delete s_curserRecords[curseVoteAddr]; - } else if (curserRecord.active && curserRecord.voteCount > 0) { - newCurseVoteProgress.accumulatedWeight += curserRecord.weight; - emit ReusedVotesToCurse( - configVersion, - curseVoteAddr, - curserRecord.weight, - curserRecord.voteCount, - curserRecord.cursesHash, - newCurseVoteProgress.accumulatedWeight - ); - } - } - newCurseVoteProgress.curseActive = - newCurseVoteProgress.accumulatedWeight >= newCurseVoteProgress.curseWeightThreshold; - if (newCurseVoteProgress.curseActive) { - emit Cursed(configVersion, block.timestamp); - } - s_curseVoteProgress = newCurseVoteProgress; + s_recordedCurseRelatedOps.push( + RecordedCurseRelatedOp({ + tag: RecordedCurseRelatedOpTag.SetConfig, + blockTimestamp: _blockTimestamp(), + cursed: false, + curseVoteAddr: address(0), + curseId: bytes16(0), + subject: bytes16(0) + }) + ); } } diff --git a/contracts/src/v0.8/ccip/interfaces/IRMN.sol b/contracts/src/v0.8/ccip/interfaces/IRMN.sol index 37b035320b..a409731549 100644 --- a/contracts/src/v0.8/ccip/interfaces/IRMN.sol +++ b/contracts/src/v0.8/ccip/interfaces/IRMN.sol @@ -12,10 +12,10 @@ interface IRMN { /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed. function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool); - /// @notice Iff there is an active global curse, or an active legacy curse (for backwards compatibility), this function returns true. + /// @notice Iff there is an active global or legacy curse, this function returns true. function isCursed() external view returns (bool); - /// @notice Iff there is an active global curse or an active subject curse, this function returns true. + /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true. /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)). function isCursed(bytes16 subject) external view returns (bool); } diff --git a/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol b/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol index 339855dedb..24b617c82a 100644 --- a/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol +++ b/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol @@ -6,35 +6,36 @@ import {IRMN} from "../../interfaces/IRMN.sol"; import {ARMProxy} from "../../ARMProxy.sol"; import {RMN} from "../../RMN.sol"; import {MockRMN} from "../mocks/MockRMN.sol"; -import {RMNSetup} from "./RMNSetup.t.sol"; +import {RMNSetup, makeSubjects} from "./RMNSetup.t.sol"; contract ARMProxyTest is RMNSetup { - event ARMSet(address arm); - + MockRMN internal s_mockRMN; ARMProxy internal s_armProxy; function setUp() public virtual override { RMNSetup.setUp(); + s_mockRMN = new MockRMN(); s_armProxy = new ARMProxy(address(s_rmn)); } function test_ARMIsCursed_Success() public { s_armProxy.setARM(address(s_mockRMN)); assertFalse(IRMN(address(s_armProxy)).isCursed()); - RMN(address(s_armProxy)).voteToCurse(bytes32(0)); + s_mockRMN.setGlobalCursed(true); assertTrue(IRMN(address(s_armProxy)).isCursed()); } function test_ARMIsBlessed_Success() public { s_armProxy.setARM(address(s_mockRMN)); + s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), true); assertTrue(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}))); - RMN(address(s_armProxy)).voteToCurse(bytes32(0)); + s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), false); assertFalse(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}))); } function test_ARMCallRevertReasonForwarded() public { bytes memory err = bytes("revert"); - s_mockRMN.setRevert(err); + s_mockRMN.setIsCursedRevert(err); s_armProxy.setARM(address(s_mockRMN)); vm.expectRevert(abi.encodeWithSelector(MockRMN.CustomError.selector, err)); IRMN(address(s_armProxy)).isCursed(); diff --git a/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol b/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol index 0ee2a508e1..4f3e96fafa 100644 --- a/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol +++ b/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol @@ -5,8 +5,6 @@ import {ARMProxy} from "../../ARMProxy.sol"; import {Test} from "forge-std/Test.sol"; contract ARMProxyStandaloneTest is Test { - event ARMSet(address arm); - address internal constant EMPTY_ADDRESS = address(0x1); address internal constant OWNER_ADDRESS = 0xC0ffeeEeC0fFeeeEc0ffeEeEc0ffEEEEC0FfEEee; address internal constant MOCK_RMN_ADDRESS = 0x1337133713371337133713371337133713371337; @@ -23,14 +21,14 @@ contract ARMProxyStandaloneTest is Test { function test_Constructor() public { vm.expectEmit(); - emit ARMSet(MOCK_RMN_ADDRESS); + emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS); ARMProxy proxy = new ARMProxy(MOCK_RMN_ADDRESS); assertEq(proxy.getARM(), MOCK_RMN_ADDRESS); } function test_SetARM() public { vm.expectEmit(); - emit ARMSet(MOCK_RMN_ADDRESS); + emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS); vm.prank(OWNER_ADDRESS); s_armProxy.setARM(MOCK_RMN_ADDRESS); assertEq(s_armProxy.getARM(), MOCK_RMN_ADDRESS); @@ -57,9 +55,9 @@ contract ARMProxyStandaloneTest is Test { ); if (expectedSuccess) { - vm.mockCall(MOCK_ARM_ADDRESS, 0, call, ret); + vm.mockCall(MOCK_RMN_ADDRESS, 0, call, ret); } else { - vm.mockCallRevert(MOCK_ARM_ADDRESS, 0, call, ret); + vm.mockCallRevert(MOCK_RMN_ADDRESS, 0, call, ret); } (bool actualSuccess, bytes memory result) = address(s_armProxy).call(call); vm.clearMockedCalls(); diff --git a/contracts/src/v0.8/ccip/test/arm/RMN.t.sol b/contracts/src/v0.8/ccip/test/arm/RMN.t.sol index 061f71afdd..d3237592f2 100644 --- a/contracts/src/v0.8/ccip/test/arm/RMN.t.sol +++ b/contracts/src/v0.8/ccip/test/arm/RMN.t.sol @@ -3,10 +3,13 @@ pragma solidity 0.8.24; import {IRMN} from "../../interfaces/IRMN.sol"; -import {RMN} from "../../RMN.sol"; -import {RMNSetup} from "./RMNSetup.t.sol"; +import {GLOBAL_CURSE_SUBJECT, LIFT_CURSE_VOTE_ADDR, OWNER_CURSE_VOTE_ADDR, RMN} from "../../RMN.sol"; +import {RMNSetup, makeCursesHash, makeSubjects} from "./RMNSetup.t.sol"; + import {Test} from "forge-std/Test.sol"; +bytes28 constant GARBAGE_CURSES_HASH = bytes28(keccak256("GARBAGE_CURSES_HASH")); + contract ConfigCompare is Test { function assertConfigEq(RMN.Config memory actualConfig, RMN.Config memory expectedConfig) public pure { assertEq(actualConfig.voters.length, expectedConfig.voters.length); @@ -32,79 +35,50 @@ contract RMN_constructor is ConfigCompare, RMNSetup { } } -contract RMN_voteToBlessRoots is RMNSetup { - event VotedToBless(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot, uint8 weight); - - // Success - +contract RMN_voteToBless is RMNSetup { function _getFirstBlessVoterAndWeight() internal pure returns (address, uint8) { RMN.Config memory cfg = rmnConstructorArgs(); return (cfg.voters[0].blessVoteAddr, cfg.voters[0].blessWeight); } - function test_1RootSuccess_gas() public { - vm.pauseGasMetering(); - (address voter, uint8 voterWeight) = _getFirstBlessVoterAndWeight(); - - vm.expectEmit(); - emit VotedToBless(1, voter, makeTaggedRoot(1), voterWeight); - - vm.startPrank(voter); - vm.resumeGasMetering(); - s_rmn.voteToBless(makeTaggedRootSingleton(1)); - vm.pauseGasMetering(); + // Success - assertFalse(s_rmn.isBlessed(makeTaggedRoot(1))); - assertEq(voterWeight, getWeightOfVotesToBlessRoot(makeTaggedRoot(1))); - assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1))); - vm.resumeGasMetering(); - } + function test_RootSuccess() public { + uint256 numRoots = 10; - function test_3RootSuccess_gas() public { - vm.pauseGasMetering(); (address voter, uint8 voterWeight) = _getFirstBlessVoterAndWeight(); - for (uint256 i = 1; i <= 3; ++i) { + for (uint256 i = 1; i <= numRoots; ++i) { vm.expectEmit(); - emit VotedToBless(1, voter, makeTaggedRoot(i), voterWeight); + emit RMN.VotedToBless(1, voter, makeTaggedRoot(i), voterWeight); } - vm.startPrank(voter); - vm.resumeGasMetering(); - s_rmn.voteToBless(makeTaggedRootsInclusive(1, 3)); - vm.pauseGasMetering(); + vm.prank(voter); + s_rmn.voteToBless(makeTaggedRootsInclusive(1, numRoots)); - for (uint256 i = 1; i <= 3; ++i) { + for (uint256 i = 1; i <= numRoots; ++i) { assertFalse(s_rmn.isBlessed(makeTaggedRoot(i))); assertEq(voterWeight, getWeightOfVotesToBlessRoot(makeTaggedRoot(i))); - assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(i))); + assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1))); } - vm.resumeGasMetering(); } - function test_5RootSuccess_gas() public { - vm.pauseGasMetering(); - (address voter, uint8 voterWeight) = _getFirstBlessVoterAndWeight(); + // Reverts - for (uint256 i = 1; i <= 5; ++i) { - vm.expectEmit(); - emit VotedToBless(1, voter, makeTaggedRoot(i), voterWeight); - } + function test_SenderAlreadyVoted_Revert() public { + (address voter,) = _getFirstBlessVoterAndWeight(); vm.startPrank(voter); - vm.resumeGasMetering(); - s_rmn.voteToBless(makeTaggedRootsInclusive(1, 5)); - vm.pauseGasMetering(); + s_rmn.voteToBless(makeTaggedRootSingleton(1)); + assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1))); - for (uint256 i = 1; i <= 5; ++i) { - assertFalse(s_rmn.isBlessed(makeTaggedRoot(i))); - assertEq(voterWeight, getWeightOfVotesToBlessRoot(makeTaggedRoot(i))); - assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1))); - } - vm.resumeGasMetering(); + uint256 votesToBlessBefore = getWeightOfVotesToBlessRoot(makeTaggedRoot(1)); + vm.expectRevert(RMN.VoteToBlessNoop.selector); + s_rmn.voteToBless(makeTaggedRootSingleton(1)); + assertEq(votesToBlessBefore, getWeightOfVotesToBlessRoot(makeTaggedRoot(1))); } - function test_IsAlreadyBlessedIgnored_Success() public { + function test_IsAlreadyBlessed_Revert() public { RMN.Config memory cfg = rmnConstructorArgs(); // Bless voters 2,3,4 vote to bless @@ -115,40 +89,27 @@ contract RMN_voteToBlessRoots is RMNSetup { uint256 votesToBlessBefore = getWeightOfVotesToBlessRoot(makeTaggedRoot(1)); vm.startPrank(cfg.voters[0].blessVoteAddr); + vm.expectRevert(RMN.VoteToBlessNoop.selector); s_rmn.voteToBless(makeTaggedRootSingleton(1)); assertEq(votesToBlessBefore, getWeightOfVotesToBlessRoot(makeTaggedRoot(1))); } - function test_SenderAlreadyVotedIgnored_Success() public { - (address voter,) = _getFirstBlessVoterAndWeight(); - - vm.startPrank(voter); - s_rmn.voteToBless(makeTaggedRootSingleton(1)); - assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1))); - - uint256 votesToBlessBefore = getWeightOfVotesToBlessRoot(makeTaggedRoot(1)); - s_rmn.voteToBless(makeTaggedRootSingleton(1)); - assertEq(votesToBlessBefore, getWeightOfVotesToBlessRoot(makeTaggedRoot(1))); - } - - // Reverts - function test_Curse_Revert() public { RMN.Config memory cfg = rmnConstructorArgs(); for (uint256 i = 0; i < cfg.voters.length; i++) { vm.startPrank(cfg.voters[i].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(i)); + s_rmn.voteToCurse(makeCurseId(i), makeSubjects(GLOBAL_CURSE_SUBJECT)); } vm.startPrank(cfg.voters[0].blessVoteAddr); - vm.expectRevert(RMN.MustRecoverFromCurse.selector); + vm.expectRevert(RMN.VoteToBlessForbiddenDuringActiveGlobalCurse.selector); s_rmn.voteToBless(makeTaggedRootSingleton(12903)); } - function test_InvalidVoter_Revert() public { + function test_UnauthorizedVoter_Revert() public { vm.startPrank(STRANGER); - vm.expectRevert(abi.encodeWithSelector(RMN.InvalidVoter.selector, STRANGER)); + vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, STRANGER)); s_rmn.voteToBless(makeTaggedRootSingleton(12321)); } } @@ -170,24 +131,20 @@ contract RMN_ownerUnbless is RMNSetup { contract RMN_unvoteToCurse is RMNSetup { uint256 internal s_curser; - bytes32 internal s_cursesHash; + bytes28 internal s_cursesHash; function setUp() public override { - RMN.Config memory cfg = rmnConstructorArgs(); RMNSetup.setUp(); - cfg = rmnConstructorArgs(); - s_curser = 0; + RMN.Config memory cfg = rmnConstructorArgs(); - vm.startPrank(cfg.voters[0].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(1)); - bytes32 expectedCursesHash = keccak256(abi.encode(bytes32(0), makeCurseId(1))); + s_curser = 0; + vm.startPrank(cfg.voters[s_curser].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + bytes28 expectedCursesHash = makeCursesHash(makeCurseId(1)); assertFalse(s_rmn.isCursed()); - (address[] memory cursers, uint32[] memory voteCounts, bytes32[] memory cursesHashes, uint16 weight, bool cursed) = - s_rmn.getCurseProgress(); + (address[] memory cursers, bytes28[] memory cursesHashes, uint16 weight, bool cursed) = s_rmn.getCurseProgress(0); assertEq(1, cursers.length); - assertEq(1, voteCounts.length); assertEq(cfg.voters[s_curser].curseVoteAddr, cursers[0]); - assertEq(1, voteCounts[0]); assertEq(cfg.voters[s_curser].curseWeight, weight); assertEq(1, cursesHashes.length); assertEq(expectedCursesHash, cursesHashes[0]); @@ -196,103 +153,322 @@ contract RMN_unvoteToCurse is RMNSetup { s_cursesHash = expectedCursesHash; } - function test_InvalidVoter() public { + function test_UnauthorizedVoter() public { RMN.Config memory cfg = rmnConstructorArgs(); // Someone else cannot unvote to curse on the curser's behalf. - address[] memory unauthorized = new address[](4); + address[] memory unauthorized = new address[](3); unauthorized[0] = cfg.voters[s_curser].blessVoteAddr; - unauthorized[1] = cfg.voters[s_curser].curseVoteAddr; + unauthorized[1] = cfg.voters[s_curser ^ 1].blessVoteAddr; unauthorized[2] = OWNER; - unauthorized[3] = cfg.voters[s_curser ^ 1].curseUnvoteAddr; for (uint256 i = 0; i < unauthorized.length; ++i) { - bytes memory expectedRevert = abi.encodeWithSelector(RMN.InvalidVoter.selector, unauthorized[i]); + bytes memory expectedRevert = abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, unauthorized[i]); vm.startPrank(unauthorized[i]); - // should fail when using the correct curses hash - vm.expectRevert(expectedRevert); - s_rmn.unvoteToCurse(cfg.voters[s_curser].curseVoteAddr, s_cursesHash); - // should fail when using garbage curses hash - vm.expectRevert(expectedRevert); - s_rmn.unvoteToCurse( - cfg.voters[s_curser].curseVoteAddr, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - ); + { + // should fail when using the correct curses hash + RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1); + reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash}); + vm.expectRevert(expectedRevert); + s_rmn.unvoteToCurse(reqs); + } + { + // should fail when using garbage curses hash + RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1); + reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH}); + vm.expectRevert(expectedRevert); + s_rmn.unvoteToCurse(reqs); + } } } function test_InvalidCursesHash() public { RMN.Config memory cfg = rmnConstructorArgs(); - vm.startPrank(cfg.voters[s_curser].curseUnvoteAddr); - vm.expectRevert( - abi.encodeWithSelector( - RMN.InvalidCursesHash.selector, s_cursesHash, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - ) - ); - s_rmn.unvoteToCurse( - cfg.voters[s_curser].curseVoteAddr, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - ); + vm.startPrank(cfg.voters[s_curser].curseVoteAddr); + RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1); + reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH}); + vm.expectRevert(RMN.UnvoteToCurseNoop.selector); + s_rmn.unvoteToCurse(reqs); } function test_ValidCursesHash() public { RMN.Config memory cfg = rmnConstructorArgs(); - vm.startPrank(cfg.voters[s_curser].curseUnvoteAddr); - s_rmn.unvoteToCurse(cfg.voters[s_curser].curseVoteAddr, s_cursesHash); + vm.startPrank(cfg.voters[s_curser].curseVoteAddr); + RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1); + reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash}); + s_rmn.unvoteToCurse(reqs); // succeeds } function test_OwnerSucceeds() public { RMN.Config memory cfg = rmnConstructorArgs(); vm.startPrank(OWNER); - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({ - curseVoteAddr: cfg.voters[s_curser].curseUnvoteAddr, - cursesHash: s_cursesHash, + RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1); + reqs[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: cfg.voters[s_curser].curseVoteAddr, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash}), forceUnvote: false }); - s_rmn.ownerUnvoteToCurse(records); + s_rmn.ownerUnvoteToCurse(reqs); } - event SkippedUnvoteToCurse(address indexed voter, bytes32 expectedCursesHash, bytes32 actualCursesHash); - function test_OwnerSkips() public { RMN.Config memory cfg = rmnConstructorArgs(); vm.startPrank(OWNER); - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({ + RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1); + reqs[0] = RMN.OwnerUnvoteToCurseRequest({ curseVoteAddr: cfg.voters[s_curser].curseVoteAddr, - cursesHash: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH}), forceUnvote: false }); + vm.expectEmit(); - emit SkippedUnvoteToCurse( - cfg.voters[s_curser].curseVoteAddr, - s_cursesHash, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - ); - s_rmn.ownerUnvoteToCurse(records); + emit RMN.SkippedUnvoteToCurse(cfg.voters[s_curser].curseVoteAddr, 0, s_cursesHash, GARBAGE_CURSES_HASH); + vm.expectRevert(RMN.UnvoteToCurseNoop.selector); + s_rmn.ownerUnvoteToCurse(reqs); } - function test_InvalidCurseState_Revert() public { + function test_VotersCantLiftCurseButOwnerCan() public { + vm.stopPrank(); RMN.Config memory cfg = rmnConstructorArgs(); - vm.startPrank(cfg.voters[1].curseUnvoteAddr); + // s_curser has voted to curse during setUp + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(accWeight, cfg.voters[s_curser].curseWeight); + assertFalse(cursed); + assertEq(voters.length, 1); + assertEq(cursesHashes.length, 1); + assertEq(voters[0], cfg.voters[s_curser].curseVoteAddr); + assertEq(cursesHashes[0], makeCursesHash(makeCurseId(1))); + } + // everyone else votes now, same curse id, same subject + { + for (uint256 i = 0; i < cfg.voters.length; ++i) { + if (i == s_curser) continue; // already voted to curse + vm.prank(cfg.voters[i].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + } + } + // subject must be cursed now + { + assertTrue(s_rmn.isCursed(0)); + } + // curse progress should be as full as it can get + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + uint256 allWeights; + for (uint256 i = 0; i < cfg.voters.length; i++) { + allWeights += cfg.voters[i].curseWeight; + } + assertEq(accWeight, allWeights); + assertTrue(cursed); + assertEq(voters.length, cfg.voters.length); + assertEq(cursesHashes.length, cfg.voters.length); + for (uint256 i = 0; i < cfg.voters.length; ++i) { + assertEq(voters[i], cfg.voters[i].curseVoteAddr); + assertEq(cursesHashes[i], makeCursesHash(makeCurseId(1))); + } + } + // everyone unvotes to curse, successfully + { + for (uint256 i = 0; i < cfg.voters.length; ++i) { + vm.prank(cfg.voters[i].curseVoteAddr); + RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1); + reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))}); + s_rmn.unvoteToCurse(reqs); + } + } + // curse should still be in place as only the owner can lift it + { + assertTrue(s_rmn.isCursed(0)); + } + // curse progress should be empty, expect for the cursed flag + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(accWeight, 0); + assertTrue(cursed); + assertEq(voters.length, 0); + assertEq(cursesHashes.length, 0); + } + // owner lifts curse + { + RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1); + ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: LIFT_CURSE_VOTE_ADDR, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: 0}), + forceUnvote: false + }); + vm.prank(OWNER); + s_rmn.ownerUnvoteToCurse(ownerReq); + } + // curse should now be lifted + { + assertFalse(s_rmn.isCursed(0)); + } + } +} + +contract RMN_voteToCurse_2 is RMNSetup { + function initialConfig() internal pure returns (RMN.Config memory) { + RMN.Config memory cfg = RMN.Config({voters: new RMN.Voter[](3), blessWeightThreshold: 1, curseWeightThreshold: 3}); + cfg.voters[0] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_1, curseVoteAddr: CURSE_VOTER_1, blessWeight: 1, curseWeight: 1}); + cfg.voters[1] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_2, curseVoteAddr: CURSE_VOTER_2, blessWeight: 1, curseWeight: 1}); + cfg.voters[2] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_3, curseVoteAddr: CURSE_VOTER_3, blessWeight: 1, curseWeight: 1}); + return cfg; + } + + function setUp() public override { + vm.prank(OWNER); + s_rmn = new RMN(initialConfig()); + } - vm.expectRevert(RMN.InvalidCurseState.selector); - s_rmn.unvoteToCurse(cfg.voters[1].curseVoteAddr, ""); + function test_VotesAreDroppedIfSubjectIsNotCursedDuringConfigChange() public { + // vote to curse the subject from an insufficient number of voters, one voter + { + RMN.Config memory cfg = initialConfig(); + vm.prank(cfg.voters[0].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + } + // vote must be in place + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, 1); + assertEq(cursesHashes.length, 1); + assertEq(accWeight, 1); + assertFalse(cursed); + } + // change config to include only the first voter, i.e., initialConfig().voters[0] + { + RMN.Config memory cfg = initialConfig(); + RMN.Voter[] memory voters = cfg.voters; + assembly { + mstore(voters, 1) + } + cfg.curseWeightThreshold = 1; + vm.prank(OWNER); + s_rmn.setConfig(cfg); + } + // vote must be dropped + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, 0); + assertEq(cursesHashes.length, 0); + assertEq(accWeight, 0); + assertFalse(cursed); + } + // cause an owner curse now + { + vm.prank(OWNER); + s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0)); + } + // only the owner curse must be visible + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, 1); + assertEq(voters[0], OWNER_CURSE_VOTE_ADDR); + assertEq(cursesHashes.length, 1); + assertEq(cursesHashes[0], makeCursesHash(makeCurseId(1))); + assertEq(accWeight, 0); + assertTrue(cursed); + } + } + + function test_VotesAreRetainedIfSubjectIsCursedDuringConfigChange() public { + uint256 numVotersInitially = initialConfig().voters.length; + // curse the subject with votes from all voters + { + RMN.Config memory cfg = initialConfig(); + for (uint256 i = 0; i < cfg.voters.length; ++i) { + vm.prank(cfg.voters[i].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + } + } + // subject is now cursed + { + assertTrue(s_rmn.isCursed(0)); + } + // throw in an owner curse + { + vm.prank(OWNER); + s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0)); + } + + uint256 snapshot = vm.snapshot(); + + for (uint256 keepVoters = 1; keepVoters <= numVotersInitially; ++keepVoters) { + vm.revertTo(snapshot); + + // change config to include only the first #keepVoters voters, i.e., initialConfig().voters[0..keepVoters] + { + RMN.Config memory cfg = initialConfig(); + RMN.Voter[] memory voters = cfg.voters; + assembly { + mstore(voters, keepVoters) + } + cfg.curseWeightThreshold = uint16(keepVoters); + vm.prank(OWNER); + s_rmn.setConfig(cfg); + } + // subject is still cursed + { + assertTrue(s_rmn.isCursed(0)); + } + // all votes from the first keepVoters & owner must be present + { + (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, keepVoters + 1 /* owner */ ); + assertEq(cursesHashes.length, keepVoters + 1 /* owner */ ); + assertEq(accWeight, keepVoters /* 1 per voter */ ); + assertTrue(cursed); + for (uint256 i = 0; i < keepVoters; ++i) { + assertEq(voters[i], initialConfig().voters[i].curseVoteAddr); + assertEq(cursesHashes[i], makeCursesHash(makeCurseId(1))); + } + assertEq(voters[voters.length - 1], OWNER_CURSE_VOTE_ADDR); + assertEq(cursesHashes[cursesHashes.length - 1], makeCursesHash(makeCurseId(1))); + } + // the owner unvoting for all is not enough to lift the curse, because remember that the owner has an active vote + // also + { + for (uint256 i = 0; i < keepVoters; ++i) { + RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1); + ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: initialConfig().voters[i].curseVoteAddr, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))}), + forceUnvote: false + }); + vm.prank(OWNER); + s_rmn.ownerUnvoteToCurse(ownerReq); + + assertTrue(s_rmn.isCursed(0)); + } + } + // after owner unvotes for themselves, finally, the curse will be lifted + { + RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1); + ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: OWNER_CURSE_VOTE_ADDR, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))}), + forceUnvote: false + }); + vm.prank(OWNER); + s_rmn.ownerUnvoteToCurse(ownerReq); + + assertFalse(s_rmn.isCursed(0)); + } + } } } contract RMN_voteToCurse is RMNSetup { - event VotedToCurse( - uint32 indexed configVersion, - address indexed voter, - uint8 weight, - uint32 voteCount, - bytes32 curseId, - bytes32 cursesHash, - uint16 accumulatedWeight - ); - event Cursed(uint32 indexed configVersion, uint256 timestamp); - event OwnerCursed(uint256 timestamp); - event RecoveredFromCurse(); - function _getFirstCurseVoterAndWeight() internal pure returns (address, uint8) { RMN.Config memory cfg = rmnConstructorArgs(); return (cfg.voters[0].curseVoteAddr, cfg.voters[0].curseWeight); @@ -300,41 +476,89 @@ contract RMN_voteToCurse is RMNSetup { // Success - function test_VoteToCurseSuccess_gas() public { - vm.pauseGasMetering(); + function test_CurseOnlyWhenThresholdReached_Success() public { + uint256 numSubjects = 3; + uint256 maxNumRevotes = 2; + + RMN.Config memory cfg = rmnConstructorArgs(); + bytes16[] memory subjects = new bytes16[](numSubjects); + for (uint256 i = 0; i < numSubjects; ++i) { + subjects[i] = bytes16(uint128(i)); + } + for (uint256 numRevotes = 1; numRevotes <= maxNumRevotes; ++numRevotes) { + // all voters but the last vote, but can't surpass the curse weight threshold + for (uint256 i = 0; i < cfg.voters.length - 1; ++i) { + vm.prank(cfg.voters[i].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(numRevotes), subjects); + } + // no curse is yet active, last voter also needs to vote for any curse to be active + { + // ensure every subject is not cursed + for (uint256 i = 0; i < numSubjects; ++i) { + assertFalse(s_rmn.isCursed(subjects[i])); + } + // ensure every vote has been recorded + assertEq( + s_rmn.getRecordedCurseRelatedOpsCount(), + 1 /* setConfig */ + (cfg.voters.length - 1) * numRevotes * numSubjects + ); + } + } + + // last voter now votes + vm.prank(cfg.voters[cfg.voters.length - 1].curseVoteAddr); + s_rmn.voteToCurse(makeCurseId(0), subjects); + // curses should be now active + { + // ensure every subject is now cursed + for (uint256 i = 0; i < numSubjects; ++i) { + assertTrue(s_rmn.isCursed(subjects[i])); + } + // ensure every vote has been recorded + assertEq( + s_rmn.getRecordedCurseRelatedOpsCount(), + 1 /* setConfig */ + ((cfg.voters.length - 1) * maxNumRevotes + 1) * numSubjects + ); + } + } + function test_VoteToCurse_NoCurse_Success() public { (address voter, uint8 weight) = _getFirstCurseVoterAndWeight(); vm.startPrank(voter); vm.expectEmit(); - emit VotedToCurse( - 1, voter, weight, 1, makeCurseId(123), keccak256(abi.encode(bytes32(0), makeCurseId(123))), weight + emit RMN.VotedToCurse( + 1, // configVersion + voter, + GLOBAL_CURSE_SUBJECT, + makeCurseId(123), + weight, + 1234567890, // blockTimestamp + makeCursesHash(makeCurseId(123)), // cursesHash + weight ); - vm.resumeGasMetering(); - s_rmn.voteToCurse(makeCurseId(123)); - vm.pauseGasMetering(); + s_rmn.voteToCurse(makeCurseId(123), makeSubjects(GLOBAL_CURSE_SUBJECT)); - (address[] memory voters,,, uint16 votes, bool cursed) = s_rmn.getCurseProgress(); + (address[] memory voters,, uint16 votes, bool cursed) = s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT); assertEq(1, voters.length); assertEq(voter, voters[0]); assertEq(weight, votes); assertFalse(cursed); - - vm.resumeGasMetering(); } - function test_EmitCurse_Success() public { + function test_VoteToCurse_YesCurse_Success() public { RMN.Config memory cfg = rmnConstructorArgs(); for (uint256 i = 0; i < cfg.voters.length - 1; ++i) { vm.startPrank(cfg.voters[i].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(1)); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); } vm.expectEmit(); - emit Cursed(1, block.timestamp); + emit RMN.Cursed(1, 0, uint64(block.timestamp)); vm.startPrank(cfg.voters[cfg.voters.length - 1].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(1)); + vm.resumeGasMetering(); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); } function test_EvenIfAlreadyCursed_Success() public { @@ -342,68 +566,104 @@ contract RMN_voteToCurse is RMNSetup { uint16 weightSum = 0; for (uint256 i = 0; i < cfg.voters.length; ++i) { vm.startPrank(cfg.voters[i].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(i)); + s_rmn.voteToCurse(makeCurseId(i), makeSubjects(0)); weightSum += cfg.voters[i].curseWeight; } // Not part of the assertion of this test but good to have as a sanity // check. We want a curse to be active in order for the ultimate assertion // to make sense. - assert(s_rmn.isCursed()); + assert(s_rmn.isCursed(0)); vm.expectEmit(); - emit VotedToCurse( + emit RMN.VotedToCurse( 1, // configVersion cfg.voters[cfg.voters.length - 1].curseVoteAddr, - cfg.voters[cfg.voters.length - 1].curseWeight, - 2, // voteCount + 0, // subject makeCurseId(cfg.voters.length + 1), // this curse id - keccak256( - abi.encode( - keccak256(abi.encode(bytes32(0), makeCurseId(cfg.voters.length - 1))), makeCurseId(cfg.voters.length + 1) - ) - ), // cursesHash + cfg.voters[cfg.voters.length - 1].curseWeight, + uint64(block.timestamp), // blockTimestamp + makeCursesHash(makeCurseId(cfg.voters.length - 1), makeCurseId(cfg.voters.length + 1)), // cursesHash weightSum // accumulatedWeight ); // Asserts that this call to vote with a new curse id goes through with no // reverts even when the RMN contract is cursed. - s_rmn.voteToCurse(makeCurseId(cfg.voters.length + 1)); + s_rmn.voteToCurse(makeCurseId(cfg.voters.length + 1), makeSubjects(0)); } function test_OwnerCanCurseAndUncurse() public { vm.startPrank(OWNER); + bytes28 expectedCursesHash = makeCursesHash(makeCurseId(0)); vm.expectEmit(); - emit OwnerCursed(block.timestamp); + emit RMN.VotedToCurse( + 1, // configVersion + OWNER_CURSE_VOTE_ADDR, // owner + 0, // subject + makeCurseId(0), // curse id + 0, // weight + uint64(block.timestamp), // blockTimestamp + expectedCursesHash, // cursesHash + 0 // accumulatedWeight + ); vm.expectEmit(); - emit Cursed(1, block.timestamp); - s_rmn.ownerCurse(); + emit RMN.Cursed( + 1, // configVersion + 0, // subject + uint64(block.timestamp) // blockTimestamp + ); + s_rmn.ownerCurse(makeCurseId(0), makeSubjects(0)); { - (address[] memory voters,,, uint24 accWeight, bool cursed) = s_rmn.getCurseProgress(); - assertEq(voters.length, 0); + (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, 1); + assertEq(voters[0], OWNER_CURSE_VOTE_ADDR /* owner */ ); + assertEq(cursesHashes.length, 1); + assertEq(cursesHashes[0], expectedCursesHash); assertEq(accWeight, 0); assertTrue(cursed); } - // ownerCurse again, this time we only get OwnerCursed, but not Cursed + // ownerCurse again, should cause a vote to appear and a change in curses hash + expectedCursesHash = makeCursesHash(makeCurseId(0), makeCurseId(1)); vm.expectEmit(); - emit OwnerCursed(block.timestamp); - s_rmn.ownerCurse(); + emit RMN.VotedToCurse( + 1, // configVersion + OWNER_CURSE_VOTE_ADDR, // owner + 0, // subject + makeCurseId(1), // curse id + 0, // weight + uint64(block.timestamp), // blockTimestamp + expectedCursesHash, // cursesHash + 0 // accumulatedWeight + ); + s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0)); { - (address[] memory voters,,, uint24 accWeight, bool cursed) = s_rmn.getCurseProgress(); - assertEq(voters.length, 0); + (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(voters.length, 1); + assertEq(voters[0], OWNER_CURSE_VOTE_ADDR /* owner */ ); + assertEq(cursesHashes.length, 1); + assertEq(cursesHashes[0], expectedCursesHash); assertEq(accWeight, 0); assertTrue(cursed); } - RMN.UnvoteToCurseRecord[] memory unvoteRecords = new RMN.UnvoteToCurseRecord[](0); + RMN.OwnerUnvoteToCurseRequest[] memory unvoteReqs = new RMN.OwnerUnvoteToCurseRequest[](1); + unvoteReqs[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: OWNER_CURSE_VOTE_ADDR, + unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: 0}), + forceUnvote: true // TODO: test with forceUnvote false also + }); vm.expectEmit(); - emit RecoveredFromCurse(); - s_rmn.ownerUnvoteToCurse(unvoteRecords); + emit RMN.CurseLifted(0); + s_rmn.ownerUnvoteToCurse(unvoteReqs); { - (address[] memory voters,,, uint24 accWeight, bool cursed) = s_rmn.getCurseProgress(); + (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) = + s_rmn.getCurseProgress(0); assertEq(voters.length, 0); + assertEq(cursesHashes.length, 0); assertEq(accWeight, 0); assertFalse(cursed); } @@ -411,26 +671,42 @@ contract RMN_voteToCurse is RMNSetup { // Reverts - function test_InvalidVoter_Revert() public { + function test_UnauthorizedVoter_Revert() public { vm.startPrank(STRANGER); - vm.expectRevert(abi.encodeWithSelector(RMN.InvalidVoter.selector, STRANGER)); - s_rmn.voteToCurse(makeCurseId(12312)); + vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, STRANGER)); + s_rmn.voteToCurse(makeCurseId(12312), makeSubjects(0)); } - function test_AlreadyVoted_Revert() public { + function test_ReusedCurseId_Revert() public { (address voter,) = _getFirstCurseVoterAndWeight(); vm.startPrank(voter); - s_rmn.voteToCurse(makeCurseId(1)); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + + vm.expectRevert(abi.encodeWithSelector(RMN.ReusedCurseId.selector, voter, makeCurseId(1))); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); + } + + function test_RepeatedSubject_Revert() public { + (address voter,) = _getFirstCurseVoterAndWeight(); + vm.prank(voter); + + bytes16 subject = bytes16(uint128(1)); + + vm.expectRevert(RMN.SubjectsMustBeStrictlyIncreasing.selector); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(subject, subject)); + } + + function test_EmptySubjects_Revert() public { + (address voter,) = _getFirstCurseVoterAndWeight(); + vm.prank(voter); - vm.expectRevert(abi.encodeWithSelector(RMN.AlreadyVotedToCurse.selector, voter, makeCurseId(1))); - s_rmn.voteToCurse(makeCurseId(1)); + vm.expectRevert(RMN.VoteToCurseNoop.selector); + s_rmn.voteToCurse(makeCurseId(1), new bytes16[](0)); } } contract RMN_ownerUnvoteToCurse is RMNSetup { - event RecoveredFromCurse(); - // These cursers are going to curse in setUp curseCount times. function getCursersAndCurseCounts() internal pure returns (address[] memory cursers, uint32[] memory curseCounts) { // NOTE: Change this when changing setUp or rmnConstructorArgs. @@ -453,23 +729,26 @@ contract RMN_ownerUnvoteToCurse is RMNSetup { for (uint256 i = 0; i < cursers.length; ++i) { vm.startPrank(cursers[i]); for (uint256 j = 0; j < curseCounts[i]; ++j) { - s_rmn.voteToCurse(makeCurseId(j)); + s_rmn.voteToCurse(makeCurseId(j), makeSubjects(GLOBAL_CURSE_SUBJECT)); } } } function ownerUnvoteToCurse() internal { - s_rmn.ownerUnvoteToCurse(makeUnvoteToCurseRecords()); + s_rmn.ownerUnvoteToCurse(makeOwnerUnvoteToCurseRequests()); } - function makeUnvoteToCurseRecords() internal pure returns (RMN.UnvoteToCurseRecord[] memory) { + function makeOwnerUnvoteToCurseRequests() internal pure returns (RMN.OwnerUnvoteToCurseRequest[] memory) { (address[] memory cursers,) = getCursersAndCurseCounts(); - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](cursers.length); + RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](cursers.length); for (uint256 i = 0; i < cursers.length; ++i) { - records[i] = - RMN.UnvoteToCurseRecord({curseVoteAddr: cursers[i], cursesHash: bytes32(uint256(0)), forceUnvote: true}); + reqs[i] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: cursers[i], + unit: RMN.UnvoteToCurseRequest({subject: GLOBAL_CURSE_SUBJECT, cursesHash: bytes28(0)}), + forceUnvote: true + }); } - return records; + return reqs; } // Success @@ -479,14 +758,15 @@ contract RMN_ownerUnvoteToCurse is RMNSetup { vm.startPrank(OWNER); vm.expectEmit(); - emit RecoveredFromCurse(); + emit RMN.CurseLifted(GLOBAL_CURSE_SUBJECT); vm.resumeGasMetering(); ownerUnvoteToCurse(); vm.pauseGasMetering(); assertFalse(s_rmn.isCursed()); - (address[] memory voters,, bytes32[] memory cursesHashes, uint256 weight, bool cursed) = s_rmn.getCurseProgress(); + (address[] memory voters, bytes28[] memory cursesHashes, uint256 weight, bool cursed) = + s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT); assertEq(voters.length, 0); assertEq(cursesHashes.length, 0); assertEq(weight, 0); @@ -497,25 +777,25 @@ contract RMN_ownerUnvoteToCurse is RMNSetup { function test_IsIdempotent() public { vm.startPrank(OWNER); ownerUnvoteToCurse(); + vm.expectRevert(RMN.UnvoteToCurseNoop.selector); ownerUnvoteToCurse(); assertFalse(s_rmn.isCursed()); - (address[] memory voters, uint32[] memory voteCounts, bytes32[] memory cursesHashes, uint256 weight, bool cursed) = - s_rmn.getCurseProgress(); + (address[] memory voters, bytes28[] memory cursesHashes, uint256 weight, bool cursed) = + s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT); assertEq(voters.length, 0); assertEq(cursesHashes.length, 0); - assertEq(voteCounts.length, 0); assertEq(weight, 0); assertFalse(cursed); } - function test_CanBlessAndCurseAfterRecovery() public { + function test_CanBlessAndCurseAfterGlobalCurseIsLifted() public { // Contract is already cursed due to setUp. // Owner unvotes to curse. vm.startPrank(OWNER); vm.expectEmit(); - emit RecoveredFromCurse(); + emit RMN.CurseLifted(GLOBAL_CURSE_SUBJECT); ownerUnvoteToCurse(); // Contract is now uncursed. @@ -527,7 +807,7 @@ contract RMN_ownerUnvoteToCurse is RMNSetup { // Vote to curse should go through. vm.startPrank(CURSE_VOTER_1); - s_rmn.voteToCurse(makeCurseId(73894728973)); + s_rmn.voteToCurse(makeCurseId(73894728973), makeSubjects(GLOBAL_CURSE_SUBJECT)); } // Reverts @@ -537,6 +817,25 @@ contract RMN_ownerUnvoteToCurse is RMNSetup { vm.expectRevert("Only callable by owner"); ownerUnvoteToCurse(); } + + function test_UnknownVoter_Revert() public { + vm.stopPrank(); + RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1); + reqs[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: STRANGER, + unit: RMN.UnvoteToCurseRequest({subject: GLOBAL_CURSE_SUBJECT, cursesHash: bytes28(0)}), + forceUnvote: true + }); + + vm.prank(OWNER); + vm.expectEmit(); + emit RMN.SkippedUnvoteToCurse(STRANGER, GLOBAL_CURSE_SUBJECT, bytes28(0), bytes28(0)); + vm.expectRevert(RMN.UnvoteToCurseNoop.selector); + s_rmn.ownerUnvoteToCurse(reqs); + + // no effect on cursedness + assertTrue(s_rmn.isCursed(GLOBAL_CURSE_SUBJECT)); + } } contract RMN_setConfig is ConfigCompare, RMNSetup { @@ -546,14 +845,12 @@ contract RMN_setConfig is ConfigCompare, RMNSetup { voters[0] = RMN.Voter({ blessVoteAddr: BLESS_VOTER_1, curseVoteAddr: CURSE_VOTER_1, - curseUnvoteAddr: CURSE_UNVOTER_1, blessWeight: WEIGHT_1, curseWeight: WEIGHT_1 }); voters[1] = RMN.Voter({ blessVoteAddr: BLESS_VOTER_2, curseVoteAddr: CURSE_VOTER_2, - curseUnvoteAddr: CURSE_UNVOTER_2, blessWeight: WEIGHT_10, curseWeight: WEIGHT_10 }); @@ -574,7 +871,7 @@ contract RMN_setConfig is ConfigCompare, RMNSetup { vm.startPrank(cfg.voters[1].blessVoteAddr); s_rmn.voteToBless(makeTaggedRootSingleton(1)); vm.startPrank(cfg.voters[1].curseVoteAddr); - s_rmn.voteToCurse(makeCurseId(1)); + s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0)); } // Success @@ -589,7 +886,7 @@ contract RMN_setConfig is ConfigCompare, RMNSetup { // BLESS_VOTER_4 is not part of cfg anymore, vote to bless should revert. vm.startPrank(BLESS_VOTER_4); - vm.expectRevert(abi.encodeWithSelector(RMN.InvalidVoter.selector, BLESS_VOTER_4)); + vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, BLESS_VOTER_4)); s_rmn.voteToBless(makeTaggedRootSingleton(2)); } @@ -610,14 +907,13 @@ contract RMN_setConfig is ConfigCompare, RMNSetup { assertEq(configVersionBefore + 1, configVersionAfter); assertConfigEq(configAfter, cfg); - // Assert that curse votes have been cleared, except for CURSE_VOTER_2 who - // has already voted and is also part of the new config - (address[] memory curseVoters,, bytes32[] memory cursesHashes, uint256 curseWeight, bool cursed) = - s_rmn.getCurseProgress(); - assertEq(1, curseVoters.length); - assertEq(WEIGHT_10, curseWeight); - assertEq(1, cursesHashes.length); - assertEq(keccak256(abi.encode(bytes32(0), makeCurseId(1))), cursesHashes[0]); + // Assert that curse votes have been cleared + + (address[] memory curseVoters, bytes28[] memory cursesHashes, uint256 curseWeight, bool cursed) = + s_rmn.getCurseProgress(0); + assertEq(0, curseVoters.length); + assertEq(0, cursesHashes.length); + assertEq(0, curseWeight); assertFalse(cursed); // Assert that good votes have been cleared @@ -700,3 +996,73 @@ contract RMN_setConfig is ConfigCompare, RMNSetup { s_rmn.setConfig(cfg); } } + +contract RMN_permaBlessing is RMNSetup { + function addresses() private pure returns (address[] memory) { + return new address[](0); + } + + function addresses(address a) private pure returns (address[] memory) { + address[] memory arr = new address[](1); + arr[0] = a; + return arr; + } + + function addresses(address a, address b) private pure returns (address[] memory) { + address[] memory arr = new address[](2); + arr[0] = a; + arr[1] = b; + return arr; + } + + function test_PermaBlessing() public { + bytes32 SOME_ROOT = bytes32(~uint256(0)); + address COMMIT_STORE_1 = makeAddr("COMMIT_STORE_1"); + address COMMIT_STORE_2 = makeAddr("COMMIT_STORE_2"); + IRMN.TaggedRoot memory taggedRootCommitStore1 = IRMN.TaggedRoot({root: SOME_ROOT, commitStore: COMMIT_STORE_1}); + IRMN.TaggedRoot memory taggedRootCommitStore2 = IRMN.TaggedRoot({root: SOME_ROOT, commitStore: COMMIT_STORE_2}); + + assertFalse(s_rmn.isBlessed(taggedRootCommitStore1)); + assertFalse(s_rmn.isBlessed(taggedRootCommitStore2)); + assertEq(s_rmn.getPermaBlessedCommitStores(), addresses()); + + // only owner can mutate permaBlessedCommitStores + vm.prank(STRANGER); + vm.expectRevert("Only callable by owner"); + s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1)); + + vm.prank(OWNER); + s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1)); + assertTrue(s_rmn.isBlessed(taggedRootCommitStore1)); + assertFalse(s_rmn.isBlessed(taggedRootCommitStore2)); + assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_1)); + + vm.prank(OWNER); + s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(COMMIT_STORE_1), addresses(COMMIT_STORE_2)); + assertFalse(s_rmn.isBlessed(taggedRootCommitStore1)); + assertTrue(s_rmn.isBlessed(taggedRootCommitStore2)); + assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_2)); + + vm.prank(OWNER); + s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1)); + assertTrue(s_rmn.isBlessed(taggedRootCommitStore1)); + assertTrue(s_rmn.isBlessed(taggedRootCommitStore2)); + assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_2, COMMIT_STORE_1)); + + vm.prank(OWNER); + s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(COMMIT_STORE_1, COMMIT_STORE_2), addresses()); + assertFalse(s_rmn.isBlessed(taggedRootCommitStore1)); + assertFalse(s_rmn.isBlessed(taggedRootCommitStore2)); + assertEq(s_rmn.getPermaBlessedCommitStores(), addresses()); + } +} + +contract RMN_getRecordedCurseRelatedOps is RMNSetup { + function test_OpsPostDeployment() public { + // The constructor call includes a setConfig, so that's the only thing we should expect to find. + assertEq(s_rmn.getRecordedCurseRelatedOpsCount(), 1); + RMN.RecordedCurseRelatedOp[] memory recordedCurseRelatedOps = s_rmn.getRecordedCurseRelatedOps(0, type(uint256).max); + assertEq(recordedCurseRelatedOps.length, 1); + assertEq(uint8(recordedCurseRelatedOps[0].tag), uint8(RMN.RecordedCurseRelatedOpTag.SetConfig)); + } +} diff --git a/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol b/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol index 9b7789bb91..8feacb95f4 100644 --- a/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol @@ -1,29 +1,92 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; +import {RMN} from "../../RMN.sol"; import {IRMN} from "../../interfaces/IRMN.sol"; -import {RMN} from "../../RMN.sol"; -import {MockRMN} from "../mocks/MockRMN.sol"; import {Test} from "forge-std/Test.sol"; +function makeSubjects(bytes16 a) pure returns (bytes16[] memory) { + bytes16[] memory subjects = new bytes16[](1); + subjects[0] = a; + return subjects; +} + +function makeSubjects(bytes16 a, bytes16 b) pure returns (bytes16[] memory) { + bytes16[] memory subjects = new bytes16[](2); + subjects[0] = a; + subjects[1] = b; + return subjects; +} + +// in order from earliest to latest curse ids +function makeCursesHashFromList(bytes32[] memory curseIds) pure returns (bytes28 cursesHash) { + for (uint256 i = 0; i < curseIds.length; ++i) { + cursesHash = bytes28(keccak256(abi.encode(cursesHash, curseIds[i]))); + } +} + +// hides the ugliness from tests +function makeCursesHash(bytes32 a) pure returns (bytes28) { + bytes32[] memory curseIds = new bytes32[](1); + curseIds[0] = a; + return makeCursesHashFromList(curseIds); +} + +function makeCursesHash(bytes32 a, bytes32 b) pure returns (bytes28) { + bytes32[] memory curseIds = new bytes32[](2); + curseIds[0] = a; + curseIds[1] = b; + return makeCursesHashFromList(curseIds); +} + contract RMNSetup is Test { + // Addresses address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; address internal constant STRANGER = address(999999); address internal constant ZERO_ADDRESS = address(0); - address internal constant BLESS_VOTER_1 = address(1); address internal constant CURSE_VOTER_1 = address(10); - address internal constant CURSE_UNVOTER_1 = address(110); address internal constant BLESS_VOTER_2 = address(2); address internal constant CURSE_VOTER_2 = address(12); - address internal constant CURSE_UNVOTER_2 = address(112); address internal constant BLESS_VOTER_3 = address(3); address internal constant CURSE_VOTER_3 = address(13); - address internal constant CURSE_UNVOTER_3 = address(113); address internal constant BLESS_VOTER_4 = address(4); address internal constant CURSE_VOTER_4 = address(14); - address internal constant CURSE_UNVOTER_4 = address(114); + + // Arm + function rmnConstructorArgs() internal pure returns (RMN.Config memory) { + RMN.Voter[] memory voters = new RMN.Voter[](4); + voters[0] = RMN.Voter({ + blessVoteAddr: BLESS_VOTER_1, + curseVoteAddr: CURSE_VOTER_1, + blessWeight: WEIGHT_1, + curseWeight: WEIGHT_1 + }); + voters[1] = RMN.Voter({ + blessVoteAddr: BLESS_VOTER_2, + curseVoteAddr: CURSE_VOTER_2, + blessWeight: WEIGHT_10, + curseWeight: WEIGHT_10 + }); + voters[2] = RMN.Voter({ + blessVoteAddr: BLESS_VOTER_3, + curseVoteAddr: CURSE_VOTER_3, + blessWeight: WEIGHT_20, + curseWeight: WEIGHT_20 + }); + voters[3] = RMN.Voter({ + blessVoteAddr: BLESS_VOTER_4, + curseVoteAddr: CURSE_VOTER_4, + blessWeight: WEIGHT_40, + curseWeight: WEIGHT_40 + }); + return RMN.Config({ + voters: voters, + blessWeightThreshold: WEIGHT_10 + WEIGHT_20 + WEIGHT_40, + curseWeightThreshold: WEIGHT_1 + WEIGHT_10 + WEIGHT_20 + WEIGHT_40 + }); + } uint8 internal constant ZERO = 0; uint8 internal constant WEIGHT_1 = 1; @@ -52,57 +115,18 @@ contract RMNSetup is Test { return keccak256(abi.encode(taggedRoot.commitStore, taggedRoot.root)); } - function makeCurseId(uint256 index) internal pure returns (bytes32) { - return bytes32(index); + function makeCurseId(uint256 index) internal pure returns (bytes16) { + return bytes16(uint128(index)); } - MockRMN internal s_mockRMN; RMN internal s_rmn; function setUp() public virtual { vm.startPrank(OWNER); s_rmn = new RMN(rmnConstructorArgs()); - s_mockRMN = new MockRMN(); vm.stopPrank(); } - function rmnConstructorArgs() internal pure returns (RMN.Config memory) { - RMN.Voter[] memory voters = new RMN.Voter[](4); - voters[0] = RMN.Voter({ - blessVoteAddr: BLESS_VOTER_1, - curseVoteAddr: CURSE_VOTER_1, - curseUnvoteAddr: CURSE_UNVOTER_1, - blessWeight: WEIGHT_1, - curseWeight: WEIGHT_1 - }); - voters[1] = RMN.Voter({ - blessVoteAddr: BLESS_VOTER_2, - curseVoteAddr: CURSE_VOTER_2, - curseUnvoteAddr: CURSE_UNVOTER_2, - blessWeight: WEIGHT_10, - curseWeight: WEIGHT_10 - }); - voters[2] = RMN.Voter({ - blessVoteAddr: BLESS_VOTER_3, - curseVoteAddr: CURSE_VOTER_3, - curseUnvoteAddr: CURSE_UNVOTER_3, - blessWeight: WEIGHT_20, - curseWeight: WEIGHT_20 - }); - voters[3] = RMN.Voter({ - blessVoteAddr: BLESS_VOTER_4, - curseVoteAddr: CURSE_VOTER_4, - curseUnvoteAddr: CURSE_UNVOTER_4, - blessWeight: WEIGHT_40, - curseWeight: WEIGHT_40 - }); - return RMN.Config({ - voters: voters, - blessWeightThreshold: WEIGHT_10 + WEIGHT_20 + WEIGHT_40, - curseWeightThreshold: WEIGHT_1 + WEIGHT_10 + WEIGHT_20 + WEIGHT_40 - }); - } - function hasVotedToBlessRoot(address voter, IRMN.TaggedRoot memory taggedRoot_) internal view returns (bool) { (address[] memory voters,,) = s_rmn.getBlessProgress(taggedRoot_); for (uint256 i = 0; i < voters.length; ++i) { diff --git a/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol b/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol new file mode 100644 index 0000000000..8564614a74 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {GLOBAL_CURSE_SUBJECT, OWNER_CURSE_VOTE_ADDR, RMN} from "../../RMN.sol"; +import {RMNSetup, makeCursesHash, makeSubjects} from "./RMNSetup.t.sol"; + +contract RMN_voteToBless_Benchmark is RMNSetup { + function test_RootSuccess_gas(uint256 n) internal { + vm.prank(BLESS_VOTER_1); + s_rmn.voteToBless(makeTaggedRootsInclusive(1, n)); + } + + function test_1RootSuccess_gas() public { + test_RootSuccess_gas(1); + } + + function test_3RootSuccess_gas() public { + test_RootSuccess_gas(3); + } + + function test_5RootSuccess_gas() public { + test_RootSuccess_gas(5); + } +} + +contract RMN_voteToBless_Blessed_Benchmark is RMN_voteToBless_Benchmark { + function setUp() public virtual override { + RMNSetup.setUp(); + vm.prank(BLESS_VOTER_2); + s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1)); + vm.prank(BLESS_VOTER_3); + s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1)); + } + + function test_1RootSuccessBecameBlessed_gas() public { + vm.prank(BLESS_VOTER_4); + s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1)); + } +} + +abstract contract RMN_voteToCurse_Benchmark is RMNSetup { + struct PreVote { + address voter; + bytes16 subject; + } + + PreVote[] internal s_preVotes; + + function setUp() public virtual override { + // Intentionally does not inherit RMNSetup setUp(), because we set up a simpler config here. + // The only way to ensure that storage slots are cold for the actual functions to be benchmarked is to perform the + // setup in setUp(). + + RMN.Config memory cfg = RMN.Config({voters: new RMN.Voter[](3), blessWeightThreshold: 3, curseWeightThreshold: 3}); + cfg.voters[0] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_1, curseVoteAddr: CURSE_VOTER_1, blessWeight: 1, curseWeight: 1}); + cfg.voters[1] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_2, curseVoteAddr: CURSE_VOTER_2, blessWeight: 1, curseWeight: 1}); + cfg.voters[2] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_3, curseVoteAddr: CURSE_VOTER_3, blessWeight: 1, curseWeight: 1}); + vm.prank(OWNER); + s_rmn = new RMN(cfg); + + for (uint256 i = 0; i < s_preVotes.length; ++i) { + vm.prank(s_preVotes[i].voter); + s_rmn.voteToCurse(makeCurseId(i), makeSubjects(s_preVotes[i].subject)); + } + } +} + +contract RMN_voteToCurse_Benchmark_1 is RMN_voteToCurse_Benchmark { + constructor() { + // some irrelevant subject & voter so that we don't pay for the nonzero->zero SSTORE of + // s_recordedVotesToCurse.length in the benchmark below + s_preVotes.push(PreVote({voter: CURSE_VOTER_3, subject: bytes16(~uint128(0))})); + } + + function test_VoteToCurse_NewSubject_NewVoter_NoCurse_gas() public { + vm.prank(CURSE_VOTER_1); + s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } + + function test_VoteToCurse_NewSubject_NewVoter_YesCurse_gas() public { + vm.prank(OWNER); + s_rmn.ownerCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } +} + +contract RMN_voteToCurse_Benchmark_2 is RMN_voteToCurse_Benchmark { + constructor() { + s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT})); + } + + function test_VoteToCurse_OldSubject_OldVoter_NoCurse_gas() public { + vm.prank(CURSE_VOTER_1); + s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } + + function test_VoteToCurse_OldSubject_NewVoter_NoCurse_gas() public { + vm.prank(CURSE_VOTER_2); + s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } +} + +contract RMN_voteToCurse_Benchmark_3 is RMN_voteToCurse_Benchmark { + constructor() { + s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT})); + s_preVotes.push(PreVote({voter: CURSE_VOTER_2, subject: GLOBAL_CURSE_SUBJECT})); + } + + function test_VoteToCurse_OldSubject_NewVoter_YesCurse_gas() public { + vm.prank(CURSE_VOTER_3); + s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } +} + +contract RMN_lazyVoteToCurseUpdate_Benchmark is RMN_voteToCurse_Benchmark { + constructor() { + s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT})); + s_preVotes.push(PreVote({voter: CURSE_VOTER_2, subject: GLOBAL_CURSE_SUBJECT})); + s_preVotes.push(PreVote({voter: CURSE_VOTER_3, subject: GLOBAL_CURSE_SUBJECT})); + } + + function setUp() public override { + RMN_voteToCurse_Benchmark.setUp(); // sends the prevotes + // initial config includes voters CURSE_VOTER_1, CURSE_VOTER_2, CURSE_VOTER_3 + // include a new voter in the config + { + (,, RMN.Config memory cfg) = s_rmn.getConfigDetails(); + RMN.Voter[] memory newVoters = new RMN.Voter[](cfg.voters.length + 1); + for (uint256 i = 0; i < cfg.voters.length; ++i) { + newVoters[i] = cfg.voters[i]; + } + newVoters[newVoters.length - 1] = + RMN.Voter({blessVoteAddr: BLESS_VOTER_4, curseVoteAddr: CURSE_VOTER_4, blessWeight: 1, curseWeight: 1}); + cfg.voters = newVoters; + + vm.prank(OWNER); + s_rmn.setConfig(cfg); + } + } + + function test_VoteToCurseLazilyRetain3VotersUponConfigChange_gas() public { + // send a vote as the new voter, should cause a lazy update and votes from CURSE_VOTER_1, CURSE_VOTER_2, + // CURSE_VOTER_3 to be retained, which is the worst case for the prior config + vm.prank(CURSE_VOTER_4); + s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } +} + +contract RMN_setConfig_Benchmark is RMNSetup { + uint256 s_numVoters; + + function configWithVoters(uint256 numVoters) internal pure returns (RMN.Config memory) { + RMN.Config memory cfg = + RMN.Config({voters: new RMN.Voter[](numVoters), blessWeightThreshold: 1, curseWeightThreshold: 1}); + for (uint256 i = 1; i <= numVoters; ++i) { + cfg.voters[i - 1] = RMN.Voter({ + blessVoteAddr: address(uint160(2 * i)), + curseVoteAddr: address(uint160(2 * i + 1)), + blessWeight: 1, + curseWeight: 1 + }); + } + return cfg; + } + + function setUp() public virtual override { + vm.prank(OWNER); + s_rmn = new RMN(configWithVoters(s_numVoters)); + } +} + +contract RMN_setConfig_Benchmark_1 is RMN_setConfig_Benchmark { + constructor() { + s_numVoters = 1; + } + + function test_SetConfig_7Voters_gas() public { + vm.prank(OWNER); + s_rmn.setConfig(configWithVoters(7)); + } +} + +contract RMN_setConfig_Benchmark_2 is RMN_setConfig_Benchmark { + constructor() { + s_numVoters = 7; + } + + function test_ResetConfig_7Voters_gas() public { + vm.prank(OWNER); + s_rmn.setConfig(configWithVoters(7)); + } +} + +contract RMN_ownerUnvoteToCurse_Benchmark is RMN_setConfig_Benchmark { + constructor() { + s_numVoters = 7; + } + + function setUp() public override { + RMN_setConfig_Benchmark.setUp(); + vm.prank(OWNER); + s_rmn.ownerCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT)); + } + + function test_OwnerUnvoteToCurse_1Voter_LiftsCurse_gas() public { + RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1); + reqs[0] = RMN.OwnerUnvoteToCurseRequest({ + curseVoteAddr: OWNER_CURSE_VOTE_ADDR, + unit: RMN.UnvoteToCurseRequest({cursesHash: makeCursesHash(makeCurseId(0xffff)), subject: GLOBAL_CURSE_SUBJECT}), + forceUnvote: false + }); + vm.prank(OWNER); + s_rmn.ownerUnvoteToCurse(reqs); + } +} diff --git a/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol b/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol index f3e97c30f7..b23e0cae0d 100644 --- a/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol +++ b/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol @@ -606,8 +606,8 @@ contract CCIPConfig_ConfigStateMachine is CCIPConfigSetup { } function test_Fuzz__groupByPluginType_Success(uint256 numCommitCfgs, uint256 numExecCfgs) public { - vm.assume(numCommitCfgs >= 0 && numCommitCfgs < 3); - vm.assume(numExecCfgs >= 0 && numExecCfgs < 3); + numCommitCfgs = bound(numCommitCfgs, 0, 2); + numExecCfgs = bound(numExecCfgs, 0, 2); bytes32[] memory p2pIds = _makeBytes32Array(4, 0); bytes[] memory signers = _makeBytesArray(4, 10); diff --git a/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol b/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol index d937b5654a..7598f9ccb6 100644 --- a/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol +++ b/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol @@ -55,13 +55,8 @@ contract CommitStoreRealRMNSetup is PriceRegistrySetup, OCR2BaseSetup { OCR2BaseSetup.setUp(); RMN.Voter[] memory voters = new RMN.Voter[](1); - voters[0] = RMN.Voter({ - blessVoteAddr: BLESS_VOTE_ADDR, - curseVoteAddr: address(9999), - curseUnvoteAddr: address(19999), - blessWeight: 1, - curseWeight: 1 - }); + voters[0] = + RMN.Voter({blessVoteAddr: BLESS_VOTE_ADDR, curseVoteAddr: address(9999), blessWeight: 1, curseWeight: 1}); // Overwrite base mock rmn with real. s_rmn = new RMN(RMN.Config({voters: voters, blessWeightThreshold: 1, curseWeightThreshold: 1})); s_commitStore = new CommitStoreHelper( @@ -424,7 +419,7 @@ contract CommitStore_report is CommitStoreSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(CommitStore.CursedByRMN.selector); bytes memory report; s_commitStore.report(report, ++s_latestEpochAndRound); @@ -587,14 +582,14 @@ contract CommitStore_isUnpausedAndRMNHealthy is CommitStoreSetup { assertTrue(s_commitStore.isUnpausedAndNotCursed()); // Test rmn - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); assertFalse(s_commitStore.isUnpausedAndNotCursed()); - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({curseVoteAddr: OWNER, cursesHash: bytes32(uint256(0)), forceUnvote: true}); - s_mockRMN.ownerUnvoteToCurse(records); + s_mockRMN.setGlobalCursed(false); + // TODO: also test with s_mockRMN.setChainCursed(sourceChainSelector), + // also for other similar tests (e.g., OffRamp, OnRamp) assertTrue(s_commitStore.isUnpausedAndNotCursed()); - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); s_commitStore.pause(); assertFalse(s_commitStore.isUnpausedAndNotCursed()); } diff --git a/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol b/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol index ad2aecdde9..816862cbdf 100644 --- a/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol +++ b/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol @@ -62,6 +62,8 @@ contract E2E is EVM2EVMOnRampSetup, CommitStoreSetup, EVM2EVMOffRampSetup { s_commitStore.report(commitReport, ++s_latestEpochAndRound); vm.pauseGasMetering(); + s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_commitStore), root: merkleRoots[0]}), true); + bytes32[] memory proofs = new bytes32[](0); uint256 timestamp = s_commitStore.verify(merkleRoots, proofs, 2 ** 2 - 1); assertEq(BLOCK_TIME, timestamp); diff --git a/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol index 7a32d20344..a1213c5730 100644 --- a/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol +++ b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol @@ -157,6 +157,9 @@ contract MultiRampsE2E is EVM2EVMMultiOnRampSetup, EVM2EVMMultiOffRampSetup { _commit(report, ++s_latestSequenceNumber); vm.pauseGasMetering(); + s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_offRamp), root: merkleRoots[0]}), true); + s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_offRamp), root: merkleRoots[1]}), true); + bytes32[] memory proofs = new bytes32[](0); bytes32[] memory hashedLeaves = new bytes32[](1); hashedLeaves[0] = merkleRoots[0]; diff --git a/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol b/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol index 250ef397a0..3f7b0200e6 100644 --- a/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol +++ b/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol @@ -5,53 +5,51 @@ import {RMN} from "../../RMN.sol"; import {IRMN} from "../../interfaces/IRMN.sol"; import {OwnerIsCreator} from "./../../../shared/access/OwnerIsCreator.sol"; -contract MockRMN is IRMN, OwnerIsCreator { +/// @notice WARNING: This contract is to be only used for testing, all methods are unprotected. +contract MockRMN is IRMN { error CustomError(bytes err); - bool private s_curse; - bytes private s_err; - RMN.VersionedConfig private s_versionedConfig; - mapping(bytes16 subject => bool cursed) private s_curseBySubject; + bytes private s_isCursedRevert; - function isCursed() external view override returns (bool) { - if (s_err.length != 0) { - revert CustomError(s_err); - } - return s_curse; - } + bool private s_globalCursed; + mapping(bytes16 subject => bool cursed) private s_cursedBySubject; + mapping(address commitStore => mapping(bytes32 root => bool blessed)) private s_blessedByRoot; - function isCursed(bytes16 subject) external view override returns (bool) { - if (s_err.length != 0) { - revert CustomError(s_err); - } - return s_curse || s_curseBySubject[subject]; + function setTaggedRootBlessed(IRMN.TaggedRoot calldata taggedRoot, bool blessed) external { + s_blessedByRoot[taggedRoot.commitStore][taggedRoot.root] = blessed; } - function voteToCurse(bytes32) external { - s_curse = true; + function setGlobalCursed(bool cursed) external { + s_globalCursed = cursed; } - function voteToCurse(bytes32, bytes16 subject) external { - s_curseBySubject[subject] = true; + function setChainCursed(uint64 chainSelector, bool cursed) external { + s_cursedBySubject[bytes16(uint128(chainSelector))] = cursed; } - function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory) external { - s_curse = false; + /// @notice Setting a revert error with length of 0 will disable reverts + /// @dev Useful to test revert handling of ARMProxy + function setIsCursedRevert(bytes calldata revertErr) external { + s_isCursedRevert = revertErr; } - function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory, bytes16 subject) external { - s_curseBySubject[subject] = false; - } + // IRMN implementation follows - function setRevert(bytes memory err) external { - s_err = err; + function isCursed() external view returns (bool) { + if (s_isCursedRevert.length > 0) { + revert CustomError(s_isCursedRevert); + } + return s_globalCursed; } - function isBlessed(IRMN.TaggedRoot calldata) external view override returns (bool) { - return !s_curse; + function isCursed(bytes16 subject) external view returns (bool) { + if (s_isCursedRevert.length > 0) { + revert CustomError(s_isCursedRevert); + } + return s_globalCursed || s_cursedBySubject[subject]; } - function getConfigDetails() external view returns (uint32 version, uint32 blockNumber, RMN.Config memory config) { - return (s_versionedConfig.configVersion, s_versionedConfig.blockNumber, s_versionedConfig.config); + function isBlessed(IRMN.TaggedRoot calldata taggedRoot) external view returns (bool) { + return s_blessedByRoot[taggedRoot.commitStore][taggedRoot.root]; } } diff --git a/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol b/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol new file mode 100644 index 0000000000..44ffc23b78 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {IRMN} from "../../interfaces/IRMN.sol"; +import {OwnerIsCreator} from "./../../../shared/access/OwnerIsCreator.sol"; + +// Inlined from RMN 1.0 contract. +// solhint-disable gas-struct-packing +contract RMN { + struct Voter { + address blessVoteAddr; + address curseVoteAddr; + address curseUnvoteAddr; + uint8 blessWeight; + uint8 curseWeight; + } + + struct Config { + Voter[] voters; + uint16 blessWeightThreshold; + uint16 curseWeightThreshold; + } + + struct VersionedConfig { + Config config; + uint32 configVersion; + uint32 blockNumber; + } + + struct UnvoteToCurseRecord { + address curseVoteAddr; + bytes32 cursesHash; + bool forceUnvote; + } +} + +/// @dev Retained almost as-is from commit 88f285b94c23d0c684d337064758a5edde380fe2 for compatibility with offchain +/// tests and scripts. Internal structs of the RMN 1.0 contract that were depended on have been inlined. +/// @dev This contract should no longer be used for any new tests or scripts. +/// @notice WARNING: This contract is to be only used for testing, all methods are unprotected. +// TODO: remove this contract when tests and scripts are updated +contract MockRMN is IRMN, OwnerIsCreator { + error CustomError(bytes err); + + bool private s_curse; + bytes private s_err; + RMN.VersionedConfig private s_versionedConfig; + mapping(bytes16 subject => bool cursed) private s_curseBySubject; + + function isCursed() external view override returns (bool) { + if (s_err.length != 0) { + revert CustomError(s_err); + } + return s_curse; + } + + function isCursed(bytes16 subject) external view override returns (bool) { + if (s_err.length != 0) { + revert CustomError(s_err); + } + return s_curse || s_curseBySubject[subject]; + } + + function voteToCurse(bytes32) external { + s_curse = true; + } + + function voteToCurse(bytes32, bytes16 subject) external { + s_curseBySubject[subject] = true; + } + + function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory) external { + s_curse = false; + } + + function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory, bytes16 subject) external { + s_curseBySubject[subject] = false; + } + + function setRevert(bytes memory err) external { + s_err = err; + } + + function isBlessed(IRMN.TaggedRoot calldata) external view override returns (bool) { + return !s_curse; + } + + function getConfigDetails() external view returns (uint32 version, uint32 blockNumber, RMN.Config memory config) { + return (s_versionedConfig.configVersion, s_versionedConfig.blockNumber, s_versionedConfig.config); + } +} diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol index 3827307739..ab7057f340 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol @@ -787,9 +787,7 @@ contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup { } function test_WithCurseOnAnotherSourceChain_Success() public { - s_mockRMN.voteToCurse( - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, bytes16(uint128(SOURCE_CHAIN_SELECTOR_2)) - ); + s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_2, true); s_offRamp.executeSingleReport( _generateReportFromMessages( SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1) @@ -832,7 +830,7 @@ contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1)); s_offRamp.executeSingleReport( _generateReportFromMessages( @@ -841,9 +839,7 @@ contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup { new uint256[](0) ); // Uncurse should succeed - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({curseVoteAddr: OWNER, cursesHash: bytes32(uint256(0)), forceUnvote: true}); - s_mockRMN.ownerUnvoteToCurse(records); + s_mockRMN.setGlobalCursed(false); s_offRamp.executeSingleReport( _generateReportFromMessages( SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1) @@ -853,8 +849,7 @@ contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup { } function test_UnhealthySingleChainCurse_Revert() public { - bytes16 subject = bytes16(uint128(SOURCE_CHAIN_SELECTOR_1)); - s_mockRMN.voteToCurse(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, subject); + s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_1, true); vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1)); s_offRamp.executeSingleReport( _generateReportFromMessages( @@ -863,9 +858,7 @@ contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup { new uint256[](0) ); // Uncurse should succeed - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({curseVoteAddr: OWNER, cursesHash: bytes32(uint256(0)), forceUnvote: true}); - s_mockRMN.ownerUnvoteToCurse(records, subject); + s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_1, false); s_offRamp.executeSingleReport( _generateReportFromMessages( SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1) @@ -1569,7 +1562,7 @@ contract EVM2EVMMultiOffRamp_batchExecute is EVM2EVMMultiOffRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1)); s_offRamp.batchExecute( _generateBatchReportFromMessages( @@ -1578,9 +1571,7 @@ contract EVM2EVMMultiOffRamp_batchExecute is EVM2EVMMultiOffRampSetup { new uint256[][](1) ); // Uncurse should succeed - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({curseVoteAddr: OWNER, cursesHash: bytes32(uint256(0)), forceUnvote: true}); - s_mockRMN.ownerUnvoteToCurse(records); + s_mockRMN.setGlobalCursed(false); s_offRamp.batchExecute( _generateBatchReportFromMessages( SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1) @@ -3533,7 +3524,7 @@ contract EVM2EVMMultiOffRamp_commit is EVM2EVMMultiOffRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + s_mockRMN.setGlobalCursed(true); EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1); roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1, diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol index 4e35e5241c..b53fb503fb 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol @@ -474,13 +474,8 @@ contract EVM2EVMMultiOffRampSetup is TokenSetup, PriceRegistrySetup, MultiOCR3Ba function _setupRealRMN() internal { RMN.Voter[] memory voters = new RMN.Voter[](1); - voters[0] = RMN.Voter({ - blessVoteAddr: BLESS_VOTE_ADDR, - curseVoteAddr: address(9999), - curseUnvoteAddr: address(19999), - blessWeight: 1, - curseWeight: 1 - }); + voters[0] = + RMN.Voter({blessVoteAddr: BLESS_VOTE_ADDR, curseVoteAddr: address(9999), blessWeight: 1, curseWeight: 1}); // Overwrite base mock rmn with real. s_realRMN = new RMN(RMN.Config({voters: voters, blessWeightThreshold: 1, curseWeightThreshold: 1})); } diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol index 18013636bf..e94184e3c5 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol @@ -629,13 +629,11 @@ contract EVM2EVMOffRamp_execute is EVM2EVMOffRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(EVM2EVMOffRamp.CursedByRMN.selector); s_offRamp.execute(_generateReportFromMessages(_generateMessagesWithTokens()), new uint256[](0)); // Uncurse should succeed - RMN.UnvoteToCurseRecord[] memory records = new RMN.UnvoteToCurseRecord[](1); - records[0] = RMN.UnvoteToCurseRecord({curseVoteAddr: OWNER, cursesHash: bytes32(uint256(0)), forceUnvote: true}); - s_mockRMN.ownerUnvoteToCurse(records); + s_mockRMN.setGlobalCursed(false); s_offRamp.execute(_generateReportFromMessages(_generateMessagesWithTokens()), new uint256[](0)); } diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol index f888e020c9..4b04a6fc16 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol @@ -629,7 +629,7 @@ contract EVM2EVMMultiOnRamp_forwardFromRouter is EVM2EVMMultiOnRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOnRamp.CursedByRMN.selector, DEST_CHAIN_SELECTOR)); s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER); } diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol index fe0b908a42..197a87b708 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol @@ -544,7 +544,7 @@ contract EVM2EVMOnRamp_forwardFromRouter is EVM2EVMOnRampSetup { } function test_Unhealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(type(uint128).max)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(EVM2EVMOnRamp.CursedByRMN.selector); s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER); } diff --git a/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol index 51c49938c6..290c4ae153 100644 --- a/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol @@ -67,7 +67,7 @@ contract BurnFromMintTokenPool_lockOrBurn is BurnFromMintTokenPoolSetup { // Should not burn tokens if cursed. function test_PoolBurnRevertNotHealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_burnMintERC677.balanceOf(address(s_pool)); vm.startPrank(s_burnMintOnRamp); diff --git a/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol index b23f54f1cd..c628c510d4 100644 --- a/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol @@ -70,7 +70,7 @@ contract BurnMintTokenPool_lockOrBurn is BurnMintTokenPoolSetup { // Should not burn tokens if cursed. function test_PoolBurnRevertNotHealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_burnMintERC677.balanceOf(address(s_pool)); vm.startPrank(s_burnMintOnRamp); @@ -130,7 +130,7 @@ contract BurnMintTokenPool_releaseOrMint is BurnMintTokenPoolSetup { function test_PoolMintNotHealthy_Revert() public { // Should not mint tokens if cursed. - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_burnMintERC677.balanceOf(OWNER); vm.startPrank(s_burnMintOffRamp); diff --git a/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol index ab4df477be..22362ee4a5 100644 --- a/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol @@ -68,7 +68,7 @@ contract BurnWithFromMintTokenPool_lockOrBurn is BurnWithFromMintTokenPoolSetup // Should not burn tokens if cursed. function test_PoolBurnRevertNotHealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_burnMintERC677.balanceOf(address(s_pool)); vm.startPrank(s_burnMintOnRamp); 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 42aae6f642..97d0d4e894 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol @@ -150,7 +150,7 @@ contract LockReleaseTokenPool_lockOrBurn is LockReleaseTokenPoolSetup { function test_PoolBurnRevertNotHealthy_Revert() public { // Should not burn tokens if cursed. - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_token.balanceOf(address(s_lockReleaseTokenPoolWithAllowList)); vm.startPrank(s_allowedOnRamp); @@ -287,7 +287,7 @@ contract LockReleaseTokenPool_releaseOrMint is LockReleaseTokenPoolSetup { function test_PoolMintNotHealthy_Revert() public { // Should not mint tokens if cursed. - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); uint256 before = s_token.balanceOf(OWNER); vm.startPrank(s_allowedOffRamp); vm.expectRevert(TokenPool.CursedByRMN.selector); diff --git a/contracts/src/v0.8/ccip/test/router/Router.t.sol b/contracts/src/v0.8/ccip/test/router/Router.t.sol index fdd6c3ab86..cfe01e3c41 100644 --- a/contracts/src/v0.8/ccip/test/router/Router.t.sol +++ b/contracts/src/v0.8/ccip/test/router/Router.t.sol @@ -296,7 +296,7 @@ contract Router_ccipSend is EVM2EVMOnRampSetup { function test_WhenNotHealthy_Revert() public { Client.EVM2AnyMessage memory message = _generateEmptyMessage(); - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(Router.BadARMSignal.selector); s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message); } @@ -864,7 +864,7 @@ contract Router_routeMessage is EVM2EVMOffRampSetup { } function test_WhenNotHealthy_Revert() public { - s_mockRMN.voteToCurse(bytes16(0)); + s_mockRMN.setGlobalCursed(true); vm.expectRevert(Router.BadARMSignal.selector); s_destRouter.routeMessage( generateReceiverMessage(SOURCE_CHAIN_SELECTOR), GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver) diff --git a/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go index 83daac3356..e5cb17ded0 100644 --- a/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go +++ b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go @@ -41,23 +41,36 @@ type RMNConfig struct { CurseWeightThreshold uint16 } -type RMNUnvoteToCurseRecord struct { +type RMNOwnerUnvoteToCurseRequest struct { CurseVoteAddr common.Address - CursesHash [32]byte + Unit RMNUnvoteToCurseRequest ForceUnvote bool } +type RMNRecordedCurseRelatedOp struct { + Tag uint8 + BlockTimestamp uint64 + Cursed bool + CurseVoteAddr common.Address + Subject [16]byte + CurseId [16]byte +} + +type RMNUnvoteToCurseRequest struct { + Subject [16]byte + CursesHash [28]byte +} + type RMNVoter struct { - BlessVoteAddr common.Address - CurseVoteAddr common.Address - CurseUnvoteAddr common.Address - BlessWeight uint8 - CurseWeight uint8 + BlessVoteAddr common.Address + CurseVoteAddr common.Address + BlessWeight uint8 + CurseWeight uint8 } var ARMContractMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseUnvoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"curseId\",\"type\":\"bytes32\"}],\"name\":\"AlreadyVotedToCurse\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCurseState\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expectedCursesHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actualCursesHash\",\"type\":\"bytes32\"}],\"name\":\"InvalidCursesHash\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"}],\"name\":\"InvalidVoter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustRecoverFromCurse\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyVotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseUnvoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"Cursed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"OwnerCursed\",\"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\":[],\"name\":\"RecoveredFromCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"voteCount\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"ReusedVotesToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"expectedCursesHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"actualCursesHash\",\"type\":\"bytes32\"}],\"name\":\"SkippedUnvoteToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"wasBlessed\",\"type\":\"bool\"}],\"name\":\"TaggedRootBlessVotesReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"TaggedRootBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"voteCount\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"}],\"name\":\"UnvotedToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"}],\"name\":\"VotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"voteCount\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"curseId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"VotedToCurse\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"getBlessProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blessVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"blessed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseUnvoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurseProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"curseVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"uint32[]\",\"name\":\"voteCounts\",\"type\":\"uint32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"cursesHashes\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"cursed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"\",\"type\":\"bytes16\"}],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ownerCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"ownerResetBlessVotes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"forceUnvote\",\"type\":\"bool\"}],\"internalType\":\"structRMN.UnvoteToCurseRecord[]\",\"name\":\"unvoteRecords\",\"type\":\"tuple[]\"}],\"name\":\"ownerUnvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseUnvoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"}],\"name\":\"unvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"voteToBless\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"curseId\",\"type\":\"bytes32\"}],\"name\":\"voteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162004c2538038062004c25833981016040819052620000349162000e20565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be816200013a565b5050604080516080808201835260008083526020830181905260608301526001600160801b03928201929092529150600190620000fd90829062000fad565b82604001516001600160801b0316901c6001600160801b0316101562000127576200012762000fc9565b506200013381620001e5565b506200115b565b336001600160a01b03821603620001945760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001fa600954640100000000900460ff1690565b1562000219576040516306523e6560e51b815260040160405180910390fd5b620002248162000a0c565b62000242576040516306b7c75960e31b815260040160405180910390fd5b6040805160028054608060208202840181019094526060830181815260009484928491879085015b82821015620002e85760008481526020908190206040805160a0810182526003860290920180546001600160a01b0390811684526001808301548216858701526002909201549081169284019290925260ff600160a01b830481166060850152600160a81b909204909116608083015290835290920191016200026a565b505050908252506001919091015461ffff808216602080850191909152620100009283900482166040948501528601516003805494880151831690930263ffffffff1990941691161791909117905590505b600254156200045a576002805460009190620003599060019062000fad565b815481106200036c576200036c62000fdf565b600091825260208083206040805160a081018252600390940290910180546001600160a01b03908116808652600183015482168686019081526002938401548084168887015260ff600160a01b8204811660608a0152600160a81b90910416608088015290875260058552838720805465ffffffffffff19169055511685526007909252909220805460ff1916905581549092508062000410576200041062000ff5565b60008281526020902060036000199092019182020180546001600160a01b03199081168255600182018054909116905560020180546001600160b01b03191690559055506200033a565b60005b8251518110156200052e5782518051600291908390811062000483576200048362000fdf565b602090810291909101810151825460018181018555600094855293839020825160039092020180546001600160a01b039283166001600160a01b03199182161782559383015181860180549184169190951617909355604082015160029093018054606084015160809094015160ff908116600160a81b0260ff60a81b1991909516600160a01b026001600160a81b031990921695909316949094179390931716179055016200045d565b5060048054600090620005479063ffffffff166200100b565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b83515160ff821610156200071557600084600001518260ff168151811062000597576200059762000fdf565b602090810291909101810151604080516060808201835263ffffffff88811683528185015160ff90811684880190815289821685870190815287516001600160a01b03908116600090815260058b52888120975188549451935190871664ffffffffff1990951694909417640100000000938616939093029290921760ff60281b1916650100000000009385169390930292909217909555855160a08101875260018082526080808a01518516838c019081528a8c01805186168a526007808e528b8b205462010000908190048a16878e019081529d8d015188169a87019a8b52825188168c52818f528c8c20860154948701948552915187168b52909c52989097209151825498519951965161ffff1990991690151561ff0019161761010099909416989098029290921762010000600160d01b03191693909216909602600160301b600160d01b031916919091176601000000000000939091169290920291909117835551910155506200070d8162001031565b90506200056b565b506004805463ffffffff4381166401000000000263ffffffff60201b1990921691909117909155604051908216907f7cf8e698b191db138396ab0eae2ad5b3fe353fd014fd5956b034b86f2d605cfd906200077290869062001053565b60405180910390a2604080516060810182528482015161ffff168152600060208201819052918101829052905b83515160ff821610156200096157600084600001518260ff1681518110620007cb57620007cb62000fdf565b6020908102919091018101518101516001600160a01b03808216600090815260078452604090819020815160a081018352815460ff808216151580845261010083049091169783019790975263ffffffff62010000820416938201939093526601000000000000909204909216606082015260019091015460808201529092509062000881576001600160a01b038216600090815260076020526040812080546001600160d01b0319168155600101556200094b565b805180156200089a57506000816040015163ffffffff16115b156200094b57806020015160ff1684602001818151620008bb919062001106565b61ffff1690525060208082015160408084015160808501519388015191516001600160a01b0387169463ffffffff8b16947fb4a70189a30e3d3b9c77d291f83699633e70ab4427fc3644a955ab4cca077b03946200094294919391929160ff94909416845263ffffffff929092166020840152604083015261ffff16606082015260800190565b60405180910390a35b505080620009599062001031565b90506200079f565b508051602082015161ffff91821691161080156040830152620009c0578163ffffffff167f6ec7e144a45fa03ed986874794df08b5b6bbbb27ed6454b4e6eaa74248b5e33342604051620009b791815260200190565b60405180910390a25b805160098054602084015160409094015115156401000000000260ff60201b1961ffff958616620100000263ffffffff1990931695909416949094171791909116919091179055505050565b805151600090158062000a2157508151516080105b8062000a335750602082015161ffff16155b8062000a455750604082015161ffff16155b1562000a5357506000919050565b6000806000846000015151600362000a6c91906200112b565b6001600160401b0381111562000a865762000a8662000d45565b60405190808252806020026020018201604052801562000ab0578160200160208202803683370190505b50905060005b85515181101562000c755760008660000151828151811062000adc5762000adc62000fdf565b6020026020010151905060006001600160a01b031681600001516001600160a01b0316148062000b17575060208101516001600160a01b0316155b8062000b2e575060408101516001600160a01b0316155b8062000b505750606081015160ff1615801562000b505750608081015160ff16155b1562000b63575060009695505050505050565b80518362000b738460036200112b565b62000b8090600062001145565b8151811062000b935762000b9362000fdf565b6001600160a01b039092166020928302919091018201528101518362000bbb8460036200112b565b62000bc890600162001145565b8151811062000bdb5762000bdb62000fdf565b6001600160a01b039092166020928302919091019091015260408101518362000c068460036200112b565b62000c1390600262001145565b8151811062000c265762000c2662000fdf565b6001600160a01b0390921660209283029190910190910152606081015162000c529060ff168662001145565b9450806080015160ff168462000c69919062001145565b93505060010162000ab6565b5060005b815181101562000d1a57600082828151811062000c9a5762000c9a62000fdf565b60200260200101519050600082600162000cb5919062001145565b90505b835181101562000d0f5783818151811062000cd75762000cd762000fdf565b60200260200101516001600160a01b0316826001600160a01b03160362000d0657506000979650505050505050565b60010162000cb8565b505060010162000c79565b50846020015161ffff16831015801562000d3c5750846040015161ffff168210155b95945050505050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171562000d805762000d8062000d45565b60405290565b60405160a081016001600160401b038111828210171562000d805762000d8062000d45565b604051601f8201601f191681016001600160401b038111828210171562000dd65762000dd662000d45565b604052919050565b80516001600160a01b038116811462000df657600080fd5b919050565b805160ff8116811462000df657600080fd5b805161ffff8116811462000df657600080fd5b6000602080838503121562000e3457600080fd5b82516001600160401b038082111562000e4c57600080fd5b8185019150606080838803121562000e6357600080fd5b62000e6d62000d5b565b83518381111562000e7d57600080fd5b8401601f8101891362000e8f57600080fd5b80518481111562000ea45762000ea462000d45565b62000eb4878260051b0162000dab565b818152878101955060a091820283018801918b83111562000ed457600080fd5b928801925b8284101562000f625780848d03121562000ef35760008081fd5b62000efd62000d86565b62000f088562000dde565b815262000f178a860162000dde565b8a820152604062000f2a81870162000dde565b9082015262000f3b85880162000dfb565b87820152608062000f4e81870162000dfb565b908201528752958801959283019262000ed9565b5083525062000f75905084860162000e0d565b8582015262000f876040850162000e0d565b6040820152979650505050505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000fc35762000fc362000f97565b92915050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600063ffffffff80831681810362001027576200102762000f97565b6001019392505050565b600060ff821660ff81036200104a576200104a62000f97565b60010192915050565b60006020808352608080840185516060808588015282825180855260a0945060a089019150868401935060005b81811015620010d857845180516001600160a01b0390811685528982015181168a860152604080830151909116908501528481015160ff90811686860152908801511687840152938701939185019160010162001080565b50509488015161ffff8116604089015294604089015161ffff811660608a0152955098975050505050505050565b61ffff81811683821601908082111562001124576200112462000f97565b5092915050565b808202811582820484141762000fc35762000fc362000f97565b8082018082111562000fc35762000fc362000f97565b613aba806200116b6000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c80634d616771116100b25780639799861111610081578063e4bbc05c11610066578063e4bbc05c1461029c578063f2fde38b146102a4578063f33f2895146102b757600080fd5b80639799861114610276578063ba86a1f01461028957600080fd5b80634d61677114610220578063618af1281461023357806379ba5097146102465780638da5cb5b1461024e57600080fd5b8063397796f7116100ee578063397796f7146101ca5780633987d651146101dd5780633f42ab73146101f657806347cf2b601461020d57600080fd5b8063119a352714610120578063181f5a77146101355780632cbc26bb1461018757806335aea869146101b7575b600080fd5b61013361012e36600461317f565b6102d9565b005b6101716040518060400160405280600d81526020017f524d4e20312e352e302d6465760000000000000000000000000000000000000081525081565b60405161017e9190613198565b60405180910390f35b6101a7610195366004613205565b50600954640100000000900460ff1690565b604051901515815260200161017e565b6101336101c5366004613272565b610765565b600954640100000000900460ff166101a7565b6101e5610afa565b60405161017e9594939291906132ee565b6101fe610efb565b60405161017e93929190613448565b61013361021b36600461355e565b611033565b6101a761022e3660046136b6565b611047565b6101336102413660046136ce565b6110d9565b61013361158a565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161017e565b610133610284366004613743565b611687565b610133610297366004613743565b611bb4565b610133611d8c565b6101336102b23660046137a6565b611e51565b6102ca6102c53660046136b6565b611e62565b60405161017e939291906137c1565b33600090815260076020908152604091829020825160a081018452815460ff808216151580845261010083049091169483019490945263ffffffff6201000082041694820194909452660100000000000090930473ffffffffffffffffffffffffffffffffffffffff16606084015260010154608083015261038e576040517f669f262e0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b33600090815260086020908152604080832085845290915290205460ff16156103ec576040517f9baf703d00000000000000000000000000000000000000000000000000000000815233600482015260248101839052604401610385565b3360009081526008602090815260408083208584529091529081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558101805161043e9061381e565b63ffffffff16905260808101516040805160208101929092528101839052606001604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206080840190815233600090815260078452829020845181548686015187860180516060808b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169515157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169590951761010060ff94851602177fffffffffffff000000000000000000000000000000000000000000000000ffff166201000063ffffffff92831681027fffffffffffff0000000000000000000000000000000000000000ffffffffffff1691909117660100000000000073ffffffffffffffffffffffffffffffffffffffff9096169590950294909417865595516001958601558651938401875260095461ffff8082168652938104909316978401979097526401000000009091041615159381019390935292519192911690036105fa57816020015160ff16816020018181516105f29190613841565b61ffff169052505b60045460208381015160408086015160808088015187860151845160ff909616865263ffffffff93841696860196909652928401899052606084019290925261ffff90931690820152911690339082907f8e5ceca76dae647f687fccbe8d42a3796e68330812669bd5003b938dacb1b6dd9060a00160405180910390a381604001511580156106995750816000015161ffff16826020015161ffff1610155b156106e35760016040838101919091525142815263ffffffff8216907f6ec7e144a45fa03ed986874794df08b5b6bbbb27ed6454b4e6eaa74248b5e3339060200160405180910390a25b5080516009805460208401516040909401511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff61ffff95861662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000909316959094169490941717919091169190911790555050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815260076020908152604091829020825160a081018452815460ff808216151583526101008204169382019390935263ffffffff62010000840416938101939093526601000000000000909104909216606082015260019091015460808201526107f560095460ff6401000000009091041690565b1561082c576040517fca47cca000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806060015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610897576040517f669f262e000000000000000000000000000000000000000000000000000000008152336004820152602401610385565b805115806108ad5750604081015163ffffffff16155b156108e4576040517f9ff6d96b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160800151146109315760808101516040517f79aa5c5f000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610385565b6004546020820151604080840151905173ffffffffffffffffffffffffffffffffffffffff87169363ffffffff16927f56c9f1d1001236f66c1e5d598905029b4093031f31aead3449a53d832eade225926109a992889060ff93909316835263ffffffff919091166020830152604082015260600190565b60405180910390a3600060408281018281526080840183815273ffffffffffffffffffffffffffffffffffffffff878116855260076020908152939094208551815494870151935160608801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009096169115157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169190911761010060ff909516948502177fffffffffffff000000000000000000000000000000000000000000000000ffff166201000063ffffffff90921682027fffffffffffff0000000000000000000000000000000000000000ffffffffffff16176601000000000000959096169490940294909417845551600190930192909255600980549091600291610adb9185910461ffff16613863565b92506101000a81548161ffff021916908361ffff160217905550505050565b60095460028054604080516020808402820181019092528281526060948594859462010000830461ffff169464010000000090930460ff16936000938493919290849084015b82821015610bec5760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff74010000000000000000000000000000000000000000830481166060850152750100000000000000000000000000000000000000000090920490911660808301529083529092019101610b40565b50505050905060005b8151811015610cbb57600060076000848481518110610c1657610c1661387e565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff9081168352828201939093526040918201600020825160a081018452815460ff808216151583526101008204169382019390935263ffffffff6201000084041693810184905266010000000000009092049093166060820152600190920154608083015290915015610cb257610caf846138ad565b93505b50600101610bf5565b508167ffffffffffffffff811115610cd557610cd5613471565b604051908082528060200260200182016040528015610cfe578160200160208202803683370190505b5096508167ffffffffffffffff811115610d1a57610d1a613471565b604051908082528060200260200182016040528015610d43578160200160208202803683370190505b5095508167ffffffffffffffff811115610d5f57610d5f613471565b604051908082528060200260200182016040528015610d88578160200160208202803683370190505b5094506000805b8251811015610ef0576000838281518110610dac57610dac61387e565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff808216600090815260078452604090819020815160a081018352815460ff808216151583526101008204169682019690965263ffffffff6201000087041692810183905266010000000000009095049092166060850152600190910154608084015290925015610ee657818b8581518110610e4d57610e4d61387e565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080604001518a8581518110610e9e57610e9e61387e565b602002602001019063ffffffff16908163ffffffff16815250508060800151898581518110610ecf57610ecf61387e565b6020908102919091010152610ee3846138ad565b93505b5050600101610d8f565b505050509091929394565b6040805160608082018352808252600060208084018290528385018290526004548551600280549384028201608090810190985294810183815263ffffffff808416986401000000009094041696959194919385939192859285015b828210156110035760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff74010000000000000000000000000000000000000000830481166060850152750100000000000000000000000000000000000000000090920490911660808301529083529092019101610f57565b505050908252506001919091015461ffff8082166020840152620100009091041660409091015292939192919050565b61103b612128565b611044816121a9565b50565b60006006816110a561105e368690038601866138e5565b80516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b8152602081019190915260400160002054760100000000000000000000000000000000000000000000900460ff1692915050565b6110e1612128565b60005b818110156114055760008383838181106111005761110061387e565b905060600201803603810190611116919061393c565b805173ffffffffffffffffffffffffffffffffffffffff908116600090815260076020908152604091829020825160a081018452815460ff808216151583526101008204169382019390935263ffffffff6201000084041681850152660100000000000090920490931660608201526001909201546080830152820151919250901580156111ac57508160200151816080015114155b156112145781516080820151602080850151604080519384529183015273ffffffffffffffffffffffffffffffffffffffff909216917ff4e3b20447f3f83360469333a2578825ae355d192dd6f59c6516d832fa425a53910160405180910390a250506113fd565b8051158061122a5750604081015163ffffffff16155b156112365750506113fd565b81516004546020838101516040808601516080870151825160ff909416845263ffffffff918216948401949094529082019290925273ffffffffffffffffffffffffffffffffffffffff909316929116907f56c9f1d1001236f66c1e5d598905029b4093031f31aead3449a53d832eade2259060600160405180910390a36000604082810182815260808401838152855173ffffffffffffffffffffffffffffffffffffffff908116855260076020908152939094208551815494870151935160608801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009096169115157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169190911761010060ff909516948502177fffffffffffff000000000000000000000000000000000000000000000000ffff166201000063ffffffff90921682027fffffffffffff0000000000000000000000000000000000000000ffffffffffff161766010000000000009590961694909402949094178455516001909301929092556009805490916002916113e09185910461ffff16613863565b92506101000a81548161ffff021916908361ffff16021790555050505b6001016110e4565b50600954640100000000900460ff16801561142e575060095461ffff8082166201000090920416105b1561158657600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff1690556040517f08c773aaf7568c6b9110dcdfc13c27177410582ee30e157d1aa306b49d603eb790600090a160408051600280546080602082028401810190945260608301818152611586948492849160009085015b8282101561155a5760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff740100000000000000000000000000000000000000008304811660608501527501000000000000000000000000000000000000000000909204909116608083015290835290920191016114ae565b505050908252506001919091015461ffff808216602084015262010000909104166040909101526121a9565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461160b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610385565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600954640100000000900460ff16156116cc576040517fca47cca000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454336000908152600560209081526040918290208251606081018452905463ffffffff81811680845260ff6401000000008404811695850195909552650100000000009092049093169382019390935292169190821461175c576040517f669f262e000000000000000000000000000000000000000000000000000000008152336004820152602401610385565b60005b83811015611bad57600085858381811061177b5761177b61387e565b90506040020180360381019061179191906138e5565b905060006117e08280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b6000818152600660209081526040918290208251608081018452905463ffffffff81168252640100000000810461ffff1692820192909252660100000000000082046fffffffffffffffffffffffffffffffff1692810192909252760100000000000000000000000000000000000000000000900460ff161580156060830152919250906118c5573373ffffffffffffffffffffffffffffffffffffffff168663ffffffff167f274d6d5b916b0a53974b7ab86c844b97a2e03a60f658cd9a4b1c028b604d7bf1856040516118b5919061398a565b60405180910390a3505050611ba5565b8563ffffffff16816000015163ffffffff161461190857506040805160808101825263ffffffff8716815260006020820181905291810182905260608101919091525b61191a81604001518660400151612c7a565b1561196c573373ffffffffffffffffffffffffffffffffffffffff168663ffffffff167f6dfbb745226fa630aeb1b9557d17d508ddb789a04f0cb873ec16e58beb8beead856040516118b5919061398a565b61197e81604001518660400151612cb4565b6fffffffffffffffffffffffffffffffff166040820152602080860151908201805160ff909216916119b1908390613841565b61ffff1690525060208581015160408051865173ffffffffffffffffffffffffffffffffffffffff168152868401519381019390935260ff9091168282015251339163ffffffff8916917f2a08a2bd2798f0aae9a843f0f4ad4de488c1b3d5f04049940cfed736ad69fb979181900360600190a3600354602082015161ffff918216911610611ab85760016060820152602081015160405163ffffffff8816917f8257378aa73bf8e4ada848713526584a3dcee0fd3db3beed7397f7a7f5067cc991611aaf918791825173ffffffffffffffffffffffffffffffffffffffff1681526020928301519281019290925261ffff16604082015260600190565b60405180910390a25b6000918252600660209081526040928390208251815492840151948401516060909401511515760100000000000000000000000000000000000000000000027fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff909516660100000000000002949094167fffffffffffffffffff0000000000000000000000000000000000ffffffffffff61ffff909616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090941663ffffffff90921691909117929092179390931617179055505b60010161175f565b5050505050565b611bbc612128565b60045463ffffffff1660005b82811015611d86576000848483818110611be457611be461387e565b905060400201803603810190611bfa91906138e5565b90506000611c498280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b60008181526006602081815260408084208151608081018352815463ffffffff808216835261ffff640100000000830416838701526fffffffffffffffffffffffffffffffff66010000000000008304169483019490945260ff76010000000000000000000000000000000000000000000082041615156060830190815296889052949093527fffffffffffffffffff000000000000000000000000000000000000000000000090931690925591518251939450919281169087161480611d0d5750805b15611d775760408051855173ffffffffffffffffffffffffffffffffffffffff1681526020808701519082015282151581830152905163ffffffff8816917f7d15a6eebaa019ea7d5b7d38937c51ebd3befbfdf51bb630a694fd28635bbcba919081900360600190a25b50505050806001019050611bc8565b50505050565b611d94612128565b6040514281527f367ba81ba03ea9fa7ee089ecfb43b1c35e0935bc87a472abf615b7580dc16b799060200160405180910390a1600954640100000000900460ff16611e4f57600980547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff1664010000000017905560045460405163ffffffff909116907f6ec7e144a45fa03ed986874794df08b5b6bbbb27ed6454b4e6eaa74248b5e33390611e469042815260200190565b60405180910390a25b565b611e59612128565b61104481612cd7565b606060008080611e7a61105e368790038701876138e5565b6000818152600660209081526040918290208251608081018452905463ffffffff808216808452640100000000830461ffff1694840194909452660100000000000082046fffffffffffffffffffffffffffffffff1694830194909452760100000000000000000000000000000000000000000000900460ff1615156060820181905260045490965093945092909116900361211f5760208101516040820151909450611f2681612dcc565b60ff1667ffffffffffffffff811115611f4157611f41613471565b604051908082528060200260200182016040528015611f6a578160200160208202803683370190505b506002805460408051602080840282018101909252828152939950600093929190849084015b8282101561203c5760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff74010000000000000000000000000000000000000000830481166060850152750100000000000000000000000000000000000000000090920490911660808301529083529092019101611f90565b5050505090506000805b825181101561211a576120ac84600560008685815181106120695761206961387e565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205465010000000000900460ff16612c7a565b15612112578281815181106120c3576120c361387e565b6020026020010151600001518983815181106120e1576120e161387e565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261210f826138ad565b91505b600101612046565b505050505b50509193909250565b60005473ffffffffffffffffffffffffffffffffffffffff163314611e4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610385565b600954640100000000900460ff16156121ee576040517fca47cca000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121f781612e0b565b61222d576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160028054608060208202840181019094526060830181815260009484928491879085015b828210156123015760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff74010000000000000000000000000000000000000000830481166060850152750100000000000000000000000000000000000000000090920490911660808301529083529092019101612255565b505050908252506001919091015461ffff80821660208085019190915262010000928390048216604094850152860151600380549488015183169093027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090941691161791909117905590505b6002541561253957600280546000919061238a906001906139b7565b8154811061239a5761239a61387e565b600091825260208083206040805160a0810182526003909402909101805473ffffffffffffffffffffffffffffffffffffffff908116808652600183015482168686019081526002938401548084168887015260ff740100000000000000000000000000000000000000008204811660608a015275010000000000000000000000000000000000000000009091041660808801529087526005855283872080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000016905551168552600790925290922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558154909250806124a2576124a26139ca565b60008281526020902060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019182020180547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905560020180547fffffffffffffffffffff0000000000000000000000000000000000000000000016905590555061236e565b60005b8251518110156126835782518051600291908390811061255e5761255e61387e565b6020908102919091018101518254600181810185556000948552938390208251600390920201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161782559383015181860180549184169190951617909355604082015160029093018054606084015160809094015160ff9081167501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9190951674010000000000000000000000000000000000000000027fffffffffffffffffffffff000000000000000000000000000000000000000000909216959093169490941793909317161790550161253c565b506004805460009061269a9063ffffffff1661381e565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b83515160ff8216101561290857600084600001518260ff16815181106126e6576126e661387e565b602090810291909101810151604080516060808201835263ffffffff88811683528185015160ff908116848801908152898216858701908152875173ffffffffffffffffffffffffffffffffffffffff908116600090815260058b5288812097518854945193519087167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000093861693909302929092177fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff16650100000000009385169390930292909217909555855160a08101875260018082526080808a01518516838c019081528a8c01805186168a526007808e528b8b205462010000908190048a16878e019081529d8d015188169a87019a8b52825188168c52818f528c8c20860154948701948552915187168b52909c5298909720915182549851995196517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009099169015157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16176101009990941698909802929092177fffffffffffff000000000000000000000000000000000000000000000000ffff16939092169096027fffffffffffff0000000000000000000000000000000000000000ffffffffffff1691909117660100000000000093909116929092029190911783555191015550612901816139f9565b90506126be565b506004805463ffffffff438116640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117909155604051908216907f7cf8e698b191db138396ab0eae2ad5b3fe353fd014fd5956b034b86f2d605cfd9061297b908690613a18565b60405180910390a2604080516060810182528482015161ffff168152600060208201819052918101829052905b83515160ff82161015612b9b57600084600001518260ff16815181106129d0576129d061387e565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff808216600090815260078452604090819020815160a081018352815460ff808216151580845261010083049091169783019790975263ffffffff620100008204169382019390935266010000000000009092049092166060820152600190910154608082015290925090612ab65773ffffffffffffffffffffffffffffffffffffffff8216600090815260076020526040812080547fffffffffffff000000000000000000000000000000000000000000000000000016815560010155612b88565b80518015612ace57506000816040015163ffffffff16115b15612b8857806020015160ff1684602001818151612aec9190613841565b61ffff16905250602080820151604080840151608085015193880151915173ffffffffffffffffffffffffffffffffffffffff87169463ffffffff8b16947fb4a70189a30e3d3b9c77d291f83699633e70ab4427fc3644a955ab4cca077b0394612b7f94919391929160ff94909416845263ffffffff929092166020840152604083015261ffff16606082015260800190565b60405180910390a35b505080612b94906139f9565b90506129a8565b508051602082015161ffff91821691161080156040830152612bf8578163ffffffff167f6ec7e144a45fa03ed986874794df08b5b6bbbb27ed6454b4e6eaa74248b5e33342604051612bef91815260200190565b60405180910390a25b80516009805460208401516040909401511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff61ffff95861662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090931695909416949094171791909116919091179055505050565b600060808260ff1610612c8f57612c8f613a2b565b50600160ff82161b82166fffffffffffffffffffffffffffffffff1615155b92915050565b600060808260ff1610612cc957612cc9613a2b565b50600160ff919091161b1790565b3373ffffffffffffffffffffffffffffffffffffffff821603612d56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610385565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b6fffffffffffffffffffffffffffffffff821615612e0657612df2600183613a5a565b90911690612dff816139f9565b9050612dcf565b919050565b8051516000901580612e1f57508151516080105b80612e305750602082015161ffff16155b80612e415750604082015161ffff16155b15612e4e57506000919050565b60008060008460000151516003612e659190613a83565b67ffffffffffffffff811115612e7d57612e7d613471565b604051908082528060200260200182016040528015612ea6578160200160208202803683370190505b50905060005b8551518110156130a357600086600001518281518110612ece57612ece61387e565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161480612f2f5750602081015173ffffffffffffffffffffffffffffffffffffffff16155b80612f525750604081015173ffffffffffffffffffffffffffffffffffffffff16155b80612f725750606081015160ff16158015612f725750608081015160ff16155b15612f84575060009695505050505050565b805183612f92846003613a83565b612f9d906000613a9a565b81518110612fad57612fad61387e565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015281015183612fe0846003613a83565b612feb906001613a9a565b81518110612ffb57612ffb61387e565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152604081015183613031846003613a83565b61303c906002613a9a565b8151811061304c5761304c61387e565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260608101516130839060ff1686613a9a565b9450806080015160ff16846130989190613a9a565b935050600101612eac565b5060005b81518110156131555760008282815181106130c4576130c461387e565b6020026020010151905060008260016130dd9190613a9a565b90505b835181101561314b578381815181106130fb576130fb61387e565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361314357506000979650505050505050565b6001016130e0565b50506001016130a7565b50846020015161ffff1683101580156131765750846040015161ffff168210155b95945050505050565b60006020828403121561319157600080fd5b5035919050565b60006020808352835180602085015260005b818110156131c6578581018301518582016040015282016131aa565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561321757600080fd5b81357fffffffffffffffffffffffffffffffff000000000000000000000000000000008116811461324757600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114612e0657600080fd5b6000806040838503121561328557600080fd5b61328e8361324e565b946020939093013593505050565b60008151808452602080850194506020840160005b838110156132e357815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016132b1565b509495945050505050565b60a08152600061330160a083018861329c565b82810360208481019190915287518083528882019282019060005b8181101561333e57845163ffffffff168352938301939183019160010161331c565b50508481036040860152875180825290820192508188019060005b8181101561337557825185529383019391830191600101613359565b50505061ffff8616606085015250905082151560808301525b9695505050505050565b8051606080845281518482018190526000926080916020918201918388019190865b8281101561341f578451805173ffffffffffffffffffffffffffffffffffffffff908116865283820151811684870152604080830151909116908601528781015160ff908116898701529087015116868501529381019360a0909301926001016133ba565b508781015161ffff81168a830152955050506040860151935061338e604088018561ffff169052565b600063ffffffff8086168352808516602084015250606060408301526131766060830184613398565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156134c3576134c3613471565b60405290565b60405160a0810167ffffffffffffffff811182821017156134c3576134c3613471565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561353357613533613471565b604052919050565b803560ff81168114612e0657600080fd5b803561ffff81168114612e0657600080fd5b6000602080838503121561357157600080fd5b823567ffffffffffffffff8082111561358957600080fd5b8185019150606080838803121561359f57600080fd5b6135a76134a0565b8335838111156135b657600080fd5b8401601f810189136135c757600080fd5b8035848111156135d9576135d9613471565b6135e7878260051b016134ec565b818152878101955060a091820283018801918b83111561360657600080fd5b928801925b828410156136855780848d0312156136235760008081fd5b61362b6134c9565b6136348561324e565b81526136418a860161324e565b8a820152604061365281870161324e565b9082015261366185880161353b565b87820152608061367281870161353b565b908201528752958801959283019261360b565b50835250613696905084860161354c565b858201526136a66040850161354c565b6040820152979650505050505050565b6000604082840312156136c857600080fd5b50919050565b600080602083850312156136e157600080fd5b823567ffffffffffffffff808211156136f957600080fd5b818501915085601f83011261370d57600080fd5b81358181111561371c57600080fd5b86602060608302850101111561373157600080fd5b60209290920196919550909350505050565b6000806020838503121561375657600080fd5b823567ffffffffffffffff8082111561376e57600080fd5b818501915085601f83011261378257600080fd5b81358181111561379157600080fd5b8660208260061b850101111561373157600080fd5b6000602082840312156137b857600080fd5b6132478261324e565b6060815260006137d4606083018661329c565b61ffff94909416602083015250901515604090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff808316818103613837576138376137ef565b6001019392505050565b61ffff81811683821601908082111561385c5761385c6137ef565b5092915050565b61ffff82811682821603908082111561385c5761385c6137ef565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036138de576138de6137ef565b5060010190565b6000604082840312156138f757600080fd5b6040516040810181811067ffffffffffffffff8211171561391a5761391a613471565b6040526139268361324e565b8152602083013560208201528091505092915050565b60006060828403121561394e57600080fd5b6139566134a0565b61395f8361324e565b8152602083013560208201526040830135801515811461397e57600080fd5b60408201529392505050565b815173ffffffffffffffffffffffffffffffffffffffff1681526020808301519082015260408101612cae565b81810381811115612cae57612cae6137ef565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060ff821660ff8103613a0f57613a0f6137ef565b60010192915050565b6020815260006132476020830184613398565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6fffffffffffffffffffffffffffffffff82811682821603908082111561385c5761385c6137ef565b8082028115828204841417612cae57612cae6137ef565b80820180821115612cae57612cae6137ef56fea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"}],\"name\":\"ReusedCurseId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubjectsMustBeStrictlyIncreasing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"}],\"name\":\"UnauthorizedVoter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnvoteToCurseNoop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToBlessForbiddenDuringActiveGlobalCurse\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToBlessNoop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToCurseNoop\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyVotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"CurseLifted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"}],\"name\":\"Cursed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"}],\"name\":\"PermaBlessedCommitStoreAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"}],\"name\":\"PermaBlessedCommitStoreRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"onchainCursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"name\":\"SkippedUnvoteToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"wasBlessed\",\"type\":\"bool\"}],\"name\":\"TaggedRootBlessVotesReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"TaggedRootBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"remainingAccumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"UnvotedToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"}],\"name\":\"VotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"VotedToCurse\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"getBlessProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blessVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"blessed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"getCurseProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"curseVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"bytes28[]\",\"name\":\"cursesHashes\",\"type\":\"bytes28[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"cursed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCursedSubjectsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPermaBlessedCommitStores\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"}],\"name\":\"getRecordedCurseRelatedOps\",\"outputs\":[{\"components\":[{\"internalType\":\"enumRMN.RecordedCurseRelatedOpTag\",\"name\":\"tag\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"cursed\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"}],\"internalType\":\"structRMN.RecordedCurseRelatedOp[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRecordedCurseRelatedOpsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"ownerCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"ownerRemoveThenAddPermaBlessedCommitStores\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"ownerResetBlessVotes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"internalType\":\"structRMN.UnvoteToCurseRequest\",\"name\":\"unit\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"forceUnvote\",\"type\":\"bool\"}],\"internalType\":\"structRMN.OwnerUnvoteToCurseRequest[]\",\"name\":\"ownerUnvoteToCurseRequests\",\"type\":\"tuple[]\"}],\"name\":\"ownerUnvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"internalType\":\"structRMN.UnvoteToCurseRequest[]\",\"name\":\"unvoteToCurseRequests\",\"type\":\"tuple[]\"}],\"name\":\"unvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"voteToBless\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"voteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b506040516200596238038062005962833981016040819052620000349162000aff565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000138565b505060408051608081018252600080825260208201819052918101919091526001600160c81b03606082015290506001620000fb81601062000c7d565b82606001516001600160c81b0316901c6001600160c81b0316101562000125576200012562000c99565b506200013181620001e3565b5062000e14565b336001600160a01b03821603620001925760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee816200071d565b6200020c576040516306b7c75960e31b815260040160405180910390fd5b602081015160038054604084015161ffff908116620100000263ffffffff199092169316929092179190911790555b60025415620003465760028054600091906200025a9060019062000c7d565b815481106200026d576200026d62000caf565b6000918252602080832060408051608081018252600294850290920180546001600160a01b0390811680855260019092015480821685870190815260ff600160a01b8304811687870152600160a81b909204909116606086015291875260058552828720805465ffffffffffff19169055905116855260099092529220805461ffff191690558054919250908062000309576200030962000cc5565b60008281526020902060026000199092019182020180546001600160a01b031916815560010180546001600160b01b03191690559055506200023b565b60005b81515181101562000403578151805160029190839081106200036f576200036f62000caf565b602090810291909101810151825460018181018555600094855293839020825160029092020180546001600160a01b039283166001600160a01b0319909116178155928201519284018054604084015160609094015160ff908116600160a81b0260ff60a81b1991909516600160a01b026001600160a81b0319909216959093169490941793909317161790550162000349565b50600480546000906200041c9063ffffffff1662000cdb565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b82515160ff821610156200054157600083600001518260ff16815181106200046c576200046c62000caf565b602090810291909101810151604080516060808201835263ffffffff80891683528385015160ff90811684880190815289821685870190815287516001600160a01b03908116600090815260058b5288812097518854945193518616650100000000000260ff60281b199487166401000000000264ffffffffff1990961691909716179390931791909116939093179094558587015190911683526009909552919020805491909201519092166101000261ffff1990921691909117600117905550620005398162000d01565b905062000440565b506001600160a01b0360005260096020527f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a7805461ffff191660011790556004805463ffffffff4381166401000000000263ffffffff60201b1990921691909117909155604051908216907f8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a990620005db90859062000d23565b60405180910390a26040805160c08101825260048082526001600160401b03421660208301526000928201839052606082018390526080820183905260a08201839052600c80546001808201835591909452825160029094027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7018054939490939092849260ff19909216919084908111156200067c576200067c62000dce565b021790555060208201518154604084015160608501516001600160a01b03166a010000000000000000000002600160501b600160f01b031991151569010000000000000000000260ff60481b196001600160401b039095166101000294909416610100600160501b031990931692909217929092179190911617815560808083015160a090930151811c600160801b0292901c919091176001909101555050565b80515160009015806200073257508151516010105b80620007445750602082015161ffff16155b80620007565750604082015161ffff16155b156200076457506000919050565b600080600084600001515160026200077d919062000de4565b6001600160401b0381111562000797576200079762000a24565b604051908082528060200260200182016040528015620007c1578160200160208202803683370190505b50905060005b8551518110156200095457600086600001518281518110620007ed57620007ed62000caf565b6020026020010151905060006001600160a01b031681600001516001600160a01b0316148062000828575060208101516001600160a01b0316155b806200083f575060208101516001600160a01b0316155b8062000858575060208101516001600160a01b03908116145b806200087a5750604081015160ff161580156200087a5750606081015160ff16155b156200088d575060009695505050505050565b8051836200089d84600262000de4565b620008aa90600062000dfe565b81518110620008bd57620008bd62000caf565b6001600160a01b0390921660209283029190910182015281015183620008e584600262000de4565b620008f290600162000dfe565b8151811062000905576200090562000caf565b6001600160a01b03909216602092830291909101909101526040810151620009319060ff168662000dfe565b9450806060015160ff168462000948919062000dfe565b935050600101620007c7565b5060005b8151811015620009f957600082828151811062000979576200097962000caf565b60200260200101519050600082600162000994919062000dfe565b90505b8351811015620009ee57838181518110620009b657620009b662000caf565b60200260200101516001600160a01b0316826001600160a01b031603620009e557506000979650505050505050565b60010162000997565b505060010162000958565b50846020015161ffff16831015801562000a1b5750846040015161ffff168210155b95945050505050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171562000a5f5762000a5f62000a24565b60405290565b604051608081016001600160401b038111828210171562000a5f5762000a5f62000a24565b604051601f8201601f191681016001600160401b038111828210171562000ab55762000ab562000a24565b604052919050565b80516001600160a01b038116811462000ad557600080fd5b919050565b805160ff8116811462000ad557600080fd5b805161ffff8116811462000ad557600080fd5b6000602080838503121562000b1357600080fd5b82516001600160401b038082111562000b2b57600080fd5b8185019150606080838803121562000b4257600080fd5b62000b4c62000a3a565b83518381111562000b5c57600080fd5b8401601f8101891362000b6e57600080fd5b80518481111562000b835762000b8362000a24565b62000b93878260051b0162000a8a565b818152878101955060079190911b82018701908a82111562000bb457600080fd5b918701915b8183101562000c33576080838c03121562000bd45760008081fd5b62000bde62000a65565b62000be98462000abd565b815262000bf889850162000abd565b89820152604062000c0b81860162000ada565b9082015262000c1c84870162000ada565b818701528652948701946080929092019162000bb9565b83525062000c45905084860162000aec565b8582015262000c576040850162000aec565b6040820152979650505050505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000c935762000c9362000c67565b92915050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600063ffffffff80831681810362000cf75762000cf762000c67565b6001019392505050565b600060ff821660ff810362000d1a5762000d1a62000c67565b60010192915050565b60006020808352608080840185516060808588015282825180855260a0890191508684019450600093505b8084101562000da157845180516001600160a01b03908116845288820151168884015260408082015160ff9081169185019190915290840151168383015293860193600193909301929085019062000d4e565b509488015161ffff8116604089015294604089015161ffff811660608a0152955098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b808202811582820484141762000c935762000c9362000c67565b8082018082111562000c935762000c9362000c67565b614b3e8062000e246000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c8063631ec73e116100d8578063979986111161008c578063d927f26711610066578063d927f26714610354578063f2fde38b14610374578063f33f28951461038757600080fd5b8063979986111461030b578063ba86a1f01461031e578063bd147ef41461033157600080fd5b806379ba5097116100bd57806379ba5097146102d35780638da5cb5b146102db578063970b8fc21461030357600080fd5b8063631ec73e146102ad5780636ba0526d146102c057600080fd5b8063397796f71161013a5780634102e4f4116101145780634102e4f4146102745780634d61677114610287578063586abe3c1461029a57600080fd5b8063397796f7146102425780633d0cf6101461024a5780633f42ab731461025d57600080fd5b8063181f5a771161016b578063181f5a77146101ba5780632cbc26bb14610203578063328d716c1461022657600080fd5b80630b009be21461018757806315c65588146101a5575b600080fd5b61018f6103a9565b60405161019c9190613e3f565b60405180910390f35b6101b86101b3366004613fdd565b6103ba565b005b6101f66040518060400160405280600d81526020017f524d4e20312e352e302d6465760000000000000000000000000000000000000081525081565b60405161019c9190614083565b6102166102113660046140f0565b6104e6565b604051901515815260200161019c565b600b5467ffffffffffffffff165b60405190815260200161019c565b6102166105b1565b6101b86102583660046141a0565b61068b565b6102656107ff565b60405161019c939291906142b3565b6101b86102823660046142ff565b610929565b610216610295366004614439565b61093d565b6101b86102a8366004614451565b6109cd565b6101b86102bb3660046144fc565b610a87565b6101b86102ce366004614451565b610ca0565b6101b8610d13565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b600c54610234565b6101b86103193660046145d0565b610e10565b6101b861032c3660046145d0565b611368565b61034461033f3660046140f0565b61150d565b60405161019c9493929190614645565b6103676103623660046146b6565b611946565b60405161019c9190614707565b6101b8610382366004614800565b611b68565b61039a610395366004614439565b611b79565b60405161019c9392919061481b565b60606103b56007611de1565b905090565b336000818152600960205260409020805460ff16610421576040517f85412e7f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b60045463ffffffff166000805b85518110156104a757600086828151811061044b5761044b614849565b602002602001015190506000610465858360000151611df5565b905060008061047b6001888b8760008d89611fd6565b91509150801561048d5761048d614878565b85806104965750815b95505050505080600101905061042e565b50806104df576040517ffb106b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b600b5460009067ffffffffffffffff16810361050457506000919050565b7f0100000000000000000000000000000100000000000000000000000000000000600052600a6020527fcf943f0e419056430919a3fdfd72276bc0b123ebdd670f4152b82bffbfb8bb385468010000000000000000900460ff16806105a657507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166000908152600a602052604090205468010000000000000000900460ff165b92915050565b919050565b600b5460009067ffffffffffffffff1681036105cd5750600090565b7f0100000000000000000000000000000100000000000000000000000000000000600052600a6020527fcf943f0e419056430919a3fdfd72276bc0b123ebdd670f4152b82bffbfb8bb385468010000000000000000900460ff16806103b55750507f0100000000000000000000000000000000000000000000000000000000000000600052600a6020527f1d4cd6d2639449a552dbfb463b59316946d78c518b3170daa4a4c217bef019ba5468010000000000000000900460ff1690565b6106936126a4565b60005b8251811015610746576106cc8382815181106106b4576106b4614849565b6020026020010151600761272790919063ffffffff16565b1561073e577fdca892154bbc36d0c05ccd01b3d0411875cb1b841fcdeebb384e5d0d6eb06b4483828151811061070457610704614849565b6020026020010151604051610735919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a15b600101610696565b5060005b81518110156107fa5761078082828151811061076857610768614849565b6020026020010151600761274990919063ffffffff16565b156107f2577f66b4b4752c65ae8cd2f3a0a48c7dc8b2118c60d5ea15514992eb2ddf56c9cb158282815181106107b8576107b8614849565b60200260200101516040516107e9919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a15b60010161074a565b505050565b6040805160608082018352808252600060208084018290528385018290526004548551600280549384028201608090810190985294810183815263ffffffff808416986401000000009094041696959194919385939192859285015b828210156108f95760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff740100000000000000000000000000000000000000008204811693850193909352750100000000000000000000000000000000000000000090049091166060830152908352909201910161085b565b505050908252506001919091015461ffff8082166020840152620100009091041660409091015292939192919050565b6109316126a4565b61093a8161276b565b50565b600060068161099b610954368690038601866148a7565b80516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b815260208101919091526040016000205460ff16806105a657506105a66109c56020840184614800565b600790612eef565b337fffffffffffffffffffffffff000000000000000000000000000000000000000181016109fd576109fd614878565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600960205260409020805460ff16610a75576040517f85412e7f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610418565b610a8182858584612f1e565b50505050565b610a8f6126a4565b600454600090819063ffffffff16815b8451811015610b66576000858281518110610abc57610abc614849565b602002602001015190506000610ada84836020015160000151611df5565b9050600080610b3d600087866000015187602001518860400151600960008b6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002089611fd6565b915091508680610b4a5750815b96508780610b555750805b975050505050806001019050610a9f565b508215610c615760408051600280546080602082028401810190945260608301818152610c61948492849160009085015b82821015610c355760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff7401000000000000000000000000000000000000000082048116938501939093527501000000000000000000000000000000000000000000900490911660608301529083529092019101610b97565b505050908252506001919091015461ffff8082166020840152620100009091041660409091015261276b565b8180610c6a5750825b610a81576040517ffb106b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca86126a4565b73ffffffffffffffffffffffffffffffffffffffff60005260096020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a7610a8182858584612f1e565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610418565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610e397f01000000000000000000000000000001000000000000000000000000000000006104e6565b15610e70576040517fcde2d97c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454336000908152600560209081526040918290208251606081018452905463ffffffff81811680845260ff64010000000084048116958501959095526501000000000090920490931693820193909352921691908214610f00576040517f85412e7f000000000000000000000000000000000000000000000000000000008152336004820152602401610418565b600160005b8481101561132f576000868683818110610f2157610f21614849565b905060400201803603810190610f3791906148a7565b90506000610f868280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b6000818152600660209081526040918290208251608081018452905460ff81161580158352610100820463ffffffff169383019390935265010000000000810461ffff169382019390935267010000000000000090920478ffffffffffffffffffffffffffffffffffffffffffffffffff16606083015291925090611062573373ffffffffffffffffffffffffffffffffffffffff168763ffffffff167f274d6d5b916b0a53974b7ab86c844b97a2e03a60f658cd9a4b1c028b604d7bf18560405161105291906148e0565b60405180910390a3505050611327565b8663ffffffff16816020015163ffffffff16146110a8575060408051608081018252600080825263ffffffff89166020830152918101829052606081019190915261110c565b6110ba816060015187604001516136d6565b1561110c573373ffffffffffffffffffffffffffffffffffffffff168763ffffffff167f6dfbb745226fa630aeb1b9557d17d508ddb789a04f0cb873ec16e58beb8beead8560405161105291906148e0565b6000945061112281606001518760400151613718565b78ffffffffffffffffffffffffffffffffffffffffffffffffff166060820152602086015160408201805160ff9092169161115e90839061493c565b61ffff1690525060208681015160408051865173ffffffffffffffffffffffffffffffffffffffff168152868401519381019390935260ff9091168282015251339163ffffffff8a16917f2a08a2bd2798f0aae9a843f0f4ad4de488c1b3d5f04049940cfed736ad69fb979181900360600190a3600354604082015161ffff91821691161061125757600181526040808201518151855173ffffffffffffffffffffffffffffffffffffffff1681526020808701519082015261ffff90911681830152905163ffffffff8916917f8257378aa73bf8e4ada848713526584a3dcee0fd3db3beed7397f7a7f5067cc9919081900360600190a25b60009182526006602090815260409283902082518154928401519484015160609094015178ffffffffffffffffffffffffffffffffffffffffffffffffff166701000000000000000266ffffffffffffff61ffff90951665010000000000029490941664ffffffffff63ffffffff909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090941693909317179390931617179055505b600101610f05565b5080156104df576040517f604c767700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113706126a4565b60045463ffffffff1660005b82811015610a8157600084848381811061139857611398614849565b9050604002018036038101906113ae91906148a7565b905060006113fd8280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b60008181526006602081815260408084208151608081018352815460ff811615158252610100810463ffffffff90811683870190815265010000000000830461ffff169584019590955267010000000000000090910478ffffffffffffffffffffffffffffffffffffffffffffffffff16606083015287875294909352939093558051925193945092878216911614806114945750805b156114fe5760408051855173ffffffffffffffffffffffffffffffffffffffff1681526020808701519082015282151581830152905163ffffffff8816917f7d15a6eebaa019ea7d5b7d38937c51ebd3befbfdf51bb630a694fd28635bbcba919081900360600190a25b5050505080600101905061137c565b600454604080516002805460806020820284018101909452606083810182815290958695600095869563ffffffff9093169486949193928492918491879085015b828210156115ec5760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff740100000000000000000000000000000000000000008204811693850193909352750100000000000000000000000000000000000000000090049091166060830152908352909201910161154e565b505050908252506001919091015461ffff80821660208085019190915262010000909204166040928301527fffffffffffffffffffffffffffffffff000000000000000000000000000000008a166000908152600a909152908120805460ff6801000000000000000082041696509293509163ffffffff80861691161080156116725750845b6000965090508560015b60028111611939578451515b6000808760000151518310156116e35787518051849081106116ac576116ac614849565b6020026020010151602001519150876000015183815181106116d0576116d0614849565b602002602001015160600151905061170a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905060005b73ffffffffffffffffffffffffffffffffffffffff82166000908152600188016020908152604080832081518083019092525463ffffffff811682526401000000009004821b63ffffffff19169181019190915290878061177a57508a63ffffffff16826000015163ffffffff16145b8061179a575073ffffffffffffffffffffffffffffffffffffffff848116145b80156117b05750602082015163ffffffff191615155b9050801561186d57856001036117d0576117c987614957565b965061186d565b85600203610182576117e560ff84168e61493c565b9c506117f08761498f565b9650838f888151811061180557611805614849565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081602001518e888151811061185657611856614849565b63ffffffff19909216602092830291909101909101525b84156118835761187c8561498f565b945061188c565b50505050611895565b50505050611688565b81600103611928578267ffffffffffffffff8111156118b6576118b6613e52565b6040519080825280602002602001820160405280156118df578160200160208202803683370190505b509a508267ffffffffffffffff8111156118fb576118fb613e52565b604051908082528060200260200182016040528015611924578160200160208202803683370190505b5099505b5061193281614957565b905061167c565b5050505050509193509193565b600c5460609060009061195984866149c4565b11611965575081611988565b600c5484101561198457600c5461197d9085906149d7565b9050611988565b5060005b60008167ffffffffffffffff8111156119a3576119a3613e52565b604051908082528060200260200182016040528015611a2157816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816119c15790505b50905060005b82811015611b5f57600c611a3b82886149c4565b81548110611a4b57611a4b614849565b600091825260209091206040805160c081019091526002909202018054829060ff166004811115611a7e57611a7e6146d8565b6004811115611a8f57611a8f6146d8565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000810460ff16151560408301526a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166060820152600190910154608081811b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090811682850152700100000000000000000000000000000000909204901b1660a0909101528251839083908110611b4c57611b4c614849565b6020908102919091010152600101611a27565b50949350505050565b611b706126a4565b61093a8161373b565b606060008080611b91610954368790038701876148a7565b6000818152600660209081526040918290208251608081018452905460ff81161515808352610100820463ffffffff90811694840185905265010000000000830461ffff169584019590955267010000000000000090910478ffffffffffffffffffffffffffffffffffffffffffffffffff166060830152600454909650939450929091169003611dd85760408101516060820151909450611c3281613830565b60ff1667ffffffffffffffff811115611c4d57611c4d613e52565b604051908082528060200260200182016040528015611c76578160200160208202803683370190505b506002805460408051602080840282018101909252828152939950600093929190849084015b82821015611d3a5760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff7401000000000000000000000000000000000000000082048116938501939093527501000000000000000000000000000000000000000000900490911660608301529083529092019101611c9c565b5050505090506000805b82518160ff161015611dd357611d5a84826136d6565b15611dc357828160ff1681518110611d7457611d74614849565b602002602001015160000151898381518110611d9257611d92614849565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152611dc082614957565b91505b611dcc816149ea565b9050611d44565b505050505b50509193909250565b60606000611dee8361389f565b9392505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166000908152600a60205260408120805463ffffffff858116911614611dee57805463ffffffff19811663ffffffff861690811783556003547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000909216176201000090910461ffff1664010000000002177fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff1680825568010000000000000000900460ff1615611dee57600260005b8154811015611fcd576000826000018281548110611ee657611ee6614849565b6000918252602080832060016002909302018281015473ffffffffffffffffffffffffffffffffffffffff1684529187019052604090912080549192509063ffffffff808a169116108015611f4d57508054640100000000900460201b63ffffffff191615155b15611fc357805463ffffffff191663ffffffff891617815560018201548554750100000000000000000000000000000000000000000090910460ff16908690600690611fa89084906601000000000000900461ffff1661493c565b92506101000a81548161ffff021916908361ffff1602179055505b5050600101611ec6565b50509392505050565b6000806001896001811115611fed57611fed6146d8565b148061200a57506000896001811115612008576120086146d8565b145b61201657612016614878565b8480612037575073ffffffffffffffffffffffffffffffffffffffff878116145b80612056575073ffffffffffffffffffffffffffffffffffffffff8716155b1561207c57600089600181111561206f5761206f6146d8565b1461207c5761207c614878565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260018401602090815260409182902082518084019093525463ffffffff811683526401000000009004811b63ffffffff191690820152845460ff16801561210d575073ffffffffffffffffffffffffffffffffffffffff888116148061210d57508863ffffffff16816000015163ffffffff16145b80156121235750602081015163ffffffff191615155b801561214b5750866020015163ffffffff1916816020015163ffffffff1916148061214b5750855b156122765773ffffffffffffffffffffffffffffffffffffffff881660009081526001858101602052604082209190915585548554919450610100900460ff169085906006906121aa9084906601000000000000900461ffff16614a09565b825461010092830a61ffff818102199092169282160291909117909255895188546020808d01518a54604080517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090961686529590930460ff169184019190915263ffffffff1916828401526601000000000000900490921660608301525173ffffffffffffffffffffffffffffffffffffffff8b16925063ffffffff8c16917fa96a155bd67c927a6c056befbd979b78465e2b2f1276bf7d4e90a31d4f430aa8919081900360800190a35b6000808b600181111561228b5761228b6146d8565b1480156122b3575083806122b3575073ffffffffffffffffffffffffffffffffffffffff8916155b90508080156122cf5750845468010000000000000000900460ff165b80156122e157506122df856138fb565b155b156123b45784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555600b80546001945060009061232a9067ffffffffffffffff16614a24565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507f65d0e78c3625f0956f58610cf0fb157eaf627683258875ef29af2f71d25ac8fd88600001516040516123ab91907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b60405180910390a15b83806123bd5750825b15612605576000808c60018111156123d7576123d76146d8565b036123f25787156123ea5750600361240f565b50600261240f565b60018c6001811115612406576124066146d8565b03610182575060015b600c6040518060c0016040528083600481111561242e5761242e6146d8565b81526020014267ffffffffffffffff168152885468010000000000000000900460ff16151560208083019190915273ffffffffffffffffffffffffffffffffffffffff8e1660408301528c517fffffffffffffffffffffffffffffffff00000000000000000000000000000000166060830152600060809092018290528354600180820186559483529120825160029092020180549293909283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911690836004811115612500576125006146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c9190911760019091015550612696565b8751602080840151818b0151604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000909516855263ffffffff1992831693850193909352169082015273ffffffffffffffffffffffffffffffffffffffff8a16907fbabb0d7099e6ca14a29fad2a2cfb4fda2bd30f97cb3c27e546174bfb4277c1cc9060600160405180910390a25b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612725576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610418565b565b6000611dee8373ffffffffffffffffffffffffffffffffffffffff841661395c565b6000611dee8373ffffffffffffffffffffffffffffffffffffffff8416613a56565b61277481613aa5565b6127aa576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160038054604084015161ffff908116620100000263ffffffff199092169316929092179190911790555b6002541561298e5760028054600091906127f5906001906149d7565b8154811061280557612805614849565b60009182526020808320604080516080810182526002948502909201805473ffffffffffffffffffffffffffffffffffffffff90811680855260019092015480821685870190815260ff740100000000000000000000000000000000000000008304811687870152750100000000000000000000000000000000000000000090920490911660608601529187526005855282872080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000016905590511685526009909252922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690558054919250908061290457612904614a66565b60008281526020902060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019182020180547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560010180547fffffffffffffffffffff000000000000000000000000000000000000000000001690559055506127d9565b60005b815151811015612ac1578151805160029190839081106129b3576129b3614849565b6020908102919091018101518254600181810185556000948552938390208251600290920201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116178155928201519284018054604084015160609094015160ff9081167501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9190951674010000000000000000000000000000000000000000027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169590931694909417939093171617905501612991565b5060048054600090612ad89063ffffffff16614a95565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b82515160ff82161015612c5557600083600001518260ff1681518110612b2457612b24614849565b602090810291909101810151604080516060808201835263ffffffff80891683528385015160ff908116848801908152898216858701908152875173ffffffffffffffffffffffffffffffffffffffff908116600090815260058b528881209751885494519351861665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff948716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009096169190971617939093179190911693909317909455858701519091168352600990955291902080549190920151909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090921691909117600117905550612c4e816149ea565b9050612afc565b5073ffffffffffffffffffffffffffffffffffffffff60005260096020527f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660011790556004805463ffffffff438116640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117909155604051908216907f8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a990612d2f908590614ab8565b60405180910390a26040805160c081018252600480825267ffffffffffffffff421660208301526000928201839052606082018390526080820183905260a08201839052600c80546001808201835591909452825160029094027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701805493949093909284927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921691908490811115612dec57612dec6146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c919091176001909101555050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515611dee565b8151600003612f59576040517f55e9b08b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008316600090815260018201602052604090205460ff1615613007576040517f078f340000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201527fffffffffffffffffffffffffffffffff0000000000000000000000000000000084166024820152604401610418565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008316600090815260018281016020526040822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905560045463ffffffff16905b83518110156136ce57600181101580156130ed575083818151811061309657613096614849565b60200260200101516fffffffffffffffffffffffffffffffff1916846001836130bf91906149d7565b815181106130cf576130cf614849565b60200260200101516fffffffffffffffffffffffffffffffff191610155b15613124576040517f2432d8ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084828151811061313857613138614849565b60200260200101519050600061314e8483611df5565b73ffffffffffffffffffffffffffffffffffffffff8981166000818152600184016020908152604080832081518083019092525463ffffffff811682526401000000009004821b63ffffffff19169181019190915293945091148015906131be5750815163ffffffff8088169116105b806131d25750602082015163ffffffff1916155b15613225575085548254600091610100900460ff169084906006906132069084906601000000000000900461ffff1661493c565b92506101000a81548161ffff021916908361ffff16021790555061322c565b5060208101515b60408051808201825263ffffffff88168152815163ffffffff1984166020828101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008d16828501528351808303850181526060909201909352805190830120909182019063ffffffff1916905273ffffffffffffffffffffffffffffffffffffffff8b166000818152600186016020908152604090912083518285015190921c6401000000000263ffffffff92831617905589549294509091908816907f8137bc8a8d712aaa27bfc6506d5566ac405618bd53f9831b8ca6b6fe5442ee7a9087908d9060ff610100909104166133234290565b6020898101518b54604080517fffffffffffffffffffffffffffffffff000000000000000000000000000000009889168152979096169287019290925260ff9093169385019390935267ffffffffffffffff16606084015263ffffffff191660808301526601000000000000900461ffff1660a082015260c00160405180910390a363ffffffff1981161580156133c85750825468010000000000000000900460ff16155b80156133d857506133d8836138fb565b156134c35782547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000178355600b80546000906134289067ffffffffffffffff16614acb565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508563ffffffff167fcfdbfd8ce9a56b5f7c202c0e102184d24f47ca87121dc165063fc4c290957bde8561347e4290565b604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316835267ffffffffffffffff90911660208301520160405180910390a25b6040805160c081018252600080825267ffffffffffffffff42166020830152855460ff680100000000000000009091041615159282019290925273ffffffffffffffffffffffffffffffffffffffff8c1660608201527fffffffffffffffffffffffffffffffff0000000000000000000000000000000086811660808301528b1660a0820152600c80546001808201835591909352815160029093027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701805492939092909183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016908360048111156135c0576135c06146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c9190911760019182015594909401935061306f92505050565b505050505050565b600060108260ff16106136eb576136eb614878565b50600160ff82161b821678ffffffffffffffffffffffffffffffffffffffffffffffffff16151592915050565b600060108260ff161061372d5761372d614878565b50600160ff919091161b1790565b3373ffffffffffffffffffffffffffffffffffffffff8216036137ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610418565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006201000078ffffffffffffffffffffffffffffffffffffffffffffffffff83161061385f5761385f614878565b78ffffffffffffffffffffffffffffffffffffffffffffffffff8216156105ac5761388b600183614ae8565b90911690613898816149ea565b905061385f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156138ef57602002820191906000526020600020905b8154815260200190600101908083116138db575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff600090815260018201602090815260408220546401000000009004901b63ffffffff19161515806105a65750505461ffff64010000000082048116660100000000000090920416101590565b60008181526001830160205260408120548015613a455760006139806001836149d7565b8554909150600090613994906001906149d7565b90508181146139f95760008660000182815481106139b4576139b4614849565b90600052602060002001549050808760000184815481106139d7576139d7614849565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613a0a57613a0a614a66565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105a6565b60009150506105a6565b5092915050565b6000818152600183016020526040812054613a9d575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105a6565b5060006105a6565b8051516000901580613ab957508151516010105b80613aca5750602082015161ffff16155b80613adb5750604082015161ffff16155b15613ae857506000919050565b60008060008460000151516002613aff9190614b1a565b67ffffffffffffffff811115613b1757613b17613e52565b604051908082528060200260200182016040528015613b40578160200160208202803683370190505b50905060005b855151811015613d1157600086600001518281518110613b6857613b68614849565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161480613bc95750602081015173ffffffffffffffffffffffffffffffffffffffff16155b80613bec5750602081015173ffffffffffffffffffffffffffffffffffffffff16155b80613c115750602081015173ffffffffffffffffffffffffffffffffffffffff908116145b80613c315750604081015160ff16158015613c315750606081015160ff16155b15613c43575060009695505050505050565b805183613c51846002614b1a565b613c5c9060006149c4565b81518110613c6c57613c6c614849565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015281015183613c9f846002614b1a565b613caa9060016149c4565b81518110613cba57613cba614849565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526040810151613cf19060ff16866149c4565b9450806060015160ff1684613d0691906149c4565b935050600101613b46565b5060005b8151811015613dc3576000828281518110613d3257613d32614849565b602002602001015190506000826001613d4b91906149c4565b90505b8351811015613db957838181518110613d6957613d69614849565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613db157506000979650505050505050565b600101613d4e565b5050600101613d15565b50846020015161ffff168310158015613de45750846040015161ffff168210155b95945050505050565b60008151808452602080850194506020840160005b83811015613e3457815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e02565b509495945050505050565b602081526000611dee6020830184613ded565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613ea457613ea4613e52565b60405290565b6040516060810167ffffffffffffffff81118282101715613ea457613ea4613e52565b6040516080810167ffffffffffffffff81118282101715613ea457613ea4613e52565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f3757613f37613e52565b604052919050565b600067ffffffffffffffff821115613f5957613f59613e52565b5060051b60200190565b80357fffffffffffffffffffffffffffffffff00000000000000000000000000000000811681146105ac57600080fd5b600060408284031215613fa557600080fd5b613fad613e81565b9050613fb882613f63565b8152602082013563ffffffff1981168114613fd257600080fd5b602082015292915050565b60006020808385031215613ff057600080fd5b823567ffffffffffffffff81111561400757600080fd5b8301601f8101851361401857600080fd5b803561402b61402682613f3f565b613ef0565b8082825260208201915060208360061b85010192508783111561404d57600080fd5b6020840193505b82841015614078576140668885613f93565b82528482019150604084019350614054565b979650505050505050565b60006020808352835180602085015260005b818110156140b157858101830151858201604001528201614095565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561410257600080fd5b611dee82613f63565b803573ffffffffffffffffffffffffffffffffffffffff811681146105ac57600080fd5b600082601f83011261414057600080fd5b8135602061415061402683613f3f565b8083825260208201915060208460051b87010193508684111561417257600080fd5b602086015b84811015614195576141888161410b565b8352918301918301614177565b509695505050505050565b600080604083850312156141b357600080fd5b823567ffffffffffffffff808211156141cb57600080fd5b6141d78683870161412f565b935060208501359150808211156141ed57600080fd5b506141fa8582860161412f565b9150509250929050565b8051606080845281518482018190526000926080916020918201918388019190865b82811015614280578451805173ffffffffffffffffffffffffffffffffffffffff908116865283820151168386015260408082015160ff908116918701919091529088015116878501529381019392850192600101614226565b508781015161ffff81168a83015295505050604086015193506142a9604088018561ffff169052565b9695505050505050565b600063ffffffff808616835280851660208401525060606040830152613de46060830184614204565b803560ff811681146105ac57600080fd5b803561ffff811681146105ac57600080fd5b6000602080838503121561431257600080fd5b823567ffffffffffffffff8082111561432a57600080fd5b8185019150606080838803121561434057600080fd5b614348613eaa565b83358381111561435757600080fd5b84019250601f8301881361436a57600080fd5b823561437861402682613f3f565b81815260079190911b8401860190868101908a83111561439757600080fd5b948701945b82861015614409576080868c0312156143b55760008081fd5b6143bd613ecd565b6143c68761410b565b81526143d389880161410b565b8982015260406143e48189016142dc565b908201526143f38787016142dc565b818701528252608095909501949087019061439c565b83525061441990508486016142ed565b85820152614429604085016142ed565b6040820152979650505050505050565b60006040828403121561444b57600080fd5b50919050565b6000806040838503121561446457600080fd5b61446d83613f63565b915060208084013567ffffffffffffffff81111561448a57600080fd5b8401601f8101861361449b57600080fd5b80356144a961402682613f3f565b81815260059190911b820183019083810190888311156144c857600080fd5b928401925b828410156144ed576144de84613f63565b825292840192908401906144cd565b80955050505050509250929050565b6000602080838503121561450f57600080fd5b823567ffffffffffffffff81111561452657600080fd5b8301601f8101851361453757600080fd5b803561454561402682613f3f565b81815260079190911b8201830190838101908783111561456457600080fd5b928401925b8284101561407857608084890312156145825760008081fd5b61458a613eaa565b6145938561410b565b81526145a189878701613f93565b86820152606085013580151581146145b95760008081fd5b604082015282526080939093019290840190614569565b600080602083850312156145e357600080fd5b823567ffffffffffffffff808211156145fb57600080fd5b818501915085601f83011261460f57600080fd5b81358181111561461e57600080fd5b8660208260061b850101111561463357600080fd5b60209290920196919550909350505050565b6080815260006146586080830187613ded565b82810360208481019190915286518083528782019282019060005b8181101561469657845163ffffffff191683529383019391830191600101614673565b505061ffff96909616604085015250505090151560609091015292915050565b600080604083850312156146c957600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208082528251828201819052600091906040908185019086840185805b838110156147f2578251805160058110614766577f4e487b710000000000000000000000000000000000000000000000000000000084526021600452602484fd5b86528088015167ffffffffffffffff16888701528681015115158787015260608082015173ffffffffffffffffffffffffffffffffffffffff16908701526080808201517fffffffffffffffffffffffffffffffff000000000000000000000000000000009081169188019190915260a091820151169086015260c09094019391860191600101614725565b509298975050505050505050565b60006020828403121561481257600080fd5b611dee8261410b565b60608152600061482e6060830186613ded565b61ffff94909416602083015250901515604090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6000604082840312156148b957600080fd5b6148c1613e81565b6148ca8361410b565b8152602083013560208201528091505092915050565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015190820152604081016105a6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff818116838216019080821115613a4f57613a4f61490d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149885761498861490d565b5060010190565b60008161499e5761499e61490d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b808201808211156105a6576105a661490d565b818103818111156105a6576105a661490d565b600060ff821660ff8103614a0057614a0061490d565b60010192915050565b61ffff828116828216039080821115613a4f57613a4f61490d565b600067ffffffffffffffff821680614a3e57614a3e61490d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600063ffffffff808316818103614aae57614aae61490d565b6001019392505050565b602081526000611dee6020830184614204565b600067ffffffffffffffff808316818103614aae57614aae61490d565b78ffffffffffffffffffffffffffffffffffffffffffffffffff828116828216039080821115613a4f57613a4f61490d565b80820281158282048414176105a6576105a661490d56fea164736f6c6343000818000a", } var ARMContractABI = ARMContractMetaData.ABI @@ -258,11 +271,11 @@ func (_ARMContract *ARMContractCallerSession) GetConfigDetails() (GetConfigDetai return _ARMContract.Contract.GetConfigDetails(&_ARMContract.CallOpts) } -func (_ARMContract *ARMContractCaller) GetCurseProgress(opts *bind.CallOpts) (GetCurseProgress, +func (_ARMContract *ARMContractCaller) GetCurseProgress(opts *bind.CallOpts, subject [16]byte) (GetCurseProgress, error) { var out []interface{} - err := _ARMContract.contract.Call(opts, &out, "getCurseProgress") + err := _ARMContract.contract.Call(opts, &out, "getCurseProgress", subject) outstruct := new(GetCurseProgress) if err != nil { @@ -270,25 +283,112 @@ func (_ARMContract *ARMContractCaller) GetCurseProgress(opts *bind.CallOpts) (Ge } outstruct.CurseVoteAddrs = *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) - outstruct.VoteCounts = *abi.ConvertType(out[1], new([]uint32)).(*[]uint32) - outstruct.CursesHashes = *abi.ConvertType(out[2], new([][32]byte)).(*[][32]byte) - outstruct.AccumulatedWeight = *abi.ConvertType(out[3], new(uint16)).(*uint16) - outstruct.Cursed = *abi.ConvertType(out[4], new(bool)).(*bool) + outstruct.CursesHashes = *abi.ConvertType(out[1], new([][28]byte)).(*[][28]byte) + outstruct.AccumulatedWeight = *abi.ConvertType(out[2], new(uint16)).(*uint16) + outstruct.Cursed = *abi.ConvertType(out[3], new(bool)).(*bool) return *outstruct, err } -func (_ARMContract *ARMContractSession) GetCurseProgress() (GetCurseProgress, +func (_ARMContract *ARMContractSession) GetCurseProgress(subject [16]byte) (GetCurseProgress, error) { - return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts) + return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts, subject) } -func (_ARMContract *ARMContractCallerSession) GetCurseProgress() (GetCurseProgress, +func (_ARMContract *ARMContractCallerSession) GetCurseProgress(subject [16]byte) (GetCurseProgress, error) { - return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts) + return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts, subject) +} + +func (_ARMContract *ARMContractCaller) GetCursedSubjectsCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ARMContract.contract.Call(opts, &out, "getCursedSubjectsCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_ARMContract *ARMContractSession) GetCursedSubjectsCount() (*big.Int, error) { + return _ARMContract.Contract.GetCursedSubjectsCount(&_ARMContract.CallOpts) +} + +func (_ARMContract *ARMContractCallerSession) GetCursedSubjectsCount() (*big.Int, error) { + return _ARMContract.Contract.GetCursedSubjectsCount(&_ARMContract.CallOpts) +} + +func (_ARMContract *ARMContractCaller) GetPermaBlessedCommitStores(opts *bind.CallOpts) ([]common.Address, error) { + var out []interface{} + err := _ARMContract.contract.Call(opts, &out, "getPermaBlessedCommitStores") + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_ARMContract *ARMContractSession) GetPermaBlessedCommitStores() ([]common.Address, error) { + return _ARMContract.Contract.GetPermaBlessedCommitStores(&_ARMContract.CallOpts) +} + +func (_ARMContract *ARMContractCallerSession) GetPermaBlessedCommitStores() ([]common.Address, error) { + return _ARMContract.Contract.GetPermaBlessedCommitStores(&_ARMContract.CallOpts) +} + +func (_ARMContract *ARMContractCaller) GetRecordedCurseRelatedOps(opts *bind.CallOpts, offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) { + var out []interface{} + err := _ARMContract.contract.Call(opts, &out, "getRecordedCurseRelatedOps", offset, limit) + + if err != nil { + return *new([]RMNRecordedCurseRelatedOp), err + } + + out0 := *abi.ConvertType(out[0], new([]RMNRecordedCurseRelatedOp)).(*[]RMNRecordedCurseRelatedOp) + + return out0, err + +} + +func (_ARMContract *ARMContractSession) GetRecordedCurseRelatedOps(offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) { + return _ARMContract.Contract.GetRecordedCurseRelatedOps(&_ARMContract.CallOpts, offset, limit) +} + +func (_ARMContract *ARMContractCallerSession) GetRecordedCurseRelatedOps(offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) { + return _ARMContract.Contract.GetRecordedCurseRelatedOps(&_ARMContract.CallOpts, offset, limit) +} + +func (_ARMContract *ARMContractCaller) GetRecordedCurseRelatedOpsCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _ARMContract.contract.Call(opts, &out, "getRecordedCurseRelatedOpsCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_ARMContract *ARMContractSession) GetRecordedCurseRelatedOpsCount() (*big.Int, error) { + return _ARMContract.Contract.GetRecordedCurseRelatedOpsCount(&_ARMContract.CallOpts) +} + +func (_ARMContract *ARMContractCallerSession) GetRecordedCurseRelatedOpsCount() (*big.Int, error) { + return _ARMContract.Contract.GetRecordedCurseRelatedOpsCount(&_ARMContract.CallOpts) } func (_ARMContract *ARMContractCaller) IsBlessed(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (bool, error) { @@ -313,9 +413,9 @@ func (_ARMContract *ARMContractCallerSession) IsBlessed(taggedRoot IRMNTaggedRoo return _ARMContract.Contract.IsBlessed(&_ARMContract.CallOpts, taggedRoot) } -func (_ARMContract *ARMContractCaller) IsCursed(opts *bind.CallOpts, arg0 [16]byte) (bool, error) { +func (_ARMContract *ARMContractCaller) IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error) { var out []interface{} - err := _ARMContract.contract.Call(opts, &out, "isCursed", arg0) + err := _ARMContract.contract.Call(opts, &out, "isCursed", subject) if err != nil { return *new(bool), err @@ -327,12 +427,12 @@ func (_ARMContract *ARMContractCaller) IsCursed(opts *bind.CallOpts, arg0 [16]by } -func (_ARMContract *ARMContractSession) IsCursed(arg0 [16]byte) (bool, error) { - return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, arg0) +func (_ARMContract *ARMContractSession) IsCursed(subject [16]byte) (bool, error) { + return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, subject) } -func (_ARMContract *ARMContractCallerSession) IsCursed(arg0 [16]byte) (bool, error) { - return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, arg0) +func (_ARMContract *ARMContractCallerSession) IsCursed(subject [16]byte) (bool, error) { + return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, subject) } func (_ARMContract *ARMContractCaller) IsCursed0(opts *bind.CallOpts) (bool, error) { @@ -413,16 +513,28 @@ func (_ARMContract *ARMContractTransactorSession) AcceptOwnership() (*types.Tran return _ARMContract.Contract.AcceptOwnership(&_ARMContract.TransactOpts) } -func (_ARMContract *ARMContractTransactor) OwnerCurse(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ARMContract.contract.Transact(opts, "ownerCurse") +func (_ARMContract *ARMContractTransactor) OwnerCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.contract.Transact(opts, "ownerCurse", curseId, subjects) +} + +func (_ARMContract *ARMContractSession) OwnerCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts, curseId, subjects) +} + +func (_ARMContract *ARMContractTransactorSession) OwnerCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts, curseId, subjects) +} + +func (_ARMContract *ARMContractTransactor) OwnerRemoveThenAddPermaBlessedCommitStores(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _ARMContract.contract.Transact(opts, "ownerRemoveThenAddPermaBlessedCommitStores", removes, adds) } -func (_ARMContract *ARMContractSession) OwnerCurse() (*types.Transaction, error) { - return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts) +func (_ARMContract *ARMContractSession) OwnerRemoveThenAddPermaBlessedCommitStores(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerRemoveThenAddPermaBlessedCommitStores(&_ARMContract.TransactOpts, removes, adds) } -func (_ARMContract *ARMContractTransactorSession) OwnerCurse() (*types.Transaction, error) { - return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts) +func (_ARMContract *ARMContractTransactorSession) OwnerRemoveThenAddPermaBlessedCommitStores(removes []common.Address, adds []common.Address) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerRemoveThenAddPermaBlessedCommitStores(&_ARMContract.TransactOpts, removes, adds) } func (_ARMContract *ARMContractTransactor) OwnerResetBlessVotes(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) { @@ -437,16 +549,16 @@ func (_ARMContract *ARMContractTransactorSession) OwnerResetBlessVotes(taggedRoo return _ARMContract.Contract.OwnerResetBlessVotes(&_ARMContract.TransactOpts, taggedRoots) } -func (_ARMContract *ARMContractTransactor) OwnerUnvoteToCurse(opts *bind.TransactOpts, unvoteRecords []RMNUnvoteToCurseRecord) (*types.Transaction, error) { - return _ARMContract.contract.Transact(opts, "ownerUnvoteToCurse", unvoteRecords) +func (_ARMContract *ARMContractTransactor) OwnerUnvoteToCurse(opts *bind.TransactOpts, ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.contract.Transact(opts, "ownerUnvoteToCurse", ownerUnvoteToCurseRequests) } -func (_ARMContract *ARMContractSession) OwnerUnvoteToCurse(unvoteRecords []RMNUnvoteToCurseRecord) (*types.Transaction, error) { - return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, unvoteRecords) +func (_ARMContract *ARMContractSession) OwnerUnvoteToCurse(ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, ownerUnvoteToCurseRequests) } -func (_ARMContract *ARMContractTransactorSession) OwnerUnvoteToCurse(unvoteRecords []RMNUnvoteToCurseRecord) (*types.Transaction, error) { - return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, unvoteRecords) +func (_ARMContract *ARMContractTransactorSession) OwnerUnvoteToCurse(ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, ownerUnvoteToCurseRequests) } func (_ARMContract *ARMContractTransactor) SetConfig(opts *bind.TransactOpts, config RMNConfig) (*types.Transaction, error) { @@ -473,16 +585,16 @@ func (_ARMContract *ARMContractTransactorSession) TransferOwnership(to common.Ad return _ARMContract.Contract.TransferOwnership(&_ARMContract.TransactOpts, to) } -func (_ARMContract *ARMContractTransactor) UnvoteToCurse(opts *bind.TransactOpts, curseVoteAddr common.Address, cursesHash [32]byte) (*types.Transaction, error) { - return _ARMContract.contract.Transact(opts, "unvoteToCurse", curseVoteAddr, cursesHash) +func (_ARMContract *ARMContractTransactor) UnvoteToCurse(opts *bind.TransactOpts, unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.contract.Transact(opts, "unvoteToCurse", unvoteToCurseRequests) } -func (_ARMContract *ARMContractSession) UnvoteToCurse(curseVoteAddr common.Address, cursesHash [32]byte) (*types.Transaction, error) { - return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, curseVoteAddr, cursesHash) +func (_ARMContract *ARMContractSession) UnvoteToCurse(unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, unvoteToCurseRequests) } -func (_ARMContract *ARMContractTransactorSession) UnvoteToCurse(curseVoteAddr common.Address, cursesHash [32]byte) (*types.Transaction, error) { - return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, curseVoteAddr, cursesHash) +func (_ARMContract *ARMContractTransactorSession) UnvoteToCurse(unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) { + return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, unvoteToCurseRequests) } func (_ARMContract *ARMContractTransactor) VoteToBless(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) { @@ -497,16 +609,16 @@ func (_ARMContract *ARMContractTransactorSession) VoteToBless(taggedRoots []IRMN return _ARMContract.Contract.VoteToBless(&_ARMContract.TransactOpts, taggedRoots) } -func (_ARMContract *ARMContractTransactor) VoteToCurse(opts *bind.TransactOpts, curseId [32]byte) (*types.Transaction, error) { - return _ARMContract.contract.Transact(opts, "voteToCurse", curseId) +func (_ARMContract *ARMContractTransactor) VoteToCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.contract.Transact(opts, "voteToCurse", curseId, subjects) } -func (_ARMContract *ARMContractSession) VoteToCurse(curseId [32]byte) (*types.Transaction, error) { - return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId) +func (_ARMContract *ARMContractSession) VoteToCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId, subjects) } -func (_ARMContract *ARMContractTransactorSession) VoteToCurse(curseId [32]byte) (*types.Transaction, error) { - return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId) +func (_ARMContract *ARMContractTransactorSession) VoteToCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) { + return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId, subjects) } type ARMContractAlreadyBlessedIterator struct { @@ -911,8 +1023,8 @@ func (_ARMContract *ARMContractFilterer) ParseConfigSet(log types.Log) (*ARMCont return event, nil } -type ARMContractCursedIterator struct { - Event *ARMContractCursed +type ARMContractCurseLiftedIterator struct { + Event *ARMContractCurseLifted contract *bind.BoundContract event string @@ -923,7 +1035,7 @@ type ARMContractCursedIterator struct { fail error } -func (it *ARMContractCursedIterator) Next() bool { +func (it *ARMContractCurseLiftedIterator) Next() bool { if it.fail != nil { return false @@ -932,7 +1044,7 @@ func (it *ARMContractCursedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(ARMContractCursed) + it.Event = new(ARMContractCurseLifted) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -947,7 +1059,7 @@ func (it *ARMContractCursedIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(ARMContractCursed) + it.Event = new(ARMContractCurseLifted) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -962,43 +1074,32 @@ func (it *ARMContractCursedIterator) Next() bool { } } -func (it *ARMContractCursedIterator) Error() error { +func (it *ARMContractCurseLiftedIterator) Error() error { return it.fail } -func (it *ARMContractCursedIterator) Close() error { +func (it *ARMContractCurseLiftedIterator) Close() error { it.sub.Unsubscribe() return nil } -type ARMContractCursed struct { - ConfigVersion uint32 - Timestamp *big.Int - Raw types.Log +type ARMContractCurseLifted struct { + Subject [16]byte + Raw types.Log } -func (_ARMContract *ARMContractFilterer) FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error) { - - var configVersionRule []interface{} - for _, configVersionItem := range configVersion { - configVersionRule = append(configVersionRule, configVersionItem) - } +func (_ARMContract *ARMContractFilterer) FilterCurseLifted(opts *bind.FilterOpts) (*ARMContractCurseLiftedIterator, error) { - logs, sub, err := _ARMContract.contract.FilterLogs(opts, "Cursed", configVersionRule) + logs, sub, err := _ARMContract.contract.FilterLogs(opts, "CurseLifted") if err != nil { return nil, err } - return &ARMContractCursedIterator{contract: _ARMContract.contract, event: "Cursed", logs: logs, sub: sub}, nil + return &ARMContractCurseLiftedIterator{contract: _ARMContract.contract, event: "CurseLifted", logs: logs, sub: sub}, nil } -func (_ARMContract *ARMContractFilterer) WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error) { - - var configVersionRule []interface{} - for _, configVersionItem := range configVersion { - configVersionRule = append(configVersionRule, configVersionItem) - } +func (_ARMContract *ARMContractFilterer) WatchCurseLifted(opts *bind.WatchOpts, sink chan<- *ARMContractCurseLifted) (event.Subscription, error) { - logs, sub, err := _ARMContract.contract.WatchLogs(opts, "Cursed", configVersionRule) + logs, sub, err := _ARMContract.contract.WatchLogs(opts, "CurseLifted") if err != nil { return nil, err } @@ -1008,8 +1109,8 @@ func (_ARMContract *ARMContractFilterer) WatchCursed(opts *bind.WatchOpts, sink select { case log := <-logs: - event := new(ARMContractCursed) - if err := _ARMContract.contract.UnpackLog(event, "Cursed", log); err != nil { + event := new(ARMContractCurseLifted) + if err := _ARMContract.contract.UnpackLog(event, "CurseLifted", log); err != nil { return err } event.Raw = log @@ -1030,17 +1131,17 @@ func (_ARMContract *ARMContractFilterer) WatchCursed(opts *bind.WatchOpts, sink }), nil } -func (_ARMContract *ARMContractFilterer) ParseCursed(log types.Log) (*ARMContractCursed, error) { - event := new(ARMContractCursed) - if err := _ARMContract.contract.UnpackLog(event, "Cursed", log); err != nil { +func (_ARMContract *ARMContractFilterer) ParseCurseLifted(log types.Log) (*ARMContractCurseLifted, error) { + event := new(ARMContractCurseLifted) + if err := _ARMContract.contract.UnpackLog(event, "CurseLifted", log); err != nil { return nil, err } event.Raw = log return event, nil } -type ARMContractOwnerCursedIterator struct { - Event *ARMContractOwnerCursed +type ARMContractCursedIterator struct { + Event *ARMContractCursed contract *bind.BoundContract event string @@ -1051,7 +1152,7 @@ type ARMContractOwnerCursedIterator struct { fail error } -func (it *ARMContractOwnerCursedIterator) Next() bool { +func (it *ARMContractCursedIterator) Next() bool { if it.fail != nil { return false @@ -1060,7 +1161,7 @@ func (it *ARMContractOwnerCursedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(ARMContractOwnerCursed) + it.Event = new(ARMContractCursed) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1075,7 +1176,7 @@ func (it *ARMContractOwnerCursedIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(ARMContractOwnerCursed) + it.Event = new(ARMContractCursed) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1090,32 +1191,44 @@ func (it *ARMContractOwnerCursedIterator) Next() bool { } } -func (it *ARMContractOwnerCursedIterator) Error() error { +func (it *ARMContractCursedIterator) Error() error { return it.fail } -func (it *ARMContractOwnerCursedIterator) Close() error { +func (it *ARMContractCursedIterator) Close() error { it.sub.Unsubscribe() return nil } -type ARMContractOwnerCursed struct { - Timestamp *big.Int - Raw types.Log +type ARMContractCursed struct { + ConfigVersion uint32 + Subject [16]byte + BlockTimestamp uint64 + Raw types.Log } -func (_ARMContract *ARMContractFilterer) FilterOwnerCursed(opts *bind.FilterOpts) (*ARMContractOwnerCursedIterator, error) { +func (_ARMContract *ARMContractFilterer) FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error) { + + var configVersionRule []interface{} + for _, configVersionItem := range configVersion { + configVersionRule = append(configVersionRule, configVersionItem) + } - logs, sub, err := _ARMContract.contract.FilterLogs(opts, "OwnerCursed") + logs, sub, err := _ARMContract.contract.FilterLogs(opts, "Cursed", configVersionRule) if err != nil { return nil, err } - return &ARMContractOwnerCursedIterator{contract: _ARMContract.contract, event: "OwnerCursed", logs: logs, sub: sub}, nil + return &ARMContractCursedIterator{contract: _ARMContract.contract, event: "Cursed", logs: logs, sub: sub}, nil } -func (_ARMContract *ARMContractFilterer) WatchOwnerCursed(opts *bind.WatchOpts, sink chan<- *ARMContractOwnerCursed) (event.Subscription, error) { +func (_ARMContract *ARMContractFilterer) WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error) { - logs, sub, err := _ARMContract.contract.WatchLogs(opts, "OwnerCursed") + var configVersionRule []interface{} + for _, configVersionItem := range configVersion { + configVersionRule = append(configVersionRule, configVersionItem) + } + + logs, sub, err := _ARMContract.contract.WatchLogs(opts, "Cursed", configVersionRule) if err != nil { return nil, err } @@ -1125,8 +1238,8 @@ func (_ARMContract *ARMContractFilterer) WatchOwnerCursed(opts *bind.WatchOpts, select { case log := <-logs: - event := new(ARMContractOwnerCursed) - if err := _ARMContract.contract.UnpackLog(event, "OwnerCursed", log); err != nil { + event := new(ARMContractCursed) + if err := _ARMContract.contract.UnpackLog(event, "Cursed", log); err != nil { return err } event.Raw = log @@ -1147,9 +1260,9 @@ func (_ARMContract *ARMContractFilterer) WatchOwnerCursed(opts *bind.WatchOpts, }), nil } -func (_ARMContract *ARMContractFilterer) ParseOwnerCursed(log types.Log) (*ARMContractOwnerCursed, error) { - event := new(ARMContractOwnerCursed) - if err := _ARMContract.contract.UnpackLog(event, "OwnerCursed", log); err != nil { +func (_ARMContract *ARMContractFilterer) ParseCursed(log types.Log) (*ARMContractCursed, error) { + event := new(ARMContractCursed) + if err := _ARMContract.contract.UnpackLog(event, "Cursed", log); err != nil { return nil, err } event.Raw = log @@ -1428,8 +1541,8 @@ func (_ARMContract *ARMContractFilterer) ParseOwnershipTransferred(log types.Log return event, nil } -type ARMContractRecoveredFromCurseIterator struct { - Event *ARMContractRecoveredFromCurse +type ARMContractPermaBlessedCommitStoreAddedIterator struct { + Event *ARMContractPermaBlessedCommitStoreAdded contract *bind.BoundContract event string @@ -1440,7 +1553,7 @@ type ARMContractRecoveredFromCurseIterator struct { fail error } -func (it *ARMContractRecoveredFromCurseIterator) Next() bool { +func (it *ARMContractPermaBlessedCommitStoreAddedIterator) Next() bool { if it.fail != nil { return false @@ -1449,7 +1562,7 @@ func (it *ARMContractRecoveredFromCurseIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(ARMContractRecoveredFromCurse) + it.Event = new(ARMContractPermaBlessedCommitStoreAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1464,7 +1577,7 @@ func (it *ARMContractRecoveredFromCurseIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(ARMContractRecoveredFromCurse) + it.Event = new(ARMContractPermaBlessedCommitStoreAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1479,31 +1592,32 @@ func (it *ARMContractRecoveredFromCurseIterator) Next() bool { } } -func (it *ARMContractRecoveredFromCurseIterator) Error() error { +func (it *ARMContractPermaBlessedCommitStoreAddedIterator) Error() error { return it.fail } -func (it *ARMContractRecoveredFromCurseIterator) Close() error { +func (it *ARMContractPermaBlessedCommitStoreAddedIterator) Close() error { it.sub.Unsubscribe() return nil } -type ARMContractRecoveredFromCurse struct { - Raw types.Log +type ARMContractPermaBlessedCommitStoreAdded struct { + CommitStore common.Address + Raw types.Log } -func (_ARMContract *ARMContractFilterer) FilterRecoveredFromCurse(opts *bind.FilterOpts) (*ARMContractRecoveredFromCurseIterator, error) { +func (_ARMContract *ARMContractFilterer) FilterPermaBlessedCommitStoreAdded(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreAddedIterator, error) { - logs, sub, err := _ARMContract.contract.FilterLogs(opts, "RecoveredFromCurse") + logs, sub, err := _ARMContract.contract.FilterLogs(opts, "PermaBlessedCommitStoreAdded") if err != nil { return nil, err } - return &ARMContractRecoveredFromCurseIterator{contract: _ARMContract.contract, event: "RecoveredFromCurse", logs: logs, sub: sub}, nil + return &ARMContractPermaBlessedCommitStoreAddedIterator{contract: _ARMContract.contract, event: "PermaBlessedCommitStoreAdded", logs: logs, sub: sub}, nil } -func (_ARMContract *ARMContractFilterer) WatchRecoveredFromCurse(opts *bind.WatchOpts, sink chan<- *ARMContractRecoveredFromCurse) (event.Subscription, error) { +func (_ARMContract *ARMContractFilterer) WatchPermaBlessedCommitStoreAdded(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreAdded) (event.Subscription, error) { - logs, sub, err := _ARMContract.contract.WatchLogs(opts, "RecoveredFromCurse") + logs, sub, err := _ARMContract.contract.WatchLogs(opts, "PermaBlessedCommitStoreAdded") if err != nil { return nil, err } @@ -1513,8 +1627,8 @@ func (_ARMContract *ARMContractFilterer) WatchRecoveredFromCurse(opts *bind.Watc select { case log := <-logs: - event := new(ARMContractRecoveredFromCurse) - if err := _ARMContract.contract.UnpackLog(event, "RecoveredFromCurse", log); err != nil { + event := new(ARMContractPermaBlessedCommitStoreAdded) + if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreAdded", log); err != nil { return err } event.Raw = log @@ -1535,17 +1649,17 @@ func (_ARMContract *ARMContractFilterer) WatchRecoveredFromCurse(opts *bind.Watc }), nil } -func (_ARMContract *ARMContractFilterer) ParseRecoveredFromCurse(log types.Log) (*ARMContractRecoveredFromCurse, error) { - event := new(ARMContractRecoveredFromCurse) - if err := _ARMContract.contract.UnpackLog(event, "RecoveredFromCurse", log); err != nil { +func (_ARMContract *ARMContractFilterer) ParsePermaBlessedCommitStoreAdded(log types.Log) (*ARMContractPermaBlessedCommitStoreAdded, error) { + event := new(ARMContractPermaBlessedCommitStoreAdded) + if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreAdded", log); err != nil { return nil, err } event.Raw = log return event, nil } -type ARMContractReusedVotesToCurseIterator struct { - Event *ARMContractReusedVotesToCurse +type ARMContractPermaBlessedCommitStoreRemovedIterator struct { + Event *ARMContractPermaBlessedCommitStoreRemoved contract *bind.BoundContract event string @@ -1556,7 +1670,7 @@ type ARMContractReusedVotesToCurseIterator struct { fail error } -func (it *ARMContractReusedVotesToCurseIterator) Next() bool { +func (it *ARMContractPermaBlessedCommitStoreRemovedIterator) Next() bool { if it.fail != nil { return false @@ -1565,7 +1679,7 @@ func (it *ARMContractReusedVotesToCurseIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(ARMContractReusedVotesToCurse) + it.Event = new(ARMContractPermaBlessedCommitStoreRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1580,7 +1694,7 @@ func (it *ARMContractReusedVotesToCurseIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(ARMContractReusedVotesToCurse) + it.Event = new(ARMContractPermaBlessedCommitStoreRemoved) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -1595,55 +1709,32 @@ func (it *ARMContractReusedVotesToCurseIterator) Next() bool { } } -func (it *ARMContractReusedVotesToCurseIterator) Error() error { +func (it *ARMContractPermaBlessedCommitStoreRemovedIterator) Error() error { return it.fail } -func (it *ARMContractReusedVotesToCurseIterator) Close() error { +func (it *ARMContractPermaBlessedCommitStoreRemovedIterator) Close() error { it.sub.Unsubscribe() return nil } -type ARMContractReusedVotesToCurse struct { - ConfigVersion uint32 - Voter common.Address - Weight uint8 - VoteCount uint32 - CursesHash [32]byte - AccumulatedWeight uint16 - Raw types.Log +type ARMContractPermaBlessedCommitStoreRemoved struct { + CommitStore common.Address + Raw types.Log } -func (_ARMContract *ARMContractFilterer) FilterReusedVotesToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractReusedVotesToCurseIterator, error) { +func (_ARMContract *ARMContractFilterer) FilterPermaBlessedCommitStoreRemoved(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreRemovedIterator, error) { - var configVersionRule []interface{} - for _, configVersionItem := range configVersion { - configVersionRule = append(configVersionRule, configVersionItem) - } - var voterRule []interface{} - for _, voterItem := range voter { - voterRule = append(voterRule, voterItem) - } - - logs, sub, err := _ARMContract.contract.FilterLogs(opts, "ReusedVotesToCurse", configVersionRule, voterRule) + logs, sub, err := _ARMContract.contract.FilterLogs(opts, "PermaBlessedCommitStoreRemoved") if err != nil { return nil, err } - return &ARMContractReusedVotesToCurseIterator{contract: _ARMContract.contract, event: "ReusedVotesToCurse", logs: logs, sub: sub}, nil + return &ARMContractPermaBlessedCommitStoreRemovedIterator{contract: _ARMContract.contract, event: "PermaBlessedCommitStoreRemoved", logs: logs, sub: sub}, nil } -func (_ARMContract *ARMContractFilterer) WatchReusedVotesToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractReusedVotesToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error) { - - var configVersionRule []interface{} - for _, configVersionItem := range configVersion { - configVersionRule = append(configVersionRule, configVersionItem) - } - var voterRule []interface{} - for _, voterItem := range voter { - voterRule = append(voterRule, voterItem) - } +func (_ARMContract *ARMContractFilterer) WatchPermaBlessedCommitStoreRemoved(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreRemoved) (event.Subscription, error) { - logs, sub, err := _ARMContract.contract.WatchLogs(opts, "ReusedVotesToCurse", configVersionRule, voterRule) + logs, sub, err := _ARMContract.contract.WatchLogs(opts, "PermaBlessedCommitStoreRemoved") if err != nil { return nil, err } @@ -1653,8 +1744,8 @@ func (_ARMContract *ARMContractFilterer) WatchReusedVotesToCurse(opts *bind.Watc select { case log := <-logs: - event := new(ARMContractReusedVotesToCurse) - if err := _ARMContract.contract.UnpackLog(event, "ReusedVotesToCurse", log); err != nil { + event := new(ARMContractPermaBlessedCommitStoreRemoved) + if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreRemoved", log); err != nil { return err } event.Raw = log @@ -1675,9 +1766,9 @@ func (_ARMContract *ARMContractFilterer) WatchReusedVotesToCurse(opts *bind.Watc }), nil } -func (_ARMContract *ARMContractFilterer) ParseReusedVotesToCurse(log types.Log) (*ARMContractReusedVotesToCurse, error) { - event := new(ARMContractReusedVotesToCurse) - if err := _ARMContract.contract.UnpackLog(event, "ReusedVotesToCurse", log); err != nil { +func (_ARMContract *ARMContractFilterer) ParsePermaBlessedCommitStoreRemoved(log types.Log) (*ARMContractPermaBlessedCommitStoreRemoved, error) { + event := new(ARMContractPermaBlessedCommitStoreRemoved) + if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreRemoved", log); err != nil { return nil, err } event.Raw = log @@ -1745,10 +1836,11 @@ func (it *ARMContractSkippedUnvoteToCurseIterator) Close() error { } type ARMContractSkippedUnvoteToCurse struct { - Voter common.Address - ExpectedCursesHash [32]byte - ActualCursesHash [32]byte - Raw types.Log + Voter common.Address + Subject [16]byte + OnchainCursesHash [28]byte + CursesHash [28]byte + Raw types.Log } func (_ARMContract *ARMContractFilterer) FilterSkippedUnvoteToCurse(opts *bind.FilterOpts, voter []common.Address) (*ARMContractSkippedUnvoteToCurseIterator, error) { @@ -2132,12 +2224,13 @@ func (it *ARMContractUnvotedToCurseIterator) Close() error { } type ARMContractUnvotedToCurse struct { - ConfigVersion uint32 - Voter common.Address - Weight uint8 - VoteCount uint32 - CursesHash [32]byte - Raw types.Log + ConfigVersion uint32 + Voter common.Address + Subject [16]byte + Weight uint8 + CursesHash [28]byte + RemainingAccumulatedWeight uint16 + Raw types.Log } func (_ARMContract *ARMContractFilterer) FilterUnvotedToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractUnvotedToCurseIterator, error) { @@ -2411,10 +2504,11 @@ func (it *ARMContractVotedToCurseIterator) Close() error { type ARMContractVotedToCurse struct { ConfigVersion uint32 Voter common.Address + Subject [16]byte + CurseId [16]byte Weight uint8 - VoteCount uint32 - CurseId [32]byte - CursesHash [32]byte + BlockTimestamp uint64 + CursesHash [28]byte AccumulatedWeight uint16 Raw types.Log } @@ -2501,8 +2595,7 @@ type GetConfigDetails struct { } type GetCurseProgress struct { CurseVoteAddrs []common.Address - VoteCounts []uint32 - CursesHashes [][32]byte + CursesHashes [][28]byte AccumulatedWeight uint16 Cursed bool } @@ -2515,18 +2608,18 @@ func (_ARMContract *ARMContract) ParseLog(log types.Log) (generated.AbigenLog, e return _ARMContract.ParseAlreadyVotedToBless(log) case _ARMContract.abi.Events["ConfigSet"].ID: return _ARMContract.ParseConfigSet(log) + case _ARMContract.abi.Events["CurseLifted"].ID: + return _ARMContract.ParseCurseLifted(log) case _ARMContract.abi.Events["Cursed"].ID: return _ARMContract.ParseCursed(log) - case _ARMContract.abi.Events["OwnerCursed"].ID: - return _ARMContract.ParseOwnerCursed(log) case _ARMContract.abi.Events["OwnershipTransferRequested"].ID: return _ARMContract.ParseOwnershipTransferRequested(log) case _ARMContract.abi.Events["OwnershipTransferred"].ID: return _ARMContract.ParseOwnershipTransferred(log) - case _ARMContract.abi.Events["RecoveredFromCurse"].ID: - return _ARMContract.ParseRecoveredFromCurse(log) - case _ARMContract.abi.Events["ReusedVotesToCurse"].ID: - return _ARMContract.ParseReusedVotesToCurse(log) + case _ARMContract.abi.Events["PermaBlessedCommitStoreAdded"].ID: + return _ARMContract.ParsePermaBlessedCommitStoreAdded(log) + case _ARMContract.abi.Events["PermaBlessedCommitStoreRemoved"].ID: + return _ARMContract.ParsePermaBlessedCommitStoreRemoved(log) case _ARMContract.abi.Events["SkippedUnvoteToCurse"].ID: return _ARMContract.ParseSkippedUnvoteToCurse(log) case _ARMContract.abi.Events["TaggedRootBlessVotesReset"].ID: @@ -2554,15 +2647,15 @@ func (ARMContractAlreadyVotedToBless) Topic() common.Hash { } func (ARMContractConfigSet) Topic() common.Hash { - return common.HexToHash("0x7cf8e698b191db138396ab0eae2ad5b3fe353fd014fd5956b034b86f2d605cfd") + return common.HexToHash("0x8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a9") } -func (ARMContractCursed) Topic() common.Hash { - return common.HexToHash("0x6ec7e144a45fa03ed986874794df08b5b6bbbb27ed6454b4e6eaa74248b5e333") +func (ARMContractCurseLifted) Topic() common.Hash { + return common.HexToHash("0x65d0e78c3625f0956f58610cf0fb157eaf627683258875ef29af2f71d25ac8fd") } -func (ARMContractOwnerCursed) Topic() common.Hash { - return common.HexToHash("0x367ba81ba03ea9fa7ee089ecfb43b1c35e0935bc87a472abf615b7580dc16b79") +func (ARMContractCursed) Topic() common.Hash { + return common.HexToHash("0xcfdbfd8ce9a56b5f7c202c0e102184d24f47ca87121dc165063fc4c290957bde") } func (ARMContractOwnershipTransferRequested) Topic() common.Hash { @@ -2573,16 +2666,16 @@ func (ARMContractOwnershipTransferred) Topic() common.Hash { return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") } -func (ARMContractRecoveredFromCurse) Topic() common.Hash { - return common.HexToHash("0x08c773aaf7568c6b9110dcdfc13c27177410582ee30e157d1aa306b49d603eb7") +func (ARMContractPermaBlessedCommitStoreAdded) Topic() common.Hash { + return common.HexToHash("0x66b4b4752c65ae8cd2f3a0a48c7dc8b2118c60d5ea15514992eb2ddf56c9cb15") } -func (ARMContractReusedVotesToCurse) Topic() common.Hash { - return common.HexToHash("0xb4a70189a30e3d3b9c77d291f83699633e70ab4427fc3644a955ab4cca077b03") +func (ARMContractPermaBlessedCommitStoreRemoved) Topic() common.Hash { + return common.HexToHash("0xdca892154bbc36d0c05ccd01b3d0411875cb1b841fcdeebb384e5d0d6eb06b44") } func (ARMContractSkippedUnvoteToCurse) Topic() common.Hash { - return common.HexToHash("0xf4e3b20447f3f83360469333a2578825ae355d192dd6f59c6516d832fa425a53") + return common.HexToHash("0xbabb0d7099e6ca14a29fad2a2cfb4fda2bd30f97cb3c27e546174bfb4277c1cc") } func (ARMContractTaggedRootBlessVotesReset) Topic() common.Hash { @@ -2594,7 +2687,7 @@ func (ARMContractTaggedRootBlessed) Topic() common.Hash { } func (ARMContractUnvotedToCurse) Topic() common.Hash { - return common.HexToHash("0x56c9f1d1001236f66c1e5d598905029b4093031f31aead3449a53d832eade225") + return common.HexToHash("0xa96a155bd67c927a6c056befbd979b78465e2b2f1276bf7d4e90a31d4f430aa8") } func (ARMContractVotedToBless) Topic() common.Hash { @@ -2602,7 +2695,7 @@ func (ARMContractVotedToBless) Topic() common.Hash { } func (ARMContractVotedToCurse) Topic() common.Hash { - return common.HexToHash("0x8e5ceca76dae647f687fccbe8d42a3796e68330812669bd5003b938dacb1b6dd") + return common.HexToHash("0x8137bc8a8d712aaa27bfc6506d5566ac405618bd53f9831b8ca6b6fe5442ee7a") } func (_ARMContract *ARMContract) Address() common.Address { @@ -2618,13 +2711,21 @@ type ARMContractInterface interface { error) - GetCurseProgress(opts *bind.CallOpts) (GetCurseProgress, + GetCurseProgress(opts *bind.CallOpts, subject [16]byte) (GetCurseProgress, error) + GetCursedSubjectsCount(opts *bind.CallOpts) (*big.Int, error) + + GetPermaBlessedCommitStores(opts *bind.CallOpts) ([]common.Address, error) + + GetRecordedCurseRelatedOps(opts *bind.CallOpts, offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) + + GetRecordedCurseRelatedOpsCount(opts *bind.CallOpts) (*big.Int, error) + IsBlessed(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (bool, error) - IsCursed(opts *bind.CallOpts, arg0 [16]byte) (bool, error) + IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error) IsCursed0(opts *bind.CallOpts) (bool, error) @@ -2634,21 +2735,23 @@ type ARMContractInterface interface { AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - OwnerCurse(opts *bind.TransactOpts) (*types.Transaction, error) + OwnerCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) + + OwnerRemoveThenAddPermaBlessedCommitStores(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) OwnerResetBlessVotes(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) - OwnerUnvoteToCurse(opts *bind.TransactOpts, unvoteRecords []RMNUnvoteToCurseRecord) (*types.Transaction, error) + OwnerUnvoteToCurse(opts *bind.TransactOpts, ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) SetConfig(opts *bind.TransactOpts, config RMNConfig) (*types.Transaction, error) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) - UnvoteToCurse(opts *bind.TransactOpts, curseVoteAddr common.Address, cursesHash [32]byte) (*types.Transaction, error) + UnvoteToCurse(opts *bind.TransactOpts, unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) VoteToBless(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) - VoteToCurse(opts *bind.TransactOpts, curseId [32]byte) (*types.Transaction, error) + VoteToCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) FilterAlreadyBlessed(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractAlreadyBlessedIterator, error) @@ -2668,17 +2771,17 @@ type ARMContractInterface interface { ParseConfigSet(log types.Log) (*ARMContractConfigSet, error) - FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error) + FilterCurseLifted(opts *bind.FilterOpts) (*ARMContractCurseLiftedIterator, error) - WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error) + WatchCurseLifted(opts *bind.WatchOpts, sink chan<- *ARMContractCurseLifted) (event.Subscription, error) - ParseCursed(log types.Log) (*ARMContractCursed, error) + ParseCurseLifted(log types.Log) (*ARMContractCurseLifted, error) - FilterOwnerCursed(opts *bind.FilterOpts) (*ARMContractOwnerCursedIterator, error) + FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error) - WatchOwnerCursed(opts *bind.WatchOpts, sink chan<- *ARMContractOwnerCursed) (event.Subscription, error) + WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error) - ParseOwnerCursed(log types.Log) (*ARMContractOwnerCursed, error) + ParseCursed(log types.Log) (*ARMContractCursed, error) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMContractOwnershipTransferRequestedIterator, error) @@ -2692,17 +2795,17 @@ type ARMContractInterface interface { ParseOwnershipTransferred(log types.Log) (*ARMContractOwnershipTransferred, error) - FilterRecoveredFromCurse(opts *bind.FilterOpts) (*ARMContractRecoveredFromCurseIterator, error) + FilterPermaBlessedCommitStoreAdded(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreAddedIterator, error) - WatchRecoveredFromCurse(opts *bind.WatchOpts, sink chan<- *ARMContractRecoveredFromCurse) (event.Subscription, error) + WatchPermaBlessedCommitStoreAdded(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreAdded) (event.Subscription, error) - ParseRecoveredFromCurse(log types.Log) (*ARMContractRecoveredFromCurse, error) + ParsePermaBlessedCommitStoreAdded(log types.Log) (*ARMContractPermaBlessedCommitStoreAdded, error) - FilterReusedVotesToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractReusedVotesToCurseIterator, error) + FilterPermaBlessedCommitStoreRemoved(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreRemovedIterator, error) - WatchReusedVotesToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractReusedVotesToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error) + WatchPermaBlessedCommitStoreRemoved(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreRemoved) (event.Subscription, error) - ParseReusedVotesToCurse(log types.Log) (*ARMContractReusedVotesToCurse, error) + ParsePermaBlessedCommitStoreRemoved(log types.Log) (*ARMContractPermaBlessedCommitStoreRemoved, error) FilterSkippedUnvoteToCurse(opts *bind.FilterOpts, voter []common.Address) (*ARMContractSkippedUnvoteToCurseIterator, error) diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 8743b9850a..8b5f3055ff 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,5 +1,5 @@ GETH_VERSION: 1.13.8 -arm_contract: ../../../contracts/solc/v0.8.24/RMN/RMN.abi ../../../contracts/solc/v0.8.24/RMN/RMN.bin 16a210d759aa4b6a4a765837277495aa7ba62e3f9497439fbd64c5376cdfd9aa +arm_contract: ../../../contracts/solc/v0.8.24/RMN/RMN.abi ../../../contracts/solc/v0.8.24/RMN/RMN.bin 1a0abacf84def916519013f713b667f106434a091af8b9f441e12cc90aa2cdf8 arm_proxy_contract: ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin b048d8e752e3c41113ebb305c1efa06737ad36b4907b93e627fb0a3113023454 burn_from_mint_token_pool: ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.bin c98d5a536e2735f1e8950a5fab6aaaf7fcbd06bb16361e99bf527f2f0027559b burn_mint_token_pool: ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.bin fee3f82935ce7a26c65e12f19a472a4fccdae62755abdb42d8b0a01f0f06981a @@ -17,7 +17,7 @@ lock_release_token_pool: ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/Lo lock_release_token_pool_and_proxy: ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.bin 8b929fab79d1caeea4c57e08cc523eb8ab45ec5c08f46da866b82c15ba94d9ad maybe_revert_message_receiver: ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin d73956c26232ebcc4a5444429fa99cbefed960e323be9b5a24925885c2e477d5 message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin 595d2e1c5172dd1838c9f56c1da09c9243975b2be98c9174c1fcab6802585e20 -mock_arm_contract: ../../../contracts/solc/v0.8.24/MockRMN/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN/MockRMN.bin e7a3a6c3eda5fb882e16bcc2b4340f78523acb67907bcdcaf3c8ffc51488688e +mock_arm_contract: ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.bin e7a3a6c3eda5fb882e16bcc2b4340f78523acb67907bcdcaf3c8ffc51488688e mock_usdc_token_messenger: ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.bin e0cf17a38b438239fc6294ddca88f86b6c39e4542aefd9815b2d92987191b8bd mock_usdc_token_transmitter: ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.bin 33bdad70822e889de7c720ed20085cf9cd3f8eba8b68f26bd6535197749595fe mock_v3_aggregator_contract: ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.abi ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.bin 518e19efa2ff52b0fefd8e597b05765317ee7638189bfe34ca43de2f6599faf4 diff --git a/core/gethwrappers/ccip/go_generate.go b/core/gethwrappers/ccip/go_generate.go index 4b717452c5..864c73d785 100644 --- a/core/gethwrappers/ccip/go_generate.go +++ b/core/gethwrappers/ccip/go_generate.go @@ -13,7 +13,7 @@ package ccip //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.abi ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.bin TokenPool token_pool //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/RMN/RMN.abi ../../../contracts/solc/v0.8.24/RMN/RMN.bin ARMContract arm_contract //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin ARMProxyContract arm_proxy_contract -//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockRMN/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN/MockRMN.bin MockARMContract mock_arm_contract +//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.bin MockARMContract mock_arm_contract //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.abi ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.bin TokenAdminRegistry token_admin_registry //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.abi ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.bin RegistryModuleOwnerCustom registry_module_owner_custom //go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.bin MockE2EUSDCTokenMessenger mock_usdc_token_messenger