Skip to content

Commit

Permalink
Merge pull request #1 from Mugen-Builders/feat/new-coprocessor-contract
Browse files Browse the repository at this point in the history
Feat/new coprocessor contract
  • Loading branch information
Nonnyjoe authored Dec 22, 2024
2 parents b8adf0f + ea97b0d commit 0710d93
Show file tree
Hide file tree
Showing 14 changed files with 473 additions and 171 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Deploy documentation to GitHub Pages

on:
push:
branches: ["main"]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

jobs:
build:
name: Build and upload artifact
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: .
steps:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- uses: actions/checkout@v4
with:
submodules: recursive

- name: generate documentation artifacts
run: forge doc -b

- name: Setup Pages
uses: actions/configure-pages@v4

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/book

deploy:
name: Deploy to GitHub Pages
needs: build
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

90 changes: 0 additions & 90 deletions src/BaseContract.sol

This file was deleted.

109 changes: 109 additions & 0 deletions src/CoprocessorAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {LibError} from "./library/LibError.sol";
import {ICoprocessor} from "./ICoprocessor.sol";
import {LibAddress} from "./library/LibAddress.sol";
import {ICoprocessorOutputs} from "./ICoprocessorOutputs.sol";
import {ICoprocessorCallback} from "./ICoprocessorCallback.sol";

/// @title CoprocessorAdapter
/// @notice A base contract, which should be inherited for interacting with the Coprocessor
abstract contract CoprocessorAdapter is ICoprocessorCallback {
using LibError for bytes;
using LibAddress for address;

bytes32 public machineHash;
ICoprocessor public coprocessor;

error UnauthorizedCaller(address caller);
error InvalidOutputLength(uint256 length);
error ComputationNotFound(bytes32 payloadHash);
error InsufficientFunds(uint256 value, uint256 balance);
error MachineHashMismatch(bytes32 current, bytes32 expected);
error InvalidOutputSelector(bytes4 selector, bytes4 expected);

mapping(bytes32 => bool) public computationSent;

/// @notice Initializes the contract with the coprocessor address and machine hash
/// @param _coprocessorAddress Address of the coprocessor
/// @param _machineHash Initial machine hash
constructor(address _coprocessorAddress, bytes32 _machineHash) {
coprocessor = ICoprocessor(_coprocessorAddress);
machineHash = _machineHash;
}

/// @notice Issues a task to the coprocessor
/// @param input ABI-encoded input data for the coprocessor
function callCoprocessor(bytes calldata input) external {
bytes32 inputHash = keccak256(input);
computationSent[inputHash] = true;
coprocessor.issueTask(machineHash, input, address(this));
}

/// @notice Handles notices sent back from the coprocessor
/// @dev This function should be overridden by child contracts to define specific behavior
/// @param notice ABI-encoded notice data
function handleNotice(bytes memory notice) internal virtual {}

/// @notice Callback function invoked by the coprocessor with computation outputs
/// @param _machineHash The hash of the machine that processed the task
/// @param _payloadHash The hash of the input payload
/// @param outputs Array of ABI-encoded outputs from the coprocessor
function coprocessorCallbackOutputsOnly(bytes32 _machineHash, bytes32 _payloadHash, bytes[] calldata outputs)
external
override
{
if (msg.sender != address(coprocessor)) {
revert UnauthorizedCaller(msg.sender);
}

if (_machineHash != machineHash) {
revert MachineHashMismatch(_machineHash, machineHash);
}

if (!computationSent[_payloadHash]) {
revert ComputationNotFound(_payloadHash);
}

for (uint256 i = 0; i < outputs.length; i++) {
bytes calldata output = outputs[i];

if (output.length <= 3) {
revert InvalidOutputLength(output.length);
}

bytes4 selector = bytes4(output[:4]);
bytes calldata arguments = output[4:];

if (selector == ICoprocessorOutputs.Notice.selector) {
handleNotice(abi.decode(arguments, (bytes)));
} else if (selector == ICoprocessorOutputs.Voucher.selector) {
_executeVoucher(arguments);
} else {
revert InvalidOutputSelector(selector, ICoprocessorOutputs.Notice.selector);
}
}
delete computationSent[_payloadHash];
}

/// @notice Executes a voucher
/// @dev This function decodes and executes a voucher with the specified parameters
/// @param arguments ABI-encoded arguments containing the destination, value, and payload
function _executeVoucher(bytes calldata arguments) internal {
address destination;
uint256 value;
bytes memory payload;

(destination, value, payload) = abi.decode(arguments, (address, uint256, bytes));

bool enoughFunds;
uint256 balance;

(enoughFunds, balance) = destination.safeCall(value, payload);

if (!enoughFunds) {
revert InsufficientFunds(value, balance);
}
}
}
9 changes: 8 additions & 1 deletion src/ICoprocessor.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

pragma solidity 0.8.28;

/// @title ICoprocessor Interface
/// @notice Defines the interface for interacting with a coprocessor contract
interface ICoprocessor {
/// @notice Issues a task to the coprocessor
/// @param machineHash The hash of the machine to which the task is assigned
/// @param input The ABI-encoded input data for the task
/// @param callbackAddress The address to which the callback will be sent upon task completion
function issueTask(bytes32 machineHash, bytes calldata input, address callbackAddress) external;
}
11 changes: 7 additions & 4 deletions src/ICoprocessorCallback.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface ICoprocessorOutputs {
function Notice(bytes calldata payload) external;
}
pragma solidity 0.8.28;

/// @title ICoprocessorCallback Interface
/// @notice Defines the callback mechanism for handling coprocessor outputs
interface ICoprocessorCallback {
/// @notice Handles outputs from the coprocessor
/// @param machineHash The hash of the machine that processed the task
/// @param payloadHash The hash of the input payload that generated these outputs
/// @param outputs Array of ABI-encoded outputs from the coprocessor
function coprocessorCallbackOutputsOnly(bytes32 machineHash, bytes32 payloadHash, bytes[] calldata outputs)
external;
}
17 changes: 17 additions & 0 deletions src/ICoprocessorOutputs.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.28;

/// @title ICoprocessorOutputs Interface
/// @notice Defines the outputs that can be generated by a coprocessor
interface ICoprocessorOutputs {
/// @notice Emits a notice event with the given payload
/// @param payload The ABI-encoded payload containing notice data
function Notice(bytes calldata payload) external;

/// @notice Issues a voucher to execute a specific action
/// @param destination The address to which the voucher is directed
/// @param value The amount of ETH to transfer with the voucher
/// @param payload The ABI-encoded payload containing the action data
function Voucher(address destination, uint256 value, bytes calldata payload) external;
}
52 changes: 52 additions & 0 deletions src/library/LibAddress.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.28;

import {LibError} from "../library/LibError.sol";

library LibAddress {
using LibError for bytes;

/// @notice Perform a low level call and raise error if failed
/// @param destination The address that will be called
/// @param value The amount of Wei to be transferred through the call
/// @param payload The payload, which—in the case of Solidity
/// contracts—encodes a function call
/// @return Whether the caller had enough Ether to make the call,
/// and the balance before the call
function safeCall(address destination, uint256 value, bytes memory payload) internal returns (bool, uint256) {
address caller = address(this);
uint256 balance = caller.balance;

if (value > balance) {
return (false, balance);
}

bool success;
bytes memory returndata;

(success, returndata) = destination.call{value: value}(payload);

if (!success) {
returndata.raise();
}

return (true, balance);
}

/// @notice Perform a delegate call and raise error if failed
/// @param destination The address that will be called
/// @param payload The payload, which—in the case of Solidity
/// libraries—encodes a function call
function safeDelegateCall(address destination, bytes memory payload) internal {
bool success;
bytes memory returndata;

(success, returndata) = destination.delegatecall(payload);

if (!success) {
returndata.raise();
}
}
}
18 changes: 18 additions & 0 deletions src/library/LibError.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)

pragma solidity ^0.8.28;

library LibError {
/// @notice Raise error data
/// @param errordata Data returned by failed low-level call
function raise(bytes memory errordata) internal pure {
if (errordata.length == 0) {
revert();
} else {
assembly {
revert(add(32, errordata), mload(errordata))
}
}
}
}
Loading

0 comments on commit 0710d93

Please sign in to comment.