Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: optimize RootVerificationModule #7

Merged
merged 8 commits into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading