diff --git a/test/invariants/FuzzTest.t.sol b/test/invariants/FuzzTest.t.sol index 210d807..71186d1 100644 --- a/test/invariants/FuzzTest.t.sol +++ b/test/invariants/FuzzTest.t.sol @@ -73,7 +73,4 @@ contract FuzzTest is PropertyParent { } } } - - //solhint-disable no-empty-blocks - function test_debug() public {} } diff --git a/test/invariants/Reproducers.t.sol b/test/invariants/Reproducers.t.sol new file mode 100644 index 0000000..6256338 --- /dev/null +++ b/test/invariants/Reproducers.t.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import {FuzzTest} from './FuzzTest.t.sol'; +import {IEBORequestModule, IOracle} from './Setup.t.sol'; + +contract Reproducers is FuzzTest { + function test_debug() public { + vm.roll(55_341); + vm.warp(292_791); + vm.prank(0x0000000000000000000000000000000000080000); + this.property_requesterCanAlwaysCreateRequest( + 0, 91_936_153_333_790_985_814_765_645_281_331_945_670_085_017_288_440_355_350_976_283_151_607_122_591_831 + ); + + vm.roll(114_433); + vm.warp(791_132); + vm.prank(0x0000000000000000000000000000000000080000); + this.property_finalizeAfterDeadline( + 13_479_973_333_575_319_897_333_507_543_509_815_336_818_572_211_270_290_147_286_325_345_251, + 107_839_786_668_602_559_178_668_057_886_353_385_264_177_471_300_505_974_851_760_065_510_272 + ); + + vm.roll(164_579); + vm.warp(1_050_332); + vm.prank(0x00000000000000000000000000000000000a0000); + this.property_requesterCanAlwaysCreateRequest(0, 300_000_000_001_847_143); + + vm.roll(225_050); + vm.warp(1_491_370); + vm.prank(0x00000000000000000000000000000000000a0000); + this.property_requesterCanAlwaysCreateRequest( + 0, 115_792_089_237_316_195_423_570_985_008_687_907_853_269_984_665_640_564_039_456_584_007_913_130_122_499 + ); + } +} diff --git a/test/invariants/handlers/HandlerEBORequestCreator.t.sol b/test/invariants/handlers/HandlerEBORequestCreator.t.sol index c2c9a53..fc6185a 100644 --- a/test/invariants/handlers/HandlerEBORequestCreator.t.sol +++ b/test/invariants/handlers/HandlerEBORequestCreator.t.sol @@ -26,47 +26,4 @@ contract HandlerEBORequestCreator is BaseHandler { _ghost_chainIdToChain[keccak256(abi.encodePacked(INITIAL_CHAINS[i]))] = INITIAL_CHAINS[i]; } } - - function handleCreateRequest(uint256 _epoch, uint256 _chainIdSeed) external { - _epoch = bound(_epoch, START_EPOCH, block.timestamp); - - string memory chainId = _getRandomChain(_chainIdSeed); - if (bytes(chainId).length == 0) return; - - // Create request via EBORequestCreator - eboRequestCreator.createRequest(_epoch, chainId); - - // Get current request data - IOracle.Request memory requestData = eboRequestCreator.getRequestData(); - - // Build request module parameters - IEBORequestModule.RequestParameters memory requestParams = - abi.decode(requestData.requestModuleData, (IEBORequestModule.RequestParameters)); - requestParams.epoch = _epoch; - requestParams.chainId = chainId; - requestData.requestModuleData = abi.encode(requestParams); - - // Calculate request ID using same logic as Oracle - bytes32 requestId = keccak256(abi.encode(requestData)); - - // Track the request - _ghost_requests.push(requestId); - _ghost_requestsPerEpochChainId[_epoch][chainId].push(requestId); - _ghost_requestData[requestId] = requestData; - _ghost_validRequests[requestId] = true; - - emit RequestCreated(requestId, _epoch, chainId); - } - - function handleAddChain(string memory _chainId) external { - eboRequestCreator.addChain(_chainId); - - // Track the chain - _ghost_chainIdToChain[keccak256(abi.encodePacked(_chainId))] = _chainId; - } - - // function handleRemoveChain(uint256 _chainIdSeed) external { - // string memory chainId = _getRandomChainId(_chainIdSeed); - // eboRequestCreator.removeChain(chainId); - // } } diff --git a/test/invariants/properties/PropertyRequester.t.sol b/test/invariants/properties/PropertyRequester.t.sol index fb74484..3dae1b6 100644 --- a/test/invariants/properties/PropertyRequester.t.sol +++ b/test/invariants/properties/PropertyRequester.t.sol @@ -9,6 +9,7 @@ contract PropertyRequester is HandlerParent { constructor() {} event Test(bool); + event TestUint(uint256); /// @custom:property-id 1 /// @custom:property Requester can always create a request as long as the same chainId/epoch isn't already finalized with response @@ -21,17 +22,26 @@ contract PropertyRequester is HandlerParent { if (bytes(chainId).length == 0) return; uint256 requestsPerEpochChainId = _ghost_requestsPerEpochChainId[_epoch][chainId].length; - bytes32 requestId; uint256 activeRequests; bool isFinalizedWithResponse; + // Calculate request ID using same logic as Oracle + // Get current request data + IOracle.Request memory requestData = eboRequestCreator.getRequestData(); + IEBORequestModule.RequestParameters memory requestParams = + abi.decode(requestData.requestModuleData, (IEBORequestModule.RequestParameters)); + requestParams.epoch = _epoch; + requestParams.chainId = chainId; + requestData.requestModuleData = abi.encode(requestParams); + bytes32 requestId = keccak256(abi.encode(requestData)); + emit TestUint(_epoch); // Create request via EBORequestCreator try eboRequestCreator.createRequest(_epoch, chainId) { // Check if there are active requests and a request finalized with response for (uint256 i; i < requestsPerEpochChainId; ++i) { - requestId = _ghost_requestsPerEpochChainId[_epoch][chainId][i]; - if (oracle.finalizedAt(requestId) == 0) ++activeRequests; - if (oracle.finalizedResponseId(requestId) != 0) { + bytes32 _currRequestId = _ghost_requestsPerEpochChainId[_epoch][chainId][i]; + if (oracle.finalizedAt(_currRequestId) == 0) ++activeRequests; + if (oracle.finalizedResponseId(_currRequestId) != 0) { isFinalizedWithResponse = true; break; } @@ -42,19 +52,6 @@ contract PropertyRequester is HandlerParent { // property 2 assertEq(activeRequests, 0, 'prop-2: same chainId/epoch active request'); - // Get current request data - IOracle.Request memory requestData = eboRequestCreator.getRequestData(); - - // Build request module parameters - IEBORequestModule.RequestParameters memory requestParams = - abi.decode(requestData.requestModuleData, (IEBORequestModule.RequestParameters)); - requestParams.epoch = _epoch; - requestParams.chainId = chainId; - requestData.requestModuleData = abi.encode(requestParams); - - // Calculate request ID using same logic as Oracle - bytes32 requestId = keccak256(abi.encode(requestData)); - // Track the request _ghost_requests.push(requestId); _ghost_requestsPerEpochChainId[_epoch][chainId].push(requestId); @@ -65,16 +62,24 @@ contract PropertyRequester is HandlerParent { } catch { // Check if there are active requests and a request finalized with response for (uint256 i; i < requestsPerEpochChainId; ++i) { - requestId = _ghost_requestsPerEpochChainId[_epoch][chainId][i]; - if (requestId != bytes32(0) && oracle.finalizedAt(requestId) == 0) ++activeRequests; - if (requestId != bytes32(0) && oracle.finalizedResponseId(requestId) != 0) { + bytes32 currRequestId = _ghost_requestsPerEpochChainId[_epoch][chainId][i]; + + // active because not finalized + if (oracle.finalizedAt(currRequestId) == 0) ++activeRequests; + + // active because finalized without answer + if ((oracle.finalizedAt(currRequestId) != 0 && oracle.finalizedResponseId(currRequestId) == 0)) { + ++activeRequests; + } + + // not active + if (oracle.finalizedResponseId(currRequestId) != 0) { isFinalizedWithResponse = true; break; } } // property 1 and 2 - emit RequestCreated(requestId, _epoch, chainId); emit Test(isFinalizedWithResponse); emit Test(activeRequests > 0); assertTrue(isFinalizedWithResponse || activeRequests > 0, 'prop-1-2: create request reverted');