Commit cce7f9c3 authored by mbaxter's avatar mbaxter Committed by GitHub

cannon: Extract MIPS step helper functions (#11017)

* cannon: Extract step helpers

* cannon: Wrap step helper logic in unchecked

* cannon: Use consistent var name between solidity and go (fun)

* cannon: Dedupe `opcode` and `fun` calculations

* cannon: Bump MIPS.sol version

* cannon: Run semver-lock, snapshots

* cannon: Address slither warnings

* cannon: Make sure all lib functions are unchecked
parent 1f64dd6d
...@@ -8,6 +8,8 @@ import ( ...@@ -8,6 +8,8 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
) )
type MemTracker func(addr uint32)
func (m *InstrumentedState) readPreimage(key [32]byte, offset uint32) (dat [32]byte, datLen uint32) { func (m *InstrumentedState) readPreimage(key [32]byte, offset uint32) (dat [32]byte, datLen uint32) {
preimage := m.lastPreimage preimage := m.lastPreimage
if key != m.lastPreimageKey { if key != m.lastPreimageKey {
...@@ -123,117 +125,14 @@ func (m *InstrumentedState) mipsStep() error { ...@@ -123,117 +125,14 @@ func (m *InstrumentedState) mipsStep() error {
} }
m.state.Step += 1 m.state.Step += 1
// instruction fetch // instruction fetch
insn := m.state.Memory.GetMemory(m.state.Cpu.PC) insn, opcode, fun := getInstructionDetails(m.state.Cpu.PC, m.state.Memory)
opcode := insn >> 26 // 6-bits
// j-type j/jal
if opcode == 2 || opcode == 3 {
linkReg := uint32(0)
if opcode == 3 {
linkReg = 31
}
// Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset
target := (m.state.Cpu.NextPC & 0xF0000000) | ((insn & 0x03FFFFFF) << 2)
m.pushStack(target)
return handleJump(&m.state.Cpu, &m.state.Registers, linkReg, target)
}
// register fetch
rs := uint32(0) // source register 1 value
rt := uint32(0) // source register 2 / temp value
rtReg := (insn >> 16) & 0x1F
// R-type or I-type (stores rt)
rs = m.state.Registers[(insn>>21)&0x1F]
rdReg := rtReg
if opcode == 0 || opcode == 0x1c {
// R-type (stores rd)
rt = m.state.Registers[rtReg]
rdReg = (insn >> 11) & 0x1F
} else if opcode < 0x20 {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if opcode == 0xC || opcode == 0xD || opcode == 0xe {
// ZeroExtImm
rt = insn & 0xFFFF
} else {
// SignExtImm
rt = signExtend(insn&0xFFFF, 16)
}
} else if opcode >= 0x28 || opcode == 0x22 || opcode == 0x26 {
// store rt value with store
rt = m.state.Registers[rtReg]
// store actual rt with lwl and lwr
rdReg = rtReg
}
if (opcode >= 4 && opcode < 8) || opcode == 1 {
return handleBranch(&m.state.Cpu, &m.state.Registers, opcode, insn, rtReg, rs)
}
storeAddr := uint32(0xFF_FF_FF_FF)
// memory fetch (all I-type)
// we do the load for stores also
mem := uint32(0)
if opcode >= 0x20 {
// M[R[rs]+SignExtImm]
rs += signExtend(insn&0xFFFF, 16)
addr := rs & 0xFFFFFFFC
m.trackMemAccess(addr)
mem = m.state.Memory.GetMemory(addr)
if opcode >= 0x28 && opcode != 0x30 {
// store
storeAddr = addr
// store opcodes don't write back to a register
rdReg = 0
}
}
// ALU
val := executeMipsInstruction(insn, rs, rt, mem)
fun := insn & 0x3f // 6-bits
if opcode == 0 && fun >= 8 && fun < 0x1c {
if fun == 8 || fun == 9 { // jr/jalr
linkReg := uint32(0)
if fun == 9 {
linkReg = rdReg
}
m.popStack()
return handleJump(&m.state.Cpu, &m.state.Registers, linkReg, rs)
}
if fun == 0xa { // movz
return handleRd(&m.state.Cpu, &m.state.Registers, rdReg, rs, rt == 0)
}
if fun == 0xb { // movn
return handleRd(&m.state.Cpu, &m.state.Registers, rdReg, rs, rt != 0)
}
// Handle syscall separately
// syscall (can read and write) // syscall (can read and write)
if fun == 0xC { if opcode == 0 && fun == 0xC {
return m.handleSyscall() return m.handleSyscall()
} }
// lo and hi registers // Exec the rest of the step logic
// can write back return execMipsCoreStepLogic(&m.state.Cpu, &m.state.Registers, m.state.Memory, insn, opcode, fun, m.trackMemAccess, m)
if fun >= 0x10 && fun < 0x1c {
return handleHiLo(&m.state.Cpu, &m.state.Registers, fun, rs, rt, rdReg)
}
}
// stupid sc, write a 1 to rt
if opcode == 0x38 && rtReg != 0 {
m.state.Registers[rtReg] = 1
}
// write memory
if storeAddr != 0xFF_FF_FF_FF {
m.trackMemAccess(storeAddr)
m.state.Memory.SetMemory(storeAddr, val)
}
// write back the value to destination register
return handleRd(&m.state.Cpu, &m.state.Registers, rdReg, val, true)
} }
package mipsevm package mipsevm
func executeMipsInstruction(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { type StackTracker interface {
opcode := insn >> 26 // 6-bits pushStack(target uint32)
popStack()
}
func getInstructionDetails(pc uint32, memory *Memory) (insn, opcode, fun uint32) {
insn = memory.GetMemory(pc)
opcode = insn >> 26 // First 6-bits
fun = insn & 0x3f // Last 6-bits
return insn, opcode, fun
}
func execMipsCoreStepLogic(cpu *CpuScalars, registers *[32]uint32, memory *Memory, insn, opcode, fun uint32, memTracker MemTracker, stackTracker StackTracker) error {
// j-type j/jal
if opcode == 2 || opcode == 3 {
linkReg := uint32(0)
if opcode == 3 {
linkReg = 31
}
// Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset
target := (cpu.NextPC & 0xF0000000) | ((insn & 0x03FFFFFF) << 2)
stackTracker.pushStack(target)
return handleJump(cpu, registers, linkReg, target)
}
// register fetch
rs := uint32(0) // source register 1 value
rt := uint32(0) // source register 2 / temp value
rtReg := (insn >> 16) & 0x1F
// R-type or I-type (stores rt)
rs = registers[(insn>>21)&0x1F]
rdReg := rtReg
if opcode == 0 || opcode == 0x1c {
// R-type (stores rd)
rt = registers[rtReg]
rdReg = (insn >> 11) & 0x1F
} else if opcode < 0x20 {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if opcode == 0xC || opcode == 0xD || opcode == 0xe {
// ZeroExtImm
rt = insn & 0xFFFF
} else {
// SignExtImm
rt = signExtend(insn&0xFFFF, 16)
}
} else if opcode >= 0x28 || opcode == 0x22 || opcode == 0x26 {
// store rt value with store
rt = registers[rtReg]
// store actual rt with lwl and lwr
rdReg = rtReg
}
if (opcode >= 4 && opcode < 8) || opcode == 1 {
return handleBranch(cpu, registers, opcode, insn, rtReg, rs)
}
storeAddr := uint32(0xFF_FF_FF_FF)
// memory fetch (all I-type)
// we do the load for stores also
mem := uint32(0)
if opcode >= 0x20 {
// M[R[rs]+SignExtImm]
rs += signExtend(insn&0xFFFF, 16)
addr := rs & 0xFFFFFFFC
memTracker(addr)
mem = memory.GetMemory(addr)
if opcode >= 0x28 && opcode != 0x30 {
// store
storeAddr = addr
// store opcodes don't write back to a register
rdReg = 0
}
}
// ALU
val := executeMipsInstruction(insn, opcode, fun, rs, rt, mem)
if opcode == 0 && fun >= 8 && fun < 0x1c {
if fun == 8 || fun == 9 { // jr/jalr
linkReg := uint32(0)
if fun == 9 {
linkReg = rdReg
}
stackTracker.popStack()
return handleJump(cpu, registers, linkReg, rs)
}
if fun == 0xa { // movz
return handleRd(cpu, registers, rdReg, rs, rt == 0)
}
if fun == 0xb { // movn
return handleRd(cpu, registers, rdReg, rs, rt != 0)
}
// lo and hi registers
// can write back
if fun >= 0x10 && fun < 0x1c {
return handleHiLo(cpu, registers, fun, rs, rt, rdReg)
}
}
// store conditional, write a 1 to rt
if opcode == 0x38 && rtReg != 0 {
registers[rtReg] = 1
}
// write memory
if storeAddr != 0xFF_FF_FF_FF {
memTracker(storeAddr)
memory.SetMemory(storeAddr, val)
}
// write back the value to destination register
return handleRd(cpu, registers, rdReg, val, true)
}
func executeMipsInstruction(insn, opcode, fun, rs, rt, mem uint32) uint32 {
if opcode == 0 || (opcode >= 8 && opcode < 0xF) { if opcode == 0 || (opcode >= 8 && opcode < 0xF) {
fun := insn & 0x3f // 6-bits
// transform ArithLogI to SPECIAL // transform ArithLogI to SPECIAL
switch opcode { switch opcode {
case 8: case 8:
...@@ -101,7 +218,6 @@ func executeMipsInstruction(insn uint32, rs uint32, rt uint32, mem uint32) uint3 ...@@ -101,7 +218,6 @@ func executeMipsInstruction(insn uint32, rs uint32, rt uint32, mem uint32) uint3
switch opcode { switch opcode {
// SPECIAL2 // SPECIAL2
case 0x1C: case 0x1C:
fun := insn & 0x3f // 6-bits
switch fun { switch fun {
case 0x2: // mul case 0x2: // mul
return uint32(int32(rs) * int32(rt)) return uint32(int32(rs) * int32(rt))
......
...@@ -34,7 +34,6 @@ const ( ...@@ -34,7 +34,6 @@ const (
) )
type PreimageReader func(key [32]byte, offset uint32) (dat [32]byte, datLen uint32) type PreimageReader func(key [32]byte, offset uint32) (dat [32]byte, datLen uint32)
type MemTracker func(addr uint32)
func getSyscallArgs(registers *[32]uint32) (syscallNum, a0, a1, a2 uint32) { func getSyscallArgs(registers *[32]uint32) (syscallNum, a0, a1, a2 uint32) {
syscallNum = registers[2] // v0 syscallNum = registers[2] // v0
......
...@@ -124,8 +124,8 @@ ...@@ -124,8 +124,8 @@
"sourceCodeHash": "0x3ff4a3f21202478935412d47fd5ef7f94a170402ddc50e5c062013ce5544c83f" "sourceCodeHash": "0x3ff4a3f21202478935412d47fd5ef7f94a170402ddc50e5c062013ce5544c83f"
}, },
"src/cannon/MIPS.sol": { "src/cannon/MIPS.sol": {
"initCodeHash": "0xe9183ee3b69d9ec9594d6b3923d78c86c996cd738ccbc09675bb281284c060af", "initCodeHash": "0xe2cfbfa5d8587a6c3cf52686e29fb0d07e2764af0ef728825529f42ebdeacb5d",
"sourceCodeHash": "0x7c2eab73da8b2eeadba30eadb39f20e91307bc29218938fadfc5f73fadcf13bc" "sourceCodeHash": "0x231f42a05f0c8e5784eb112518afca0bb16a3689f317ce021b8390a0aa70377b"
}, },
"src/cannon/PreimageOracle.sol": { "src/cannon/PreimageOracle.sol": {
"initCodeHash": "0xe5db668fe41436f53995e910488c7c140766ba8745e19743773ebab508efd090", "initCodeHash": "0xe5db668fe41436f53995e910488c7c140766ba8745e19743773ebab508efd090",
......
...@@ -48,7 +48,7 @@ contract MIPS is ISemver { ...@@ -48,7 +48,7 @@ contract MIPS is ISemver {
/// @notice The semantic version of the MIPS contract. /// @notice The semantic version of the MIPS contract.
/// @custom:semver 1.0.1 /// @custom:semver 1.0.1
string public constant version = "1.1.0-beta.4"; string public constant version = "1.1.0-beta.5";
/// @notice The preimage oracle contract. /// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE; IPreimageOracle internal immutable ORACLE;
...@@ -262,178 +262,30 @@ contract MIPS is ISemver { ...@@ -262,178 +262,30 @@ contract MIPS is ISemver {
// instruction fetch // instruction fetch
uint256 insnProofOffset = MIPSMemory.memoryProofOffset(STEP_PROOF_OFFSET, 0); uint256 insnProofOffset = MIPSMemory.memoryProofOffset(STEP_PROOF_OFFSET, 0);
uint32 insn = MIPSMemory.readMem(state.memRoot, state.pc, insnProofOffset); (uint32 insn, uint32 opcode, uint32 fun) =
uint32 opcode = insn >> 26; // 6-bits ins.getInstructionDetails(state.pc, state.memRoot, insnProofOffset);
// j-type j/jal
if (opcode == 2 || opcode == 3) {
// Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset
uint32 target = (state.nextPC & 0xF0000000) | (insn & 0x03FFFFFF) << 2;
return handleJumpAndReturnOutput(state, opcode == 2 ? 0 : 31, target);
}
// register fetch
uint32 rs; // source register 1 value
uint32 rt; // source register 2 / temp value
uint32 rtReg = (insn >> 16) & 0x1F;
// R-type or I-type (stores rt)
rs = state.registers[(insn >> 21) & 0x1F];
uint32 rdReg = rtReg;
if (opcode == 0 || opcode == 0x1c) {
// R-type (stores rd)
rt = state.registers[rtReg];
rdReg = (insn >> 11) & 0x1F;
} else if (opcode < 0x20) {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if (opcode == 0xC || opcode == 0xD || opcode == 0xe) {
// ZeroExtImm
rt = insn & 0xFFFF;
} else {
// SignExtImm
rt = ins.signExtend(insn & 0xFFFF, 16);
}
} else if (opcode >= 0x28 || opcode == 0x22 || opcode == 0x26) {
// store rt value with store
rt = state.registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
if ((opcode >= 4 && opcode < 8) || opcode == 1) {
st.CpuScalars memory cpu = getCpuScalars(state);
ins.handleBranch({
_cpu: cpu,
_registers: state.registers,
_opcode: opcode,
_insn: insn,
_rtReg: rtReg,
_rs: rs
});
setStateCpuScalars(state, cpu);
return outputState();
}
uint32 storeAddr = 0xFF_FF_FF_FF;
// memory fetch (all I-type)
// we do the load for stores also
uint32 mem;
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm]
rs += ins.signExtend(insn & 0xFFFF, 16);
uint32 addr = rs & 0xFFFFFFFC;
uint256 memProofOffset = MIPSMemory.memoryProofOffset(STEP_PROOF_OFFSET, 1);
mem = MIPSMemory.readMem(state.memRoot, addr, memProofOffset);
if (opcode >= 0x28 && opcode != 0x30) {
// store
storeAddr = addr;
// store opcodes don't write back to a register
rdReg = 0;
}
}
// ALU
// Note: swr outputs more than 4 bytes without the mask 0xffFFffFF
uint32 val = ins.executeMipsInstruction(insn, rs, rt, mem) & 0xffFFffFF;
uint32 func = insn & 0x3f; // 6-bits
if (opcode == 0 && func >= 8 && func < 0x1c) {
if (func == 8 || func == 9) {
// jr/jalr
return handleJumpAndReturnOutput(state, func == 8 ? 0 : rdReg, rs);
}
if (func == 0xa) {
// movz
return handleRdAndReturnOutput(state, rdReg, rs, rt == 0);
}
if (func == 0xb) {
// movn
return handleRdAndReturnOutput(state, rdReg, rs, rt != 0);
}
// Handle syscall separately
// syscall (can read and write) // syscall (can read and write)
if (func == 0xC) { if (opcode == 0 && fun == 0xC) {
return handleSyscall(_localContext); return handleSyscall(_localContext);
} }
// lo and hi registers // Exec the rest of the step logic
// can write back
if (func >= 0x10 && func < 0x1c) {
st.CpuScalars memory cpu = getCpuScalars(state); st.CpuScalars memory cpu = getCpuScalars(state);
(state.memRoot) = ins.execMipsCoreStepLogic({
ins.handleHiLo({
_cpu: cpu, _cpu: cpu,
_registers: state.registers, _registers: state.registers,
_func: func, _memRoot: state.memRoot,
_rs: rs, _memProofOffset: MIPSMemory.memoryProofOffset(STEP_PROOF_OFFSET, 1),
_rt: rt, _insn: insn,
_storeReg: rdReg _opcode: opcode,
_fun: fun
}); });
setStateCpuScalars(state, cpu); setStateCpuScalars(state, cpu);
return outputState();
}
}
// stupid sc, write a 1 to rt
if (opcode == 0x38 && rtReg != 0) {
state.registers[rtReg] = 1;
}
// write memory
if (storeAddr != 0xFF_FF_FF_FF) {
uint256 memProofOffset = MIPSMemory.memoryProofOffset(STEP_PROOF_OFFSET, 1);
state.memRoot = MIPSMemory.writeMem(storeAddr, memProofOffset, val);
}
// write back the value to destination register
return handleRdAndReturnOutput(state, rdReg, val, true);
}
}
function handleJumpAndReturnOutput(
State memory _state,
uint32 _linkReg,
uint32 _dest
)
internal
returns (bytes32 out_)
{
st.CpuScalars memory cpu = getCpuScalars(_state);
ins.handleJump({ _cpu: cpu, _registers: _state.registers, _linkReg: _linkReg, _dest: _dest });
setStateCpuScalars(_state, cpu);
return outputState(); return outputState();
} }
function handleRdAndReturnOutput(
State memory _state,
uint32 _storeReg,
uint32 _val,
bool _conditional
)
internal
returns (bytes32 out_)
{
st.CpuScalars memory cpu = getCpuScalars(_state);
ins.handleRd({
_cpu: cpu,
_registers: _state.registers,
_storeReg: _storeReg,
_val: _val,
_conditional: _conditional
});
setStateCpuScalars(_state, cpu);
return outputState();
} }
function getCpuScalars(State memory _state) internal pure returns (st.CpuScalars memory) { function getCpuScalars(State memory _state) internal pure returns (st.CpuScalars memory) {
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { MIPSMemory } from "src/cannon/libraries/MIPSMemory.sol";
import { MIPSState as st } from "src/cannon/libraries/MIPSState.sol"; import { MIPSState as st } from "src/cannon/libraries/MIPSState.sol";
library MIPSInstructions { library MIPSInstructions {
/// @param _pc The program counter.
/// @param _memRoot The current memory root.
/// @param _insnProofOffset The calldata offset of the memory proof for the current instruction.
/// @return insn_ The current 32-bit instruction at the pc.
/// @return opcode_ The opcode value parsed from insn_.
/// @return fun_ The function value parsed from insn_.
function getInstructionDetails(
uint32 _pc,
bytes32 _memRoot,
uint256 _insnProofOffset
)
internal
pure
returns (uint32 insn_, uint32 opcode_, uint32 fun_)
{
unchecked {
insn_ = MIPSMemory.readMem(_memRoot, _pc, _insnProofOffset);
opcode_ = insn_ >> 26; // First 6-bits
fun_ = insn_ & 0x3f; // Last 6-bits
return (insn_, opcode_, fun_);
}
}
/// @notice Execute core MIPS step logic.
/// @notice _cpu The CPU scalar fields.
/// @notice _registers The CPU registers.
/// @notice _memRoot The current merkle root of the memory.
/// @notice _memProofOffset The offset in calldata specify where the memory merkle proof is located.
/// @param _insn The current 32-bit instruction at the pc.
/// @param _opcode The opcode value parsed from insn_.
/// @param _fun The function value parsed from insn_.
/// @return newMemRoot_ The updated merkle root of memory after any modifications, may be unchanged.
function execMipsCoreStepLogic(
st.CpuScalars memory _cpu,
uint32[32] memory _registers,
bytes32 _memRoot,
uint256 _memProofOffset,
uint32 _insn,
uint32 _opcode,
uint32 _fun
)
internal
pure
returns (bytes32 newMemRoot_)
{
unchecked {
newMemRoot_ = _memRoot;
// j-type j/jal
if (_opcode == 2 || _opcode == 3) {
// Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset
uint32 target = (_cpu.nextPC & 0xF0000000) | (_insn & 0x03FFFFFF) << 2;
handleJump(_cpu, _registers, _opcode == 2 ? 0 : 31, target);
return newMemRoot_;
}
// register fetch
uint32 rs = 0; // source register 1 value
uint32 rt = 0; // source register 2 / temp value
uint32 rtReg = (_insn >> 16) & 0x1F;
// R-type or I-type (stores rt)
rs = _registers[(_insn >> 21) & 0x1F];
uint32 rdReg = rtReg;
if (_opcode == 0 || _opcode == 0x1c) {
// R-type (stores rd)
rt = _registers[rtReg];
rdReg = (_insn >> 11) & 0x1F;
} else if (_opcode < 0x20) {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if (_opcode == 0xC || _opcode == 0xD || _opcode == 0xe) {
// ZeroExtImm
rt = _insn & 0xFFFF;
} else {
// SignExtImm
rt = signExtend(_insn & 0xFFFF, 16);
}
} else if (_opcode >= 0x28 || _opcode == 0x22 || _opcode == 0x26) {
// store rt value with store
rt = _registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
if ((_opcode >= 4 && _opcode < 8) || _opcode == 1) {
handleBranch({
_cpu: _cpu,
_registers: _registers,
_opcode: _opcode,
_insn: _insn,
_rtReg: rtReg,
_rs: rs
});
return newMemRoot_;
}
uint32 storeAddr = 0xFF_FF_FF_FF;
// memory fetch (all I-type)
// we do the load for stores also
uint32 mem = 0;
if (_opcode >= 0x20) {
// M[R[rs]+SignExtImm]
rs += signExtend(_insn & 0xFFFF, 16);
uint32 addr = rs & 0xFFFFFFFC;
mem = MIPSMemory.readMem(_memRoot, addr, _memProofOffset);
if (_opcode >= 0x28 && _opcode != 0x30) {
// store
storeAddr = addr;
// store opcodes don't write back to a register
rdReg = 0;
}
}
// ALU
// Note: swr outputs more than 4 bytes without the mask 0xffFFffFF
uint32 val = executeMipsInstruction(_insn, _opcode, _fun, rs, rt, mem) & 0xffFFffFF;
if (_opcode == 0 && _fun >= 8 && _fun < 0x1c) {
if (_fun == 8 || _fun == 9) {
// jr/jalr
handleJump(_cpu, _registers, _fun == 8 ? 0 : rdReg, rs);
return newMemRoot_;
}
if (_fun == 0xa) {
// movz
handleRd(_cpu, _registers, rdReg, rs, rt == 0);
return newMemRoot_;
}
if (_fun == 0xb) {
// movn
handleRd(_cpu, _registers, rdReg, rs, rt != 0);
return newMemRoot_;
}
// lo and hi registers
// can write back
if (_fun >= 0x10 && _fun < 0x1c) {
handleHiLo({ _cpu: _cpu, _registers: _registers, _fun: _fun, _rs: rs, _rt: rt, _storeReg: rdReg });
return newMemRoot_;
}
}
// stupid sc, write a 1 to rt
if (_opcode == 0x38 && rtReg != 0) {
_registers[rtReg] = 1;
}
// write memory
if (storeAddr != 0xFF_FF_FF_FF) {
newMemRoot_ = MIPSMemory.writeMem(storeAddr, _memProofOffset, val);
}
// write back the value to destination register
handleRd(_cpu, _registers, rdReg, val, true);
return newMemRoot_;
}
}
/// @notice Execute an instruction. /// @notice Execute an instruction.
function executeMipsInstruction( function executeMipsInstruction(
uint32 _insn, uint32 _insn,
uint32 _opcode,
uint32 _fun,
uint32 _rs, uint32 _rs,
uint32 _rt, uint32 _rt,
uint32 _mem uint32 _mem
...@@ -16,167 +184,163 @@ library MIPSInstructions { ...@@ -16,167 +184,163 @@ library MIPSInstructions {
returns (uint32 out_) returns (uint32 out_)
{ {
unchecked { unchecked {
uint32 opcode = _insn >> 26; // 6-bits if (_opcode == 0 || (_opcode >= 8 && _opcode < 0xF)) {
if (opcode == 0 || (opcode >= 8 && opcode < 0xF)) {
uint32 func = _insn & 0x3f; // 6-bits
assembly { assembly {
// transform ArithLogI to SPECIAL // transform ArithLogI to SPECIAL
switch opcode switch _opcode
// addi // addi
case 0x8 { func := 0x20 } case 0x8 { _fun := 0x20 }
// addiu // addiu
case 0x9 { func := 0x21 } case 0x9 { _fun := 0x21 }
// stli // stli
case 0xA { func := 0x2A } case 0xA { _fun := 0x2A }
// sltiu // sltiu
case 0xB { func := 0x2B } case 0xB { _fun := 0x2B }
// andi // andi
case 0xC { func := 0x24 } case 0xC { _fun := 0x24 }
// ori // ori
case 0xD { func := 0x25 } case 0xD { _fun := 0x25 }
// xori // xori
case 0xE { func := 0x26 } case 0xE { _fun := 0x26 }
} }
// sll // sll
if (func == 0x00) { if (_fun == 0x00) {
return _rt << ((_insn >> 6) & 0x1F); return _rt << ((_insn >> 6) & 0x1F);
} }
// srl // srl
else if (func == 0x02) { else if (_fun == 0x02) {
return _rt >> ((_insn >> 6) & 0x1F); return _rt >> ((_insn >> 6) & 0x1F);
} }
// sra // sra
else if (func == 0x03) { else if (_fun == 0x03) {
uint32 shamt = (_insn >> 6) & 0x1F; uint32 shamt = (_insn >> 6) & 0x1F;
return signExtend(_rt >> shamt, 32 - shamt); return signExtend(_rt >> shamt, 32 - shamt);
} }
// sllv // sllv
else if (func == 0x04) { else if (_fun == 0x04) {
return _rt << (_rs & 0x1F); return _rt << (_rs & 0x1F);
} }
// srlv // srlv
else if (func == 0x6) { else if (_fun == 0x6) {
return _rt >> (_rs & 0x1F); return _rt >> (_rs & 0x1F);
} }
// srav // srav
else if (func == 0x07) { else if (_fun == 0x07) {
return signExtend(_rt >> _rs, 32 - _rs); return signExtend(_rt >> _rs, 32 - _rs);
} }
// functs in range [0x8, 0x1b] are handled specially by other functions // functs in range [0x8, 0x1b] are handled specially by other functions
// Explicitly enumerate each funct in range to reduce code diff against Go Vm // Explicitly enumerate each funct in range to reduce code diff against Go Vm
// jr // jr
else if (func == 0x08) { else if (_fun == 0x08) {
return _rs; return _rs;
} }
// jalr // jalr
else if (func == 0x09) { else if (_fun == 0x09) {
return _rs; return _rs;
} }
// movz // movz
else if (func == 0x0a) { else if (_fun == 0x0a) {
return _rs; return _rs;
} }
// movn // movn
else if (func == 0x0b) { else if (_fun == 0x0b) {
return _rs; return _rs;
} }
// syscall // syscall
else if (func == 0x0c) { else if (_fun == 0x0c) {
return _rs; return _rs;
} }
// 0x0d - break not supported // 0x0d - break not supported
// sync // sync
else if (func == 0x0f) { else if (_fun == 0x0f) {
return _rs; return _rs;
} }
// mfhi // mfhi
else if (func == 0x10) { else if (_fun == 0x10) {
return _rs; return _rs;
} }
// mthi // mthi
else if (func == 0x11) { else if (_fun == 0x11) {
return _rs; return _rs;
} }
// mflo // mflo
else if (func == 0x12) { else if (_fun == 0x12) {
return _rs; return _rs;
} }
// mtlo // mtlo
else if (func == 0x13) { else if (_fun == 0x13) {
return _rs; return _rs;
} }
// mult // mult
else if (func == 0x18) { else if (_fun == 0x18) {
return _rs; return _rs;
} }
// multu // multu
else if (func == 0x19) { else if (_fun == 0x19) {
return _rs; return _rs;
} }
// div // div
else if (func == 0x1a) { else if (_fun == 0x1a) {
return _rs; return _rs;
} }
// divu // divu
else if (func == 0x1b) { else if (_fun == 0x1b) {
return _rs; return _rs;
} }
// The rest includes transformed R-type arith imm instructions // The rest includes transformed R-type arith imm instructions
// add // add
else if (func == 0x20) { else if (_fun == 0x20) {
return (_rs + _rt); return (_rs + _rt);
} }
// addu // addu
else if (func == 0x21) { else if (_fun == 0x21) {
return (_rs + _rt); return (_rs + _rt);
} }
// sub // sub
else if (func == 0x22) { else if (_fun == 0x22) {
return (_rs - _rt); return (_rs - _rt);
} }
// subu // subu
else if (func == 0x23) { else if (_fun == 0x23) {
return (_rs - _rt); return (_rs - _rt);
} }
// and // and
else if (func == 0x24) { else if (_fun == 0x24) {
return (_rs & _rt); return (_rs & _rt);
} }
// or // or
else if (func == 0x25) { else if (_fun == 0x25) {
return (_rs | _rt); return (_rs | _rt);
} }
// xor // xor
else if (func == 0x26) { else if (_fun == 0x26) {
return (_rs ^ _rt); return (_rs ^ _rt);
} }
// nor // nor
else if (func == 0x27) { else if (_fun == 0x27) {
return ~(_rs | _rt); return ~(_rs | _rt);
} }
// slti // slti
else if (func == 0x2a) { else if (_fun == 0x2a) {
return int32(_rs) < int32(_rt) ? 1 : 0; return int32(_rs) < int32(_rt) ? 1 : 0;
} }
// sltiu // sltiu
else if (func == 0x2b) { else if (_fun == 0x2b) {
return _rs < _rt ? 1 : 0; return _rs < _rt ? 1 : 0;
} else { } else {
revert("invalid instruction"); revert("invalid instruction");
} }
} else { } else {
// SPECIAL2 // SPECIAL2
if (opcode == 0x1C) { if (_opcode == 0x1C) {
uint32 func = _insn & 0x3f; // 6-bits
// mul // mul
if (func == 0x2) { if (_fun == 0x2) {
return uint32(int32(_rs) * int32(_rt)); return uint32(int32(_rs) * int32(_rt));
} }
// clz, clo // clz, clo
else if (func == 0x20 || func == 0x21) { else if (_fun == 0x20 || _fun == 0x21) {
if (func == 0x20) { if (_fun == 0x20) {
_rs = ~_rs; _rs = ~_rs;
} }
uint32 i = 0; uint32 i = 0;
...@@ -188,75 +352,75 @@ library MIPSInstructions { ...@@ -188,75 +352,75 @@ library MIPSInstructions {
} }
} }
// lui // lui
else if (opcode == 0x0F) { else if (_opcode == 0x0F) {
return _rt << 16; return _rt << 16;
} }
// lb // lb
else if (opcode == 0x20) { else if (_opcode == 0x20) {
return signExtend((_mem >> (24 - (_rs & 3) * 8)) & 0xFF, 8); return signExtend((_mem >> (24 - (_rs & 3) * 8)) & 0xFF, 8);
} }
// lh // lh
else if (opcode == 0x21) { else if (_opcode == 0x21) {
return signExtend((_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF, 16); return signExtend((_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF, 16);
} }
// lwl // lwl
else if (opcode == 0x22) { else if (_opcode == 0x22) {
uint32 val = _mem << ((_rs & 3) * 8); uint32 val = _mem << ((_rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) << ((_rs & 3) * 8); uint32 mask = uint32(0xFFFFFFFF) << ((_rs & 3) * 8);
return (_rt & ~mask) | val; return (_rt & ~mask) | val;
} }
// lw // lw
else if (opcode == 0x23) { else if (_opcode == 0x23) {
return _mem; return _mem;
} }
// lbu // lbu
else if (opcode == 0x24) { else if (_opcode == 0x24) {
return (_mem >> (24 - (_rs & 3) * 8)) & 0xFF; return (_mem >> (24 - (_rs & 3) * 8)) & 0xFF;
} }
// lhu // lhu
else if (opcode == 0x25) { else if (_opcode == 0x25) {
return (_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF; return (_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF;
} }
// lwr // lwr
else if (opcode == 0x26) { else if (_opcode == 0x26) {
uint32 val = _mem >> (24 - (_rs & 3) * 8); uint32 val = _mem >> (24 - (_rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) >> (24 - (_rs & 3) * 8); uint32 mask = uint32(0xFFFFFFFF) >> (24 - (_rs & 3) * 8);
return (_rt & ~mask) | val; return (_rt & ~mask) | val;
} }
// sb // sb
else if (opcode == 0x28) { else if (_opcode == 0x28) {
uint32 val = (_rt & 0xFF) << (24 - (_rs & 3) * 8); uint32 val = (_rt & 0xFF) << (24 - (_rs & 3) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (_rs & 3) * 8)); uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (_rs & 3) * 8));
return (_mem & mask) | val; return (_mem & mask) | val;
} }
// sh // sh
else if (opcode == 0x29) { else if (_opcode == 0x29) {
uint32 val = (_rt & 0xFFFF) << (16 - (_rs & 2) * 8); uint32 val = (_rt & 0xFFFF) << (16 - (_rs & 2) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (_rs & 2) * 8)); uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (_rs & 2) * 8));
return (_mem & mask) | val; return (_mem & mask) | val;
} }
// swl // swl
else if (opcode == 0x2a) { else if (_opcode == 0x2a) {
uint32 val = _rt >> ((_rs & 3) * 8); uint32 val = _rt >> ((_rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) >> ((_rs & 3) * 8); uint32 mask = uint32(0xFFFFFFFF) >> ((_rs & 3) * 8);
return (_mem & ~mask) | val; return (_mem & ~mask) | val;
} }
// sw // sw
else if (opcode == 0x2b) { else if (_opcode == 0x2b) {
return _rt; return _rt;
} }
// swr // swr
else if (opcode == 0x2e) { else if (_opcode == 0x2e) {
uint32 val = _rt << (24 - (_rs & 3) * 8); uint32 val = _rt << (24 - (_rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) << (24 - (_rs & 3) * 8); uint32 mask = uint32(0xFFFFFFFF) << (24 - (_rs & 3) * 8);
return (_mem & ~mask) | val; return (_mem & ~mask) | val;
} }
// ll // ll
else if (opcode == 0x30) { else if (_opcode == 0x30) {
return _mem; return _mem;
} }
// sc // sc
else if (opcode == 0x38) { else if (_opcode == 0x38) {
return _rt; return _rt;
} else { } else {
revert("invalid instruction"); revert("invalid instruction");
...@@ -345,14 +509,14 @@ library MIPSInstructions { ...@@ -345,14 +509,14 @@ library MIPSInstructions {
/// @notice Handles HI and LO register instructions. /// @notice Handles HI and LO register instructions.
/// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo. /// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo.
/// @param _registers Holds the current state of the cpu registers. /// @param _registers Holds the current state of the cpu registers.
/// @param _func The function code of the instruction. /// @param _fun The function code of the instruction.
/// @param _rs The value of the RS register. /// @param _rs The value of the RS register.
/// @param _rt The value of the RT register. /// @param _rt The value of the RT register.
/// @param _storeReg The register to store the result in. /// @param _storeReg The register to store the result in.
function handleHiLo( function handleHiLo(
st.CpuScalars memory _cpu, st.CpuScalars memory _cpu,
uint32[32] memory _registers, uint32[32] memory _registers,
uint32 _func, uint32 _fun,
uint32 _rs, uint32 _rs,
uint32 _rt, uint32 _rt,
uint32 _storeReg uint32 _storeReg
...@@ -364,29 +528,29 @@ library MIPSInstructions { ...@@ -364,29 +528,29 @@ library MIPSInstructions {
uint32 val = 0; uint32 val = 0;
// mfhi: Move the contents of the HI register into the destination // mfhi: Move the contents of the HI register into the destination
if (_func == 0x10) { if (_fun == 0x10) {
val = _cpu.hi; val = _cpu.hi;
} }
// mthi: Move the contents of the source into the HI register // mthi: Move the contents of the source into the HI register
else if (_func == 0x11) { else if (_fun == 0x11) {
_cpu.hi = _rs; _cpu.hi = _rs;
} }
// mflo: Move the contents of the LO register into the destination // mflo: Move the contents of the LO register into the destination
else if (_func == 0x12) { else if (_fun == 0x12) {
val = _cpu.lo; val = _cpu.lo;
} }
// mtlo: Move the contents of the source into the LO register // mtlo: Move the contents of the source into the LO register
else if (_func == 0x13) { else if (_fun == 0x13) {
_cpu.lo = _rs; _cpu.lo = _rs;
} }
// mult: Multiplies `rs` by `rt` and stores the result in HI and LO registers // mult: Multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_func == 0x18) { else if (_fun == 0x18) {
uint64 acc = uint64(int64(int32(_rs)) * int64(int32(_rt))); uint64 acc = uint64(int64(int32(_rs)) * int64(int32(_rt)));
_cpu.hi = uint32(acc >> 32); _cpu.hi = uint32(acc >> 32);
_cpu.lo = uint32(acc); _cpu.lo = uint32(acc);
} }
// multu: Unsigned multiplies `rs` by `rt` and stores the result in HI and LO registers // multu: Unsigned multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_func == 0x19) { else if (_fun == 0x19) {
uint64 acc = uint64(uint64(_rs) * uint64(_rt)); uint64 acc = uint64(uint64(_rs) * uint64(_rt));
_cpu.hi = uint32(acc >> 32); _cpu.hi = uint32(acc >> 32);
_cpu.lo = uint32(acc); _cpu.lo = uint32(acc);
...@@ -394,7 +558,7 @@ library MIPSInstructions { ...@@ -394,7 +558,7 @@ library MIPSInstructions {
// div: Divides `rs` by `rt`. // div: Divides `rs` by `rt`.
// Stores the quotient in LO // Stores the quotient in LO
// And the remainder in HI // And the remainder in HI
else if (_func == 0x1a) { else if (_fun == 0x1a) {
if (int32(_rt) == 0) { if (int32(_rt) == 0) {
revert("MIPS: division by zero"); revert("MIPS: division by zero");
} }
...@@ -404,7 +568,7 @@ library MIPSInstructions { ...@@ -404,7 +568,7 @@ library MIPSInstructions {
// divu: Unsigned divides `rs` by `rt`. // divu: Unsigned divides `rs` by `rt`.
// Stores the quotient in LO // Stores the quotient in LO
// And the remainder in HI // And the remainder in HI
else if (_func == 0x1b) { else if (_fun == 0x1b) {
if (_rt == 0) { if (_rt == 0) {
revert("MIPS: division by zero"); revert("MIPS: division by zero");
} }
......
...@@ -93,9 +93,9 @@ library MIPSMemory { ...@@ -93,9 +93,9 @@ library MIPSMemory {
newMemRoot_ := node newMemRoot_ := node
} }
}
return newMemRoot_; return newMemRoot_;
} }
}
/// @notice Computes the offset of a memory proof in the calldata. /// @notice Computes the offset of a memory proof in the calldata.
/// @param _proofDataOffset The offset of the set of all memory proof data within calldata (proof.offset) /// @param _proofDataOffset The offset of the set of all memory proof data within calldata (proof.offset)
...@@ -114,6 +114,7 @@ library MIPSMemory { ...@@ -114,6 +114,7 @@ library MIPSMemory {
/// @notice Validates that enough calldata is available to hold a full memory proof at the given offset /// @notice Validates that enough calldata is available to hold a full memory proof at the given offset
/// @param _proofStartOffset The index of the first byte of the target memory proof in calldata /// @param _proofStartOffset The index of the first byte of the target memory proof in calldata
function validateMemoryProofAvailability(uint256 _proofStartOffset) internal pure { function validateMemoryProofAvailability(uint256 _proofStartOffset) internal pure {
unchecked {
uint256 s = 0; uint256 s = 0;
assembly { assembly {
s := calldatasize() s := calldatasize()
...@@ -121,4 +122,5 @@ library MIPSMemory { ...@@ -121,4 +122,5 @@ library MIPSMemory {
// A memory proof consists of 28 bytes32 values - verify we have enough calldata // A memory proof consists of 28 bytes32 values - verify we have enough calldata
require(s >= (_proofStartOffset + 28 * 32), "check that there is enough calldata"); require(s >= (_proofStartOffset + 28 * 32), "check that there is enough calldata");
} }
}
} }
...@@ -37,6 +37,7 @@ library MIPSSyscalls { ...@@ -37,6 +37,7 @@ library MIPSSyscalls {
pure pure
returns (uint32 sysCallNum_, uint32 a0_, uint32 a1_, uint32 a2_) returns (uint32 sysCallNum_, uint32 a0_, uint32 a1_, uint32 a2_)
{ {
unchecked {
sysCallNum_ = _registers[2]; sysCallNum_ = _registers[2];
a0_ = _registers[4]; a0_ = _registers[4];
...@@ -45,6 +46,7 @@ library MIPSSyscalls { ...@@ -45,6 +46,7 @@ library MIPSSyscalls {
return (sysCallNum_, a0_, a1_, a2_); return (sysCallNum_, a0_, a1_, a2_);
} }
}
/// @notice Like a Linux mmap syscall. Allocates a page from the heap. /// @notice Like a Linux mmap syscall. Allocates a page from the heap.
/// @param _a0 The address for the new mapping /// @param _a0 The address for the new mapping
...@@ -62,6 +64,7 @@ library MIPSSyscalls { ...@@ -62,6 +64,7 @@ library MIPSSyscalls {
pure pure
returns (uint32 v0_, uint32 v1_, uint32 newHeap_) returns (uint32 v0_, uint32 v1_, uint32 newHeap_)
{ {
unchecked {
v1_ = uint32(0); v1_ = uint32(0);
newHeap_ = _heap; newHeap_ = _heap;
...@@ -79,6 +82,7 @@ library MIPSSyscalls { ...@@ -79,6 +82,7 @@ library MIPSSyscalls {
return (v0_, v1_, newHeap_); return (v0_, v1_, newHeap_);
} }
}
/// @notice Like a Linux read syscall. Splits unaligned reads into aligned reads. /// @notice Like a Linux read syscall. Splits unaligned reads into aligned reads.
/// @param _a0 The file descriptor. /// @param _a0 The file descriptor.
...@@ -109,6 +113,7 @@ library MIPSSyscalls { ...@@ -109,6 +113,7 @@ library MIPSSyscalls {
view view
returns (uint32 v0_, uint32 v1_, uint32 newPreimageOffset_, bytes32 newMemRoot_) returns (uint32 v0_, uint32 v1_, uint32 newPreimageOffset_, bytes32 newMemRoot_)
{ {
unchecked {
v0_ = uint32(0); v0_ = uint32(0);
v1_ = uint32(0); v1_ = uint32(0);
newMemRoot_ = _memRoot; newMemRoot_ = _memRoot;
...@@ -164,6 +169,7 @@ library MIPSSyscalls { ...@@ -164,6 +169,7 @@ library MIPSSyscalls {
return (v0_, v1_, newPreimageOffset_, newMemRoot_); return (v0_, v1_, newPreimageOffset_, newMemRoot_);
} }
}
/// @notice Like a Linux write syscall. Splits unaligned writes into aligned writes. /// @notice Like a Linux write syscall. Splits unaligned writes into aligned writes.
/// @param _a0 The file descriptor. /// @param _a0 The file descriptor.
...@@ -190,6 +196,7 @@ library MIPSSyscalls { ...@@ -190,6 +196,7 @@ library MIPSSyscalls {
pure pure
returns (uint32 v0_, uint32 v1_, bytes32 newPreimageKey_, uint32 newPreimageOffset_) returns (uint32 v0_, uint32 v1_, bytes32 newPreimageKey_, uint32 newPreimageOffset_)
{ {
unchecked {
// args: _a0 = fd, _a1 = addr, _a2 = count // args: _a0 = fd, _a1 = addr, _a2 = count
// returns: v0_ = written, v1_ = err code // returns: v0_ = written, v1_ = err code
v0_ = uint32(0); v0_ = uint32(0);
...@@ -229,6 +236,7 @@ library MIPSSyscalls { ...@@ -229,6 +236,7 @@ library MIPSSyscalls {
return (v0_, v1_, newPreimageKey_, newPreimageOffset_); return (v0_, v1_, newPreimageKey_, newPreimageOffset_);
} }
}
/// @notice Like Linux fcntl (file control) syscall, but only supports minimal file-descriptor control commands, to /// @notice Like Linux fcntl (file control) syscall, but only supports minimal file-descriptor control commands, to
/// retrieve the file-descriptor R/W flags. /// retrieve the file-descriptor R/W flags.
...@@ -237,6 +245,7 @@ library MIPSSyscalls { ...@@ -237,6 +245,7 @@ library MIPSSyscalls {
/// @param v0_ The file status flag (only supported command is F_GETFL), or -1 on error. /// @param v0_ The file status flag (only supported command is F_GETFL), or -1 on error.
/// @param v1_ An error number, or 0 if there is no error. /// @param v1_ An error number, or 0 if there is no error.
function handleSysFcntl(uint32 _a0, uint32 _a1) internal pure returns (uint32 v0_, uint32 v1_) { function handleSysFcntl(uint32 _a0, uint32 _a1) internal pure returns (uint32 v0_, uint32 v1_) {
unchecked {
v0_ = uint32(0); v0_ = uint32(0);
v1_ = uint32(0); v1_ = uint32(0);
...@@ -258,6 +267,7 @@ library MIPSSyscalls { ...@@ -258,6 +267,7 @@ library MIPSSyscalls {
return (v0_, v1_); return (v0_, v1_);
} }
}
function handleSyscallUpdates( function handleSyscallUpdates(
st.CpuScalars memory _cpu, st.CpuScalars memory _cpu,
...@@ -268,6 +278,7 @@ library MIPSSyscalls { ...@@ -268,6 +278,7 @@ library MIPSSyscalls {
internal internal
pure pure
{ {
unchecked {
// Write the results back to the state registers // Write the results back to the state registers
_registers[2] = _v0; _registers[2] = _v0;
_registers[7] = _v1; _registers[7] = _v1;
...@@ -276,4 +287,5 @@ library MIPSSyscalls { ...@@ -276,4 +287,5 @@ library MIPSSyscalls {
_cpu.pc = _cpu.nextPC; _cpu.pc = _cpu.nextPC;
_cpu.nextPC = _cpu.nextPC + 4; _cpu.nextPC = _cpu.nextPC + 4;
} }
}
} }
...@@ -25,7 +25,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode { ...@@ -25,7 +25,7 @@ contract DeploymentSummaryFaultProofs is DeploymentSummaryFaultProofsCode {
address internal constant l1ERC721BridgeProxyAddress = 0xD31598c909d9C935a9e35bA70d9a3DD47d4D5865; address internal constant l1ERC721BridgeProxyAddress = 0xD31598c909d9C935a9e35bA70d9a3DD47d4D5865;
address internal constant l1StandardBridgeAddress = 0xb7900B27Be8f0E0fF65d1C3A4671e1220437dd2b; address internal constant l1StandardBridgeAddress = 0xb7900B27Be8f0E0fF65d1C3A4671e1220437dd2b;
address internal constant l1StandardBridgeProxyAddress = 0xDeF3bca8c80064589E6787477FFa7Dd616B5574F; address internal constant l1StandardBridgeProxyAddress = 0xDeF3bca8c80064589E6787477FFa7Dd616B5574F;
address internal constant mipsAddress = 0x28bF1582225713139c0E898326Db808B6484cFd4; address internal constant mipsAddress = 0xcdAdd729ca2319E8955240bDb61A6A6A956A7664;
address internal constant optimismPortal2Address = 0xfcbb237388CaF5b08175C9927a37aB6450acd535; address internal constant optimismPortal2Address = 0xfcbb237388CaF5b08175C9927a37aB6450acd535;
address internal constant optimismPortalProxyAddress = 0x978e3286EB805934215a88694d80b09aDed68D90; address internal constant optimismPortalProxyAddress = 0x978e3286EB805934215a88694d80b09aDed68D90;
address internal constant preimageOracleAddress = 0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75; address internal constant preimageOracleAddress = 0x3bd7E801E51d48c5d94Ea68e8B801DFFC275De75;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment