Skip to content

Commit

Permalink
perf: optimize RootVerificationModule (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
gas1cent authored Nov 11, 2023
1 parent 6eb1aff commit c96f6cd
Show file tree
Hide file tree
Showing 5 changed files with 485 additions and 544 deletions.
7 changes: 3 additions & 4 deletions docs/src/content/modules/dispute/root_verification_module.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ The Root Verification Module is a pre-dispute module that allows disputers to ca

### Key Methods

- `decodeRequestData(bytes32 _requestId)`: Returns the decoded data for a request.
- `disputeResponse(bytes32 _requestId, bytes32 _responseId, address _disputer, address _proposer)`: Calculates the correct root and compares it to the proposed one. Updates the dispute status after checking if the disputed response is indeed wrong.
- `onDisputeStatusChange(bytes32 _requestId, IOracle.Dispute memory _dispute)`: Updates the status of the dispute and resolves it by proposing the correct root as a response and finalizing the request.
- `disputeEscalated(bytes32 _disputeId)`: This function is present to comply with the module interface but it is not implemented since this is a pre-dispute module.
- `decodeRequestData`: Returns the decoded data for a request.
- `disputeResponse`: Calculates the correct root and compares it to the proposed one. Updates the dispute status after checking if the disputed response is indeed wrong.
- `onDisputeStatusChange`: Updates the status of the dispute and resolves it by proposing the correct root as a response and finalizing the request.

### Request Parameters

Expand Down
189 changes: 95 additions & 94 deletions solidity/contracts/modules/dispute/RootVerificationModule.sol
Original file line number Diff line number Diff line change
@@ -1,94 +1,95 @@
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.19;

// // solhint-disable-next-line no-unused-import
// import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol';
// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol';

// import {IRootVerificationModule} from '../../../interfaces/modules/dispute/IRootVerificationModule.sol';
// import {MerkleLib} from '../../libraries/MerkleLib.sol';

// contract RootVerificationModule is Module, IRootVerificationModule {
// using MerkleLib for MerkleLib.Tree;

// /**
// * @notice The calculated correct root for a given request
// */
// mapping(bytes32 _requestId => bytes32 _correctRoot) internal _correctRoots;

// constructor(IOracle _oracle) Module(_oracle) {}

// /// @inheritdoc IModule
// function moduleName() external pure returns (string memory _moduleName) {
// return 'RootVerificationModule';
// }

// /// @inheritdoc IRootVerificationModule
// function decodeRequestData(bytes32 _requestId) public view returns (RequestParameters memory _params) {
// _params = abi.decode(requestData[_requestId], (RequestParameters));
// }

// /// @inheritdoc IRootVerificationModule
// function disputeEscalated(bytes32 _disputeId) external onlyOracle {}

// /// @inheritdoc IRootVerificationModule
// function onDisputeStatusChange(bytes32, IOracle.Dispute memory _dispute) external onlyOracle {
// RequestParameters memory _params = decodeRequestData(_dispute.requestId);

// IOracle.Response memory _response = ORACLE.getResponse(_dispute.responseId);

// bool _won = abi.decode(_response.response, (bytes32)) != _correctRoots[_dispute.requestId];

// if (_won) {
// _params.accountingExtension.pay({
// _requestId: _dispute.requestId,
// _payer: _dispute.proposer,
// _receiver: _dispute.disputer,
// _token: _params.bondToken,
// _amount: _params.bondSize
// });
// bytes32 _correctResponseId =
// ORACLE.proposeResponse(_dispute.disputer, _dispute.requestId, abi.encode(_correctRoots[_dispute.requestId]));
// ORACLE.finalize(_dispute.requestId, _correctResponseId);
// } else {
// ORACLE.finalize(_dispute.requestId, _dispute.responseId);
// }

// delete _correctRoots[_dispute.requestId];

// emit DisputeStatusChanged({
// _requestId: _dispute.requestId,
// _responseId: _dispute.responseId,
// _disputer: _dispute.disputer,
// _proposer: _dispute.proposer,
// _status: _dispute.status
// });
// }

// /// @inheritdoc IRootVerificationModule
// function disputeResponse(
// bytes32 _requestId,
// bytes32 _responseId,
// address _disputer,
// address _proposer
// ) external onlyOracle returns (IOracle.Dispute memory _dispute) {
// IOracle.Response memory _response = ORACLE.getResponse(_responseId);
// RequestParameters memory _params = decodeRequestData(_requestId);

// bytes32 _correctRoot = _params.treeVerifier.calculateRoot(_params.treeData, _params.leavesToInsert);
// _correctRoots[_requestId] = _correctRoot;

// bool _won = abi.decode(_response.response, (bytes32)) != _correctRoot;

// _dispute = IOracle.Dispute({
// disputer: _disputer,
// responseId: _responseId,
// proposer: _proposer,
// requestId: _requestId,
// status: _won ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost,
// createdAt: block.timestamp
// });

// emit ResponseDisputed(_requestId, _responseId, _disputer, _proposer);
// }
// }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// solhint-disable-next-line no-unused-import
import {Module, IModule} from '@defi-wonderland/prophet-core-contracts/solidity/contracts/Module.sol';
import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol';

import {IRootVerificationModule} from '../../../interfaces/modules/dispute/IRootVerificationModule.sol';
import {MerkleLib} from '../../libraries/MerkleLib.sol';

contract RootVerificationModule is Module, IRootVerificationModule {
using MerkleLib for MerkleLib.Tree;

/**
* @notice The calculated correct root for a given request
*/
mapping(bytes32 _requestId => bytes32 _correctRoot) internal _correctRoots;

constructor(IOracle _oracle) Module(_oracle) {}

/// @inheritdoc IModule
function moduleName() external pure returns (string memory _moduleName) {
return 'RootVerificationModule';
}

/// @inheritdoc IRootVerificationModule
function decodeRequestData(bytes calldata _data) public pure returns (RequestParameters memory _params) {
_params = abi.decode(_data, (RequestParameters));
}

/// @inheritdoc IRootVerificationModule
function onDisputeStatusChange(
bytes32 _disputeId,
IOracle.Request calldata _request,
IOracle.Response calldata _response,
IOracle.Dispute calldata _dispute
) external onlyOracle {
// TODO: Call `disputeStatus` to check the current status
RequestParameters memory _params = decodeRequestData(_request.disputeModuleData);

bytes32 _correctRoot = _correctRoots[_dispute.requestId];
bool _won = abi.decode(_response.response, (bytes32)) != _correctRoot;

if (_won) {
_params.accountingExtension.pay({
_requestId: _dispute.requestId,
_payer: _dispute.proposer,
_receiver: _dispute.disputer,
_token: _params.bondToken,
_amount: _params.bondSize
});

IOracle.Response memory _newResponse = IOracle.Response({
requestId: _dispute.requestId,
proposer: _dispute.disputer,
response: abi.encode(_correctRoot)
});

emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Won});

ORACLE.proposeResponse(_request, _newResponse);
ORACLE.finalize(_request, _newResponse);
} else {
emit DisputeStatusChanged({_disputeId: _disputeId, _dispute: _dispute, _status: IOracle.DisputeStatus.Lost});
ORACLE.finalize(_request, _response);
}

delete _correctRoots[_dispute.requestId];
}

/// @inheritdoc IRootVerificationModule
function disputeResponse(
IOracle.Request calldata _request,
IOracle.Response calldata _response,
IOracle.Dispute calldata _dispute
) external onlyOracle {
RequestParameters memory _params = decodeRequestData(_request.disputeModuleData);

bytes32 _correctRoot = _params.treeVerifier.calculateRoot(_params.treeData, _params.leavesToInsert);
_correctRoots[_response.requestId] = _correctRoot;

IOracle.DisputeStatus _status =
abi.decode(_response.response, (bytes32)) != _correctRoot ? IOracle.DisputeStatus.Won : IOracle.DisputeStatus.Lost;

emit ResponseDisputed({
_requestId: _response.requestId,
_responseId: _dispute.responseId,
_disputeId: _getId(_dispute),
_dispute: _dispute,
_blockNumber: block.number
});

ORACLE.updateDisputeStatus(_request, _response, _dispute, _status);
}
}
151 changes: 74 additions & 77 deletions solidity/interfaces/modules/dispute/IRootVerificationModule.sol
Original file line number Diff line number Diff line change
@@ -1,84 +1,81 @@
// // SPDX-License-Identifier: MIT
// pragma solidity ^0.8.19;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
// import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol';
// import {IDisputeModule} from
// '@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/dispute/IDisputeModule.sol';
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IOracle} from '@defi-wonderland/prophet-core-contracts/solidity/interfaces/IOracle.sol';
import {IDisputeModule} from
'@defi-wonderland/prophet-core-contracts/solidity/interfaces/modules/dispute/IDisputeModule.sol';

// import {ITreeVerifier} from '../../ITreeVerifier.sol';
// import {IAccountingExtension} from '../../extensions/IAccountingExtension.sol';
import {ITreeVerifier} from '../../ITreeVerifier.sol';
import {IAccountingExtension} from '../../extensions/IAccountingExtension.sol';

// /*
// * @title RootVerificationModule
// * @notice Dispute module allowing disputers to calculate the correct root
// * for a given request and propose it as a response. If the disputer wins the
// * dispute, he is rewarded with the bond of the proposer.
// * @dev This module is a pre-dispute module. It allows disputing
// * and resolving a response in a single call.
// */
// interface IRootVerificationModule is IDisputeModule {
// /*///////////////////////////////////////////////////////////////
// STRUCTS
// //////////////////////////////////////////////////////////////*/
/*
* @title RootVerificationModule
* @notice Dispute module allowing disputers to calculate the correct root for a given request and propose it as a response.
* If the disputer wins the dispute, he is rewarded with the bond of the proposer.
*
* @dev This module is a pre-dispute module. It allows disputing and resolving a response in a single call.
*/
interface IRootVerificationModule is IDisputeModule {
/*///////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/

// /**
// * @notice Parameters of the request as stored in the module
// * @param treeData The data of the tree
// * @param leavesToInsert The leaves to insert in the tree
// * @param treeVerifier The tree verifier to use to calculate the correct root
// * @param accountingExtension The accounting extension to use for bonds and payments
// * @param bondToken The token to use for bonds and payments
// * @param bondSize The size of the bond to participate in the request
// */
// struct RequestParameters {
// bytes treeData;
// bytes32[] leavesToInsert;
// ITreeVerifier treeVerifier;
// IAccountingExtension accountingExtension;
// IERC20 bondToken;
// uint256 bondSize;
// }
// /*///////////////////////////////////////////////////////////////
// LOGIC
// //////////////////////////////////////////////////////////////*/
/**
* @notice Parameters of the request as stored in the module
* @param treeData The data of the tree
* @param leavesToInsert The leaves to insert in the tree
* @param treeVerifier The tree verifier to use to calculate the correct root
* @param accountingExtension The accounting extension to use for bonds and payments
* @param bondToken The token to use for bonds and payments
* @param bondSize The size of the bond to participate in the request
*/
struct RequestParameters {
bytes treeData;
bytes32[] leavesToInsert;
ITreeVerifier treeVerifier;
IAccountingExtension accountingExtension;
IERC20 bondToken;
uint256 bondSize;
}
/*///////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/

// /**
// * @notice Returns the decoded data for a request
// * @param _requestId The ID of the request
// * @return _params The struct containing the parameters for the request
// */
// function decodeRequestData(bytes32 _requestId) external view returns (RequestParameters memory _params);
/**
* @notice Returns the decoded data for a request
* @param _data The encoded request parameters
* @return _params The decoded parameters of the request
*/
function decodeRequestData(bytes calldata _data) external view returns (RequestParameters memory _params);

// /**
// * @notice Calculates the correct root and compares it to the proposed one.
// * @dev Since this is a pre-dispute module, the dispute status is updated after checking
// * if the disputed response is indeed wrong, since it is calculated on dispute.
// * @param _requestId The id of the request from which the response is being disputed
// * @param _responseId The id of the response being disputed
// * @param _disputer The user who is disputing the response
// * @param _proposer The proposer of the response being disputed
// * @return _dispute The dispute of the current response with the updated status
// */
// function disputeResponse(
// bytes32 _requestId,
// bytes32 _responseId,
// address _disputer,
// address _proposer
// ) external returns (IOracle.Dispute memory _dispute);
/**
* @notice Initiates and resolves the dispute by comparing the proposed response with the one returned by the verifier
*
* @dev This function will notify the oracle about the outcome of the dispute
* @param _request The request that the response was proposed to
* @param _response The response that is being disputed
* @param _dispute The dispute created by the oracle
*/
function disputeResponse(
IOracle.Request calldata _request,
IOracle.Response calldata _response,
IOracle.Dispute calldata _dispute
) external;

// /**
// * @notice Updates the status of the dispute and resolves it by proposing the correct root
// * as a response and finalizing the request.
// * @dev The correct root is retrieved from storage and compared to the proposed root.
// * If the dispute is won, the disputer is paid. In both cases, the request is finalized.
// * @param _dispute The dispute of the current response
// */
// function onDisputeStatusChange(bytes32, IOracle.Dispute memory _dispute) external;

// /**
// * @dev This function is present to comply with the module interface but it
// * is not implemented since this is a pre-dispute module.
// */
// function disputeEscalated(bytes32 _disputeId) external;
// }
/**
* @notice Depending on the status of the dispute, either pays the disputer and submits the correct response,
* or pays the proposer. Finalizes the request in any case.
*
* @param _disputeId The id of the dispute
* @param _request The request that the response was proposed to
* @param _response The response that was disputed
* @param _dispute The dispute
*/
function onDisputeStatusChange(
bytes32 _disputeId,
IOracle.Request calldata _request,
IOracle.Response calldata _response,
IOracle.Dispute calldata _dispute
) external;
}
Loading

0 comments on commit c96f6cd

Please sign in to comment.