diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a27e723d..0d7e8b79 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -35,6 +35,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + submodules: recursive - name: Install Golang uses: actions/setup-go@v5 with: diff --git a/rvgo/bindings/riscv.go b/rvgo/bindings/riscv.go index a8c815f1..6be82cbe 100644 --- a/rvgo/bindings/riscv.go +++ b/rvgo/bindings/riscv.go @@ -31,7 +31,7 @@ var ( // RISCVMetaData contains all meta data concerning the RISCV contract. var RISCVMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_oracle\",\"type\":\"address\",\"internalType\":\"contractIPreimageOracle\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"oracle\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPreimageOracle\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"step\",\"inputs\":[{\"name\":\"stateData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"localContext\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_oracle\",\"type\":\"address\",\"internalType\":\"contractIPreimageOracle\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"oracle\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIPreimageOracle\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"step\",\"inputs\":[{\"name\":\"_stateData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_localContext\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"}]", } // RISCVABI is the input ABI used to generate the binding from. @@ -211,23 +211,54 @@ func (_RISCV *RISCVCallerSession) Oracle() (common.Address, error) { return _RISCV.Contract.Oracle(&_RISCV.CallOpts) } +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_RISCV *RISCVCaller) Version(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _RISCV.contract.Call(opts, &out, "version") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_RISCV *RISCVSession) Version() (string, error) { + return _RISCV.Contract.Version(&_RISCV.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_RISCV *RISCVCallerSession) Version() (string, error) { + return _RISCV.Contract.Version(&_RISCV.CallOpts) +} + // Step is a paid mutator transaction binding the contract method 0xe14ced32. // -// Solidity: function step(bytes stateData, bytes proof, bytes32 localContext) returns(bytes32) -func (_RISCV *RISCVTransactor) Step(opts *bind.TransactOpts, stateData []byte, proof []byte, localContext [32]byte) (*types.Transaction, error) { - return _RISCV.contract.Transact(opts, "step", stateData, proof, localContext) +// Solidity: function step(bytes _stateData, bytes _proof, bytes32 _localContext) returns(bytes32) +func (_RISCV *RISCVTransactor) Step(opts *bind.TransactOpts, _stateData []byte, _proof []byte, _localContext [32]byte) (*types.Transaction, error) { + return _RISCV.contract.Transact(opts, "step", _stateData, _proof, _localContext) } // Step is a paid mutator transaction binding the contract method 0xe14ced32. // -// Solidity: function step(bytes stateData, bytes proof, bytes32 localContext) returns(bytes32) -func (_RISCV *RISCVSession) Step(stateData []byte, proof []byte, localContext [32]byte) (*types.Transaction, error) { - return _RISCV.Contract.Step(&_RISCV.TransactOpts, stateData, proof, localContext) +// Solidity: function step(bytes _stateData, bytes _proof, bytes32 _localContext) returns(bytes32) +func (_RISCV *RISCVSession) Step(_stateData []byte, _proof []byte, _localContext [32]byte) (*types.Transaction, error) { + return _RISCV.Contract.Step(&_RISCV.TransactOpts, _stateData, _proof, _localContext) } // Step is a paid mutator transaction binding the contract method 0xe14ced32. // -// Solidity: function step(bytes stateData, bytes proof, bytes32 localContext) returns(bytes32) -func (_RISCV *RISCVTransactorSession) Step(stateData []byte, proof []byte, localContext [32]byte) (*types.Transaction, error) { - return _RISCV.Contract.Step(&_RISCV.TransactOpts, stateData, proof, localContext) +// Solidity: function step(bytes _stateData, bytes _proof, bytes32 _localContext) returns(bytes32) +func (_RISCV *RISCVTransactorSession) Step(_stateData []byte, _proof []byte, _localContext [32]byte) (*types.Transaction, error) { + return _RISCV.Contract.Step(&_RISCV.TransactOpts, _stateData, _proof, _localContext) } diff --git a/rvsol/src/RISCV.sol b/rvsol/src/RISCV.sol index c53d6c75..70be3ebf 100644 --- a/rvsol/src/RISCV.sol +++ b/rvsol/src/RISCV.sol @@ -1,17 +1,29 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.13; +pragma solidity 0.8.15; import { IPreimageOracle } from "@optimism/src/cannon/interfaces/IPreimageOracle.sol"; - -contract RISCV { +import { IBigStepper } from "@optimism/src/dispute/interfaces/IBigStepper.sol"; + +/// @title RISCV +/// @notice The RISCV contract emulates a single RISCV hart cycle statelessly, using memory proofs to verify the +/// instruction and optional memory access' inclusion in the memory merkle root provided in the trusted +/// prestate witness. +/// @dev https://github.com/ethereum-optimism/asterisc +contract RISCV is IBigStepper { + /// @notice The preimage oracle contract. IPreimageOracle public oracle; + /// @notice The version of the contract. + /// @custom:semver 1.1.0-rc.1 + string public constant version = "1.1.0-rc.1"; + + /// @param _oracle The preimage oracle contract. constructor(IPreimageOracle _oracle) { oracle = _oracle; } - // Executes a single RISC-V instruction, starting from - function step(bytes calldata stateData, bytes calldata proof, bytes32 localContext) public returns (bytes32) { + /// @inheritdoc IBigStepper + function step(bytes calldata _stateData, bytes calldata _proof, bytes32 _localContext) public returns (bytes32) { assembly { function revertWithCode(code) { mstore(0, code) @@ -310,11 +322,11 @@ contract RISCV { // expected memory check: no allocated memory (start after scratch + free-mem-ptr + zero slot = 0x80) revert(0, 0) } - if iszero(eq(stateData.offset, 132)) { + if iszero(eq(_stateData.offset, 132)) { // 32*4+4 = 132 expected state data offset revert(0, 0) } - if iszero(eq(calldataload(sub(stateData.offset, 32)), stateSize())) { + if iszero(eq(calldataload(sub(_stateData.offset, 32)), stateSize())) { // user-provided state size must match expected state size revert(0, 0) } @@ -323,7 +335,7 @@ contract RISCV { let padding := mod(sub(32, mod(v, 32)), 32) out := add(v, padding) } - if iszero(eq(proof.offset, add(add(stateData.offset, paddedLen(stateSize())), 32))) { + if iszero(eq(_proof.offset, add(add(_stateData.offset, paddedLen(stateSize())), 32))) { // 132+stateSize+padding+32 = expected proof offset revert(0, 0) } @@ -332,7 +344,7 @@ contract RISCV { // 132+362+(32-362%32)+32=548 out := 548 } - if iszero(eq(proof.offset, proofContentOffset())) { revert(0, 0) } + if iszero(eq(_proof.offset, proofContentOffset())) { revert(0, 0) } // // State loading @@ -342,7 +354,7 @@ contract RISCV { } // copy the state calldata into memory, so we can mutate it mstore(0x40, add(memStateOffset(), stateSize())) // alloc, update free mem pointer - calldatacopy(memStateOffset(), stateData.offset, stateSize()) // same format in memory as in calldata + calldatacopy(memStateOffset(), _stateData.offset, stateSize()) // same format in memory as in calldata // // State access @@ -764,8 +776,7 @@ contract RISCV { // as prefix mstore(add(memPtr, 0x04), key) mstore(add(memPtr, 0x24), offset) - let cgas := 100000 // TODO change call gas - let res := call(cgas, addr, 0, memPtr, 0x44, 0x00, 0x40) // output into scratch space + let res := call(gas(), addr, 0, memPtr, 0x44, 0x00, 0x40) // output into scratch space if res { // 1 on success dat := mload(0x00) @@ -775,7 +786,7 @@ contract RISCV { revertWithCode(0xbadf00d0) } - // Original implementation is at @optimism/src/cannon/PreimageKeyLib.sol + // Original implementation is at src/cannon/PreimageKeyLib.sol // but it cannot be used because this is inside assembly block function localize(preImageKey, localContext_) -> localizedKey { // Grab the current free memory pointer to restore later. @@ -1499,7 +1510,7 @@ contract RISCV { // I-type, top 12 bits case 0 { // imm12 = 000000000000 ECALL - sysCall(localContext) + sysCall(_localContext) setPC(add64(_pc, toU64(4))) } default {