Skip to content

Commit

Permalink
test(medusa): correct prop-6
Browse files Browse the repository at this point in the history
  • Loading branch information
0xJabberwock committed Nov 29, 2024
1 parent 97fff3c commit 80d145f
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 21 deletions.
7 changes: 5 additions & 2 deletions test/invariants/handlers/BaseHandler.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ contract BaseHandler is Setup, Actors {
bytes32 _requestId,
uint256 _seed
) internal view returns (bytes32, IOracle.Response memory) {
bytes32 responseId = _ghost_activeResponses[_requestId][_seed % _ghost_activeResponses[_requestId].length];

bytes32[] storage responses = _ghost_activeResponses[_requestId];
if (responses.length == 0) {
return (bytes32(0), IOracle.Response(address(0), bytes32(0), bytes('')));
}
bytes32 responseId = responses[_seed % responses.length];
return (responseId, _ghost_responseData[responseId]);
}

Expand Down
17 changes: 9 additions & 8 deletions test/invariants/handlers/HandlerOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,27 @@ contract HandlerOracle is BaseHandler {
// Track response
_ghost_activeResponses[requestId].push(responseId);
_ghost_responseData[responseId] = response;
_ghost_bonds[proposer][requestId] += RESPONSE_BOND_SIZE;

emit ResponseProposed(requestId, responseId);

return responseId;
}

function handleDisputeResponseOracle(uint256 _requestSeed, uint256 _actorSeed) external returns (bytes32) {
function handleDisputeResponseOracle(
uint256 _requestSeed,
uint256 _responseSeed,
uint256 _actorSeed
) external returns (bytes32) {
(bytes32 requestId, IOracle.Request memory request) = _getRandomRequest(_requestSeed);
if (requestId == bytes32(0) || !_ghost_validRequests[requestId]) {
return bytes32(0);
}

if (_ghost_activeResponses[requestId].length == 0) return (bytes32(0));
bytes32 responseId = _ghost_activeResponses[requestId][0];

IOracle.Response memory response = _ghost_responseData[responseId];
if (_ghost_finalizedResponses[responseId]) return bytes32(0);
(bytes32 responseId, IOracle.Response memory response) = _getRandomActiveResponse(requestId, _responseSeed);
if (responseId == bytes32(0) || _ghost_finalizedResponses[responseId]) return bytes32(0);

address disputer = _pickActor(_actorSeed);
uint256 bond = DISPUTE_BOND_SIZE;

IOracle.Dispute memory dispute =
IOracle.Dispute({disputer: disputer, proposer: response.proposer, requestId: requestId, responseId: responseId});
Expand All @@ -60,7 +61,7 @@ contract HandlerOracle is BaseHandler {
// Track dispute
_ghost_disputes[requestId].push(disputeId);
_ghost_disputeData[disputeId] = dispute;
_ghost_bonds[disputer][requestId] = bond;
_ghost_bonds[disputer][requestId] += DISPUTE_BOND_SIZE;

emit DisputeCreated(requestId, responseId, disputeId);

Expand Down
20 changes: 15 additions & 5 deletions test/invariants/properties/PropertyDisputer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ contract PropertyDisputer is HandlerParent {
/// @custom:property-id 6
/// @custom:property A disputer can always dispute a response before the finalisation, if no previous dispute has been made
function property_disputerCanAlwaysCreateDispute(uint256 _requestIdSeed, uint256 _responseIdSeed) public {
// Pick random Response
// Pick random request
(bytes32 _requestId, IOracle.Request memory _requestData) = _getRandomRequest(_requestIdSeed);
if (_requestId == bytes32(0) || !_ghost_validRequests[_requestId]) return;

// Pick random response
(bytes32 _responseId, IOracle.Response memory _responseData) = _getRandomActiveResponse(_requestId, _responseIdSeed);
if (_responseId == bytes32(0)) return;

IOracle.Dispute memory _disputeData = IOracle.Dispute({
disputer: msg.sender,
Expand All @@ -23,21 +27,27 @@ contract PropertyDisputer is HandlerParent {
_stakeGRT(DISPUTE_BOND_SIZE);
_provisionGRT(DISPUTE_BOND_SIZE);

bytes32 _prevDisputeId = oracle.disputeOf(_responseId);

vm.prank(msg.sender);
try oracle.disputeResponse(_requestData, _responseData, _disputeData) returns (bytes32 _disputeId) {
// check if no previous dispute
assertEq(_ghost_disputes[_requestId].length, 0, 'property 6: new dispute duplicate');
assertEq(_prevDisputeId, 0, 'property 6: new dispute duplicate');

// add to ghost disputes
_ghost_disputes[_requestId].push(_disputeId);
_ghost_disputeData[_disputeId] = _disputeData;
_ghost_bonds[msg.sender][_requestId] += DISPUTE_BOND_SIZE;

emit DisputeCreated(_requestId, _responseId, _disputeId);
} catch {
// check that there was a previous dispute, or
// outside of the dispute window, or
//
// request already finalized
assertTrue(
_ghost_disputes[_responseId].length > 0
|| block.timestamp > oracle.responseCreatedAt(_responseId) + RESPONSE_DISPUTE_WINDOW,
_prevDisputeId != bytes32(0)
|| block.timestamp > oracle.responseCreatedAt(_responseId) + RESPONSE_DISPUTE_WINDOW
|| oracle.finalizedAt(_requestId) != 0,
'property 6: fails but no previous active dispute'
);
}
Expand Down
8 changes: 3 additions & 5 deletions test/invariants/properties/PropertyProposer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,26 @@ contract PropertyProposer is HandlerParent {
/// @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_proposeBeforeDeadlineAndNoAnswer(uint256 _requestIdSeed, bytes calldata _response) public {
function property_proposerProposeBeforeDeadlineAndNoAnswer(uint256 _requestIdSeed, bytes calldata _response) public {
// Pick random request
(bytes32 requestId, IOracle.Request memory requestData) = _getRandomRequest(_requestIdSeed);
if (requestId == bytes32(0) || !_ghost_validRequests[requestId]) return;

// Build response data
IOracle.Response memory responseData = IOracle.Response(msg.sender, requestId, _response); // abi.encode(_blockNumber)?

// Calculate response ID using same logic as Oracle
bytes32 responseId = keccak256(abi.encode(responseData));

// Stake some GRT in Horizon
_stakeGRT(RESPONSE_BOND_SIZE);
// Provision some GRT in Horizon
_provisionGRT(RESPONSE_BOND_SIZE);

// Propose response
vm.prank(msg.sender);
try oracle.proposeResponse(requestData, responseData) {
try oracle.proposeResponse(requestData, responseData) returns (bytes32 responseId) {
// Track response
_ghost_activeResponses[requestId].push(responseId);
_ghost_responseData[responseId] = responseData;
_ghost_bonds[msg.sender][requestId] += RESPONSE_BOND_SIZE;

emit ResponseProposed(requestId, responseId);
} catch {
Expand Down
2 changes: 1 addition & 1 deletion test/invariants/properties/PropertyRequester.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ contract PropertyRequester is HandlerParent {
/// @custom:property Requester can always create a request as long as the same chainId/epoch isn't already finalized with response
/// @custom:property-id 2
/// @custom:property Requester can always create a request as long as there is no other active request per the same chainId/epoch
function property_canAlwaysCreateRequest(uint256 _epoch, uint256 _chainIdSeed) external {
function property_requesterCanAlwaysCreateRequest(uint256 _epoch, uint256 _chainIdSeed) external {
_epoch = bound(_epoch, START_EPOCH, block.timestamp);

string memory chainId = _getRandomChain(_chainIdSeed);
Expand Down

0 comments on commit 80d145f

Please sign in to comment.