-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
176 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
blueprints/incredible-squaring-symbiotic/contracts/src/IIncredibleSquaringTaskManager.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.13; | ||
|
||
interface IIncredibleSquaringTaskManager { | ||
// EVENTS | ||
event NewTaskCreated(uint32 indexed taskIndex, Task task); | ||
|
||
event TaskResponded(TaskResponse taskResponse, uint32 indexed taskIndex); | ||
|
||
event TaskCompleted(uint32 indexed taskIndex); | ||
|
||
// STRUCTS | ||
struct Task { | ||
uint256 numberToBeSquared; | ||
uint32 taskCreatedBlock; | ||
} | ||
|
||
// Task response is hashed and signed by operators. | ||
// these signatures are aggregated and sent to the contract as response. | ||
struct TaskResponse { | ||
// Can be obtained by the operator from the event NewTaskCreated. | ||
uint32 referenceTaskIndex; | ||
// This is just the response that the operator has to compute by itself. | ||
uint256 numberSquared; | ||
} | ||
|
||
// FUNCTIONS | ||
// NOTE: this function creates new task. | ||
function createNewTask( | ||
uint256 numberToBeSquared | ||
) external; | ||
|
||
/// @notice Returns the current 'taskNumber' for the middleware | ||
function taskNumber() external view returns (uint32); | ||
|
||
/// @notice Returns the TASK_RESPONSE_WINDOW_BLOCK | ||
function getTaskResponseWindowBlock() external view returns (uint32); | ||
} |
124 changes: 124 additions & 0 deletions
124
blueprints/incredible-squaring-symbiotic/contracts/src/IncredibleSquaringTaskManager.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.13; | ||
|
||
import "incredible-squaring/SimpleMiddleware.sol"; | ||
import "incredible-squaring/IIncredibleSquaringTaskManager.sol"; | ||
|
||
contract IncredibleSquaringTaskManager is | ||
SimpleMiddleware, | ||
IIncredibleSquaringTaskManager | ||
{ | ||
|
||
/* CONSTANT */ | ||
// The number of blocks from the task initialization within which the aggregator has to respond to | ||
uint32 public immutable TASK_RESPONSE_WINDOW_BLOCK; | ||
uint32 public constant TASK_CHALLENGE_WINDOW_BLOCK = 100; | ||
uint256 internal constant _THRESHOLD_DENOMINATOR = 100; | ||
|
||
/* STORAGE */ | ||
// The latest task index | ||
uint32 public latestTaskNum; | ||
|
||
// mapping of task indices to all tasks hashes | ||
// when a task is created, task hash is stored here, | ||
// and responses need to pass the actual task, | ||
// which is hashed onchain and checked against this mapping | ||
mapping(uint32 => bytes32) public allTaskHashes; | ||
|
||
// mapping of task indices to hash of abi.encode(taskResponse, taskResponseMetadata) | ||
mapping(uint32 => bytes32) public allTaskResponses; | ||
|
||
mapping(uint32 => bool) public taskSuccesfullyChallenged; | ||
|
||
address public aggregator; | ||
address public generator; | ||
|
||
/* MODIFIERS */ | ||
|
||
// onlyTaskGenerator is used to restrict createNewTask from only being called by a permissioned entity | ||
// in a real world scenario, this would be removed by instead making createNewTask a payable function | ||
modifier onlyTaskGenerator() { | ||
require(msg.sender == generator, "Task generator must be the caller"); | ||
_; | ||
} | ||
|
||
constructor( | ||
address _network, | ||
address _operatorRegistry, | ||
address _vaultRegistry, | ||
address _operatorNetOptin, | ||
uint48 _epochDuration, | ||
uint48 _slashingWindow, | ||
uint32 _taskResponseWindowBlock | ||
) SimpleMiddleware(_network, _operatorRegistry, _vaultRegistry, _operatorNetOptin, _epochDuration, _slashingWindow) { | ||
TASK_RESPONSE_WINDOW_BLOCK = _taskResponseWindowBlock; | ||
} | ||
|
||
function initialize( | ||
address initialOwner, | ||
address _generator | ||
) public initializer { | ||
_transferOwnership(initialOwner); | ||
generator = _generator; | ||
} | ||
|
||
/* FUNCTIONS */ | ||
// NOTE: this function creates new task, assigns it a taskId | ||
function createNewTask( | ||
uint256 numberToBeSquared | ||
) external onlyTaskGenerator { | ||
// create a new task struct | ||
Task memory newTask; | ||
newTask.numberToBeSquared = numberToBeSquared; | ||
newTask.taskCreatedBlock = uint32(block.number); | ||
|
||
// store hash of task onchain, emit event, and increase taskNum | ||
allTaskHashes[latestTaskNum] = keccak256(abi.encode(newTask)); | ||
emit NewTaskCreated(latestTaskNum, newTask); | ||
latestTaskNum = latestTaskNum + 1; | ||
} | ||
|
||
// NOTE: this function responds to existing tasks. | ||
function respondToTask( | ||
Task calldata task, | ||
TaskResponse calldata taskResponse | ||
) external onlyOperator { | ||
uint32 taskCreatedBlock = task.taskCreatedBlock; | ||
|
||
// check that the task is valid, hasn't been responsed yet, and is being responsed in time | ||
require( | ||
keccak256(abi.encode(task)) == | ||
allTaskHashes[taskResponse.referenceTaskIndex], | ||
"Task hash does not match" | ||
); | ||
require( | ||
allTaskResponses[taskResponse.referenceTaskIndex] == bytes32(0), | ||
"Task already responded to" | ||
); | ||
require( | ||
uint32(block.number) <= | ||
taskCreatedBlock + TASK_RESPONSE_WINDOW_BLOCK, | ||
"Task responded to too late" | ||
); | ||
require( | ||
taskResponse.numberSquared == task.numberToBeSquared * task.numberToBeSquared, | ||
"Task response invalid, numberSquared is not the square of numberToBeSquared" | ||
); | ||
|
||
// updating the storage with task response hash | ||
allTaskResponses[taskResponse.referenceTaskIndex] = keccak256( | ||
abi.encode(taskResponse) | ||
); | ||
|
||
// emitting event | ||
emit TaskResponded(taskResponse, taskResponse.referenceTaskIndex); | ||
} | ||
|
||
function taskNumber() external view returns (uint32) { | ||
return latestTaskNum; | ||
} | ||
|
||
function getTaskResponseWindowBlock() external view returns (uint32) { | ||
return TASK_RESPONSE_WINDOW_BLOCK; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters