From 7218056b52311e475f8e125088a6486499c909d7 Mon Sep 17 00:00:00 2001 From: 0xJabberwock <0xjabberwock@defi.sucks> Date: Fri, 13 Dec 2024 12:16:29 -0300 Subject: [PATCH] test(medusa): proposer properties --- test/invariants/Reproducers.t.sol | 8 ++--- test/invariants/handlers/HandlerOracle.t.sol | 8 ++--- .../properties/PropertyDisputer.t.sol | 1 + .../properties/PropertyProposer.t.sol | 32 +++++++++++++++---- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/test/invariants/Reproducers.t.sol b/test/invariants/Reproducers.t.sol index 3a86013..d268bc8 100644 --- a/test/invariants/Reproducers.t.sol +++ b/test/invariants/Reproducers.t.sol @@ -18,8 +18,8 @@ contract Reproducers is FuzzTest { vm.roll(29_920); vm.warp(191_126); vm.prank(0x0000000000000000000000000000000000020000); - this.property_proposerProposeBeforeDeadlineAndNoAnswer( - 3_533_694_129_556_768_659_166_594_920_800_430_618_073_929_656_453_786_986_859_439_806_182_558_244, '' + this.property_proposerProposeBeforeDeadline( + 3_533_694_129_556_768_659_166_594_920_800_430_618_073_929_656_453_786_986_859_439_806_182_558_244 ); vm.roll(41_973); @@ -81,9 +81,7 @@ contract Reproducers is FuzzTest { vm.roll(86_763); vm.warp(575_158); vm.prank(0x0000000000000000000000000000000000030000); - this.property_proposerProposeBeforeDeadlineAndNoAnswer( - 631_432_499_075_532_304_456_395_701_379_901_335_158_300_516, '' - ); + this.property_proposerProposeBeforeDeadline(631_432_499_075_532_304_456_395_701_379_901_335_158_300_516); vm.roll(108_137); vm.warp(650_339); diff --git a/test/invariants/handlers/HandlerOracle.t.sol b/test/invariants/handlers/HandlerOracle.t.sol index 7060282..f5ffa22 100644 --- a/test/invariants/handlers/HandlerOracle.t.sol +++ b/test/invariants/handlers/HandlerOracle.t.sol @@ -11,11 +11,7 @@ contract HandlerOracle is BaseHandler { return oracle.createRequest(request, _previousId); } - function handleProposeResponse( - uint256 _requestSeed, - uint256 _blockNumber, - uint256 _actorSeed - ) external returns (bytes32) { + function handleProposeResponse(uint256 _requestSeed, uint256 _actorSeed) external returns (bytes32) { (bytes32 requestId, IOracle.Request memory request) = _getRandomRequest(_requestSeed); if (requestId == bytes32(0) || !_ghost_validRequests[requestId]) { return bytes32(0); @@ -24,7 +20,7 @@ contract HandlerOracle is BaseHandler { address proposer = _pickActor(_actorSeed); IOracle.Response memory response = - IOracle.Response({requestId: requestId, response: abi.encode(_blockNumber), proposer: proposer}); + IOracle.Response({requestId: requestId, response: abi.encode(block.number), proposer: proposer}); bytes32 responseId = oracle.proposeResponse(request, response); diff --git a/test/invariants/properties/PropertyDisputer.t.sol b/test/invariants/properties/PropertyDisputer.t.sol index db832a4..53f3b09 100644 --- a/test/invariants/properties/PropertyDisputer.t.sol +++ b/test/invariants/properties/PropertyDisputer.t.sol @@ -18,6 +18,7 @@ contract PropertyDisputer is HandlerParent { (bytes32 _responseId, IOracle.Response memory _responseData) = _getRandomActiveResponse(_requestId, _responseSeed); if (_responseId == bytes32(0)) return; + // Build dispute data IOracle.Dispute memory _disputeData = IOracle.Dispute({ disputer: msg.sender, proposer: _responseData.proposer, diff --git a/test/invariants/properties/PropertyProposer.t.sol b/test/invariants/properties/PropertyProposer.t.sol index 31140b0..199f9c7 100644 --- a/test/invariants/properties/PropertyProposer.t.sol +++ b/test/invariants/properties/PropertyProposer.t.sol @@ -8,23 +8,38 @@ contract PropertyProposer is HandlerParent { /// @custom:property-id 3 /// @custom:property A proposer can always propose an answer before the deadline, if no response has been submitted /// @custom:property-id 4 - /// @custom:property A proposer can always propose an answer before the deadline, if previous response is disputed and has staked - function property_proposerProposeBeforeDeadlineAndNoAnswer(uint256 _requestSeed, bytes calldata _response) public { + /// @custom:property A proposer can always propose an answer before the deadline, if previous response is disputed without losing + function property_proposerProposeBeforeDeadline(uint256 _requestSeed) public { // Pick random request (bytes32 requestId, IOracle.Request memory requestData) = _getRandomRequest(_requestSeed); if (requestId == bytes32(0) || !_ghost_validRequests[requestId]) return; // Build response data - IOracle.Response memory responseData = IOracle.Response(msg.sender, requestId, _response); // abi.encode(_blockNumber)? + IOracle.Response memory responseData = IOracle.Response(msg.sender, requestId, abi.encode(block.number)); - // Stake some GRT in Horizon + // Stake and provision some GRT in Horizon _stakeGRT(RESPONSE_BOND_SIZE); - // Provision some GRT in Horizon _provisionGRT(RESPONSE_BOND_SIZE); + bool activeResponses = _ghost_activeResponses[requestId].length > 0; + bytes32 prevResponseId; + bytes32 prevDisputeId; + IOracle.DisputeStatus status; + if (activeResponses) { + prevResponseId = _ghost_activeResponses[requestId][_ghost_activeResponses[requestId].length - 1]; + prevDisputeId = oracle.disputeOf(prevResponseId); + status = oracle.disputeStatus(prevDisputeId); + } + // Propose response vm.prank(msg.sender); try oracle.proposeResponse(requestData, responseData) returns (bytes32 responseId) { + // property 3 and 4 + assertTrue( + !activeResponses || prevDisputeId != 0 && status != IOracle.DisputeStatus.Lost, + 'prop-3-4: active response not disputed or with lost dispute' + ); + // Track response _ghost_activeResponses[requestId].push(responseId); _ghost_responseData[responseId] = responseData; @@ -32,7 +47,12 @@ contract PropertyProposer is HandlerParent { emit ResponseProposed(requestId, responseId); } catch { - // assert(false); + // property 3 and 4 + assertTrue( + activeResponses && (prevDisputeId == 0 || status == IOracle.DisputeStatus.Lost) + || block.timestamp >= oracle.requestCreatedAt(requestId) + RESPONSE_DEADLINE, + 'prop-3-4: fails but no active response disputed or with lost dispute' + ); } } }