Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| 0x60c06040 | 8789509 | 148 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Contract Name:
MIPS64
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 999999 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
// Libraries
import {
InvalidMemoryProof,
InvalidRMWInstruction,
InvalidSecondMemoryProof,
UnsupportedStateVersion
} from "src/cannon/libraries/CannonErrors.sol";
import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol";
import { MIPS64Instructions as ins } from "src/cannon/libraries/MIPS64Instructions.sol";
import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol";
import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol";
import { MIPS64Syscalls as sys } from "src/cannon/libraries/MIPS64Syscalls.sol";
import { VMStatuses } from "src/dispute/lib/Types.sol";
// Interfaces
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { ISemver } from "interfaces/universal/ISemver.sol";
/// @title MIPS64
/// @notice The MIPS64 contract emulates a single MIPS instruction.
/// It differs from MIPS.sol in that it supports MIPS64 instructions and multi-tasking.
contract MIPS64 is ISemver {
/// @notice The thread context.
/// Total state size: 8 + 1 + 1 + 8 + 8 + 8 + 8 + 32 * 8 = 298 bytes
struct ThreadState {
// metadata
uint64 threadID;
uint8 exitCode;
bool exited;
// state
uint64 pc;
uint64 nextPC;
uint64 lo;
uint64 hi;
uint64[32] registers;
}
uint32 internal constant PACKED_THREAD_STATE_SIZE = 298;
uint8 internal constant LL_STATUS_NONE = 0;
uint8 internal constant LL_STATUS_ACTIVE_32_BIT = 0x1;
uint8 internal constant LL_STATUS_ACTIVE_64_BIT = 0x2;
/// @notice Stores the VM state.
/// Total state size: 32 + 32 + 8 + 8 + 1 + 8 + 8 + 1 + 1 + 8 + 8 + 1 + 32 + 32 + 8 = 188 bytes
/// If nextPC != pc + 4, then the VM is executing a branch/jump delay slot.
struct State {
bytes32 memRoot;
bytes32 preimageKey;
uint64 preimageOffset;
uint64 heap;
uint8 llReservationStatus;
uint64 llAddress;
uint64 llOwnerThread;
uint8 exitCode;
bool exited;
uint64 step;
uint64 stepsSinceLastContextSwitch;
bool traverseRight;
bytes32 leftThreadStack;
bytes32 rightThreadStack;
uint64 nextThreadID;
}
/// @notice The semantic version of the MIPS64 contract.
/// @custom:semver 1.8.0
string public constant version = "1.8.0";
/// @notice The preimage oracle contract.
IPreimageOracle internal immutable ORACLE;
/// @notice The state version implemented. This identifies the specific state transition rules applied.
uint256 internal immutable STATE_VERSION;
// The offset of the start of proof calldata (_threadWitness.offset) in the step() function
uint256 internal constant THREAD_PROOF_OFFSET = 356;
// The offset of the start of proof calldata (_memProof.offset) in the step() function
uint256 internal constant MEM_PROOF_OFFSET = THREAD_PROOF_OFFSET + PACKED_THREAD_STATE_SIZE + 32;
// The empty thread root - keccak256(bytes32(0) ++ bytes32(0))
bytes32 internal constant EMPTY_THREAD_ROOT = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5";
// State memory offset allocated during step
uint256 internal constant STATE_MEM_OFFSET = 0x80;
// ThreadState memory offset allocated during step
uint256 internal constant TC_MEM_OFFSET = 0x260;
/// @param _oracle The address of the preimage oracle contract.
constructor(IPreimageOracle _oracle, uint256 _stateVersion) {
// Supports VersionMultiThreaded64_v4 (7) and VersionMultiThreaded64_v5 (8)
if (_stateVersion != 7 && _stateVersion != 8) {
revert UnsupportedStateVersion();
}
ORACLE = _oracle;
STATE_VERSION = _stateVersion;
}
/// @notice Getter for the pre-image oracle contract.
/// @return oracle_ The IPreimageOracle contract.
function oracle() external view returns (IPreimageOracle oracle_) {
oracle_ = ORACLE;
}
/// @notice Getter for the state version.
/// @return stateVersion_ The state version implemented by this contract.
function stateVersion() external view returns (uint256 stateVersion_) {
stateVersion_ = STATE_VERSION;
}
/// @notice Executes a single step of the multi-threaded vm.
/// Will revert if any required input state is missing.
/// @param _stateData The encoded state witness data.
/// @param _proof The encoded proof data: <<thread_context, inner_root>, <memory proof>.
/// Contains the thread context witness and the memory proof data for leaves within the MIPS VM's
/// memory.
/// The thread context witness is a packed tuple of the thread context and the immediate inner root of
/// the current thread stack.
/// @param _localContext The local key context for the preimage oracle. Optional, can be set as a constant
/// if the caller only requires one set of local keys.
/// @return postState_ The hash of the post state witness after the state transition.
function step(
bytes calldata _stateData,
bytes calldata _proof,
bytes32 _localContext
)
public
returns (bytes32 postState_)
{
postState_ = doStep(_stateData, _proof, _localContext);
assertPostStateChecks();
}
function assertPostStateChecks() internal pure {
State memory state;
assembly {
state := STATE_MEM_OFFSET
}
bytes32 activeStack = state.traverseRight ? state.rightThreadStack : state.leftThreadStack;
if (activeStack == EMPTY_THREAD_ROOT) {
revert("MIPS64: post-state active thread stack is empty");
}
}
function doStep(
bytes calldata _stateData,
bytes calldata _proof,
bytes32 _localContext
)
internal
returns (bytes32)
{
unchecked {
State memory state;
ThreadState memory thread;
uint32 exited;
assembly {
if iszero(eq(state, STATE_MEM_OFFSET)) {
// expected state mem offset check
revert(0, 0)
}
if iszero(eq(thread, TC_MEM_OFFSET)) {
// expected thread mem offset check
// STATE_MEM_OFFSET = 0x80 = 128
// 32 bytes per state field = 32 * 15 = 480
// TC_MEM_OFFSET = 480 + 128 = 608 = 0x260
revert(0, 0)
}
if iszero(eq(mload(0x40), shl(5, 59))) {
// 4 + 15 state slots + 40 thread slots = 59 expected memory check
revert(0, 0)
}
if iszero(eq(_stateData.offset, 132)) {
// 32*4+4=132 expected state data offset
revert(0, 0)
}
if iszero(eq(_proof.offset, THREAD_PROOF_OFFSET)) {
// _stateData.offset = 132
// stateData.length = ceil(stateSize / 32) * 32 = 6 * 32 = 192
// _proof size prefix = 32
// expected thread proof offset equals the sum of the above is 356
revert(0, 0)
}
function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut {
// calldata is packed, thus starting left-aligned, shift-right to pad and right-align
let w := shr(shl(3, sub(32, size)), calldataload(callOffset))
mstore(memOffset, w)
callOffsetOut := add(callOffset, size)
memOffsetOut := add(memOffset, 32)
}
// Unpack state from calldata into memory
let c := _stateData.offset // calldata offset
let m := STATE_MEM_OFFSET // mem offset
c, m := putField(c, m, 32) // memRoot
c, m := putField(c, m, 32) // preimageKey
c, m := putField(c, m, 8) // preimageOffset
c, m := putField(c, m, 8) // heap
c, m := putField(c, m, 1) // llReservationStatus
c, m := putField(c, m, 8) // llAddress
c, m := putField(c, m, 8) // llOwnerThread
c, m := putField(c, m, 1) // exitCode
c, m := putField(c, m, 1) // exited
exited := mload(sub(m, 32))
c, m := putField(c, m, 8) // step
c, m := putField(c, m, 8) // stepsSinceLastContextSwitch
c, m := putField(c, m, 1) // traverseRight
c, m := putField(c, m, 32) // leftThreadStack
c, m := putField(c, m, 32) // rightThreadStack
c, m := putField(c, m, 8) // nextThreadID
}
st.assertExitedIsValid(exited);
if (state.exited) {
// thread state is unchanged
return outputState();
}
if (
(state.leftThreadStack == EMPTY_THREAD_ROOT && !state.traverseRight)
|| (state.rightThreadStack == EMPTY_THREAD_ROOT && state.traverseRight)
) {
revert("MIPS64: active thread stack is empty");
}
state.step += 1;
setThreadStateFromCalldata(thread);
validateCalldataThreadWitness(state, thread);
if (thread.exited) {
popThread(state);
return outputState();
}
if (state.stepsSinceLastContextSwitch >= sys.SCHED_QUANTUM) {
preemptThread(state, thread);
return outputState();
}
state.stepsSinceLastContextSwitch += 1;
// instruction fetch
uint256 insnProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 0);
(uint32 insn, uint32 opcode, uint32 fun) =
ins.getInstructionDetails(thread.pc, state.memRoot, insnProofOffset);
// Handle syscall separately
// syscall (can read and write)
if (opcode == 0 && fun == 0xC) {
return handleSyscall(_localContext);
}
// Handle RMW (read-modify-write) ops
if (opcode == ins.OP_LOAD_LINKED || opcode == ins.OP_STORE_CONDITIONAL) {
return handleRMWOps(state, thread, insn, opcode);
}
if (opcode == ins.OP_LOAD_LINKED64 || opcode == ins.OP_STORE_CONDITIONAL64) {
return handleRMWOps(state, thread, insn, opcode);
}
// Exec the rest of the step logic
st.CpuScalars memory cpu = getCpuScalars(thread);
ins.CoreStepLogicParams memory coreStepArgs = ins.CoreStepLogicParams({
cpu: cpu,
registers: thread.registers,
memRoot: state.memRoot,
memProofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1),
insn: insn,
opcode: opcode,
fun: fun,
stateVersion: STATE_VERSION
});
bool memUpdated;
uint64 effMemAddr;
(state.memRoot, memUpdated, effMemAddr) = ins.execMipsCoreStepLogic(coreStepArgs);
setStateCpuScalars(thread, cpu);
updateCurrentThreadRoot();
if (memUpdated) {
handleMemoryUpdate(state, effMemAddr);
}
return outputState();
}
}
function handleMemoryUpdate(State memory _state, uint64 _effMemAddr) internal pure {
if (_effMemAddr == (arch.ADDRESS_MASK & _state.llAddress)) {
// Reserved address was modified, clear the reservation
clearLLMemoryReservation(_state);
}
}
function clearLLMemoryReservation(State memory _state) internal pure {
_state.llReservationStatus = LL_STATUS_NONE;
_state.llAddress = 0;
_state.llOwnerThread = 0;
}
function handleRMWOps(
State memory _state,
ThreadState memory _thread,
uint32 _insn,
uint32 _opcode
)
internal
returns (bytes32)
{
unchecked {
uint64 base = _thread.registers[(_insn >> 21) & 0x1F];
uint32 rtReg = (_insn >> 16) & 0x1F;
uint64 addr = base + ins.signExtendImmediate(_insn);
// Determine some opcode-specific parameters
uint8 targetStatus = LL_STATUS_ACTIVE_32_BIT;
uint64 byteLength = 4;
if (_opcode == ins.OP_LOAD_LINKED64 || _opcode == ins.OP_STORE_CONDITIONAL64) {
// Use 64-bit params
targetStatus = LL_STATUS_ACTIVE_64_BIT;
byteLength = 8;
}
uint64 retVal = 0;
uint64 threadId = _thread.threadID;
if (_opcode == ins.OP_LOAD_LINKED || _opcode == ins.OP_LOAD_LINKED64) {
retVal = loadSubWord(_state, addr, byteLength, true);
_state.llReservationStatus = targetStatus;
_state.llAddress = addr;
_state.llOwnerThread = threadId;
} else if (_opcode == ins.OP_STORE_CONDITIONAL || _opcode == ins.OP_STORE_CONDITIONAL64) {
// Check if our memory reservation is still intact
if (
_state.llReservationStatus == targetStatus && _state.llOwnerThread == threadId
&& _state.llAddress == addr
) {
// Complete atomic update: set memory and return 1 for success
clearLLMemoryReservation(_state);
uint64 val = _thread.registers[rtReg];
storeSubWord(_state, addr, byteLength, val);
retVal = 1;
} else {
// Atomic update failed, return 0 for failure
retVal = 0;
}
} else {
revert InvalidRMWInstruction();
}
st.CpuScalars memory cpu = getCpuScalars(_thread);
ins.handleRd(cpu, _thread.registers, rtReg, retVal, true);
setStateCpuScalars(_thread, cpu);
updateCurrentThreadRoot();
return outputState();
}
}
/// @notice Loads a subword of byteLength size contained from memory based on the low-order bits of vaddr
/// @param _vaddr The virtual address of the the subword.
/// @param _byteLength The size of the subword.
/// @param _signExtend Whether to sign extend the selected subwrod.
function loadSubWord(
State memory _state,
uint64 _vaddr,
uint64 _byteLength,
bool _signExtend
)
internal
pure
returns (uint64 val_)
{
uint64 effAddr = _vaddr & arch.ADDRESS_MASK;
uint256 memProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1);
uint64 mem = MIPS64Memory.readMem(_state.memRoot, effAddr, memProofOffset);
val_ = ins.selectSubWord(_vaddr, mem, _byteLength, _signExtend);
}
/// @notice Stores a word that has been updated by the specified subword at bit positions determined by the virtual
/// address
/// @param _vaddr The virtual address of the subword.
/// @param _byteLength The size of the subword.
/// @param _value The subword that updates _memWord.
function storeSubWord(State memory _state, uint64 _vaddr, uint64 _byteLength, uint64 _value) internal pure {
uint64 effAddr = _vaddr & arch.ADDRESS_MASK;
uint256 memProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1);
uint64 mem = MIPS64Memory.readMem(_state.memRoot, effAddr, memProofOffset);
uint64 newMemVal = ins.updateSubWord(_vaddr, mem, _byteLength, _value);
_state.memRoot = MIPS64Memory.writeMem(effAddr, memProofOffset, newMemVal);
}
function handleSyscall(bytes32 _localContext) internal returns (bytes32 out_) {
unchecked {
// Load state from memory offsets to reduce stack pressure
State memory state;
ThreadState memory thread;
assembly {
state := STATE_MEM_OFFSET
thread := TC_MEM_OFFSET
}
// Load the syscall numbers and args from the registers
(uint64 syscall_no, uint64 a0, uint64 a1, uint64 a2) = sys.getSyscallArgs(thread.registers);
// Syscalls that are unimplemented but known return with v0=0 and v1=0
uint64 v0 = 0;
uint64 v1 = 0;
if (syscall_no == sys.SYS_MMAP) {
(v0, v1, state.heap) = sys.handleSysMmap(a0, a1, state.heap);
} else if (syscall_no == sys.SYS_BRK) {
// brk: Returns a fixed address for the program break at 0x40000000
v0 = sys.PROGRAM_BREAK;
} else if (syscall_no == sys.SYS_CLONE) {
if (sys.VALID_SYS_CLONE_FLAGS != a0) {
state.exited = true;
state.exitCode = VMStatuses.PANIC.raw();
return outputState();
}
v0 = state.nextThreadID;
v1 = 0;
ThreadState memory newThread;
newThread.threadID = state.nextThreadID;
newThread.exitCode = 0;
newThread.exited = false;
newThread.pc = thread.nextPC;
newThread.nextPC = thread.nextPC + 4;
newThread.lo = thread.lo;
newThread.hi = thread.hi;
for (uint256 i; i < 32; i++) {
newThread.registers[i] = thread.registers[i];
}
newThread.registers[29] = a1; // set stack pointer
// the child will perceive a 0 value as returned value instead, and no error
newThread.registers[2] = 0;
newThread.registers[7] = 0;
state.nextThreadID++;
// Preempt this thread for the new one. But not before updating PCs
st.CpuScalars memory cpu0 = getCpuScalars(thread);
sys.handleSyscallUpdates(cpu0, thread.registers, v0, v1);
setStateCpuScalars(thread, cpu0);
updateCurrentThreadRoot();
pushThread(state, newThread);
return outputState();
} else if (syscall_no == sys.SYS_EXIT_GROUP) {
// exit group: Sets the Exited and ExitCode states to true and argument 0.
state.exited = true;
state.exitCode = uint8(a0);
updateCurrentThreadRoot();
return outputState();
} else if (syscall_no == sys.SYS_READ) {
sys.SysReadParams memory args = sys.SysReadParams({
a0: a0,
a1: a1,
a2: a2,
preimageKey: state.preimageKey,
preimageOffset: state.preimageOffset,
localContext: _localContext,
oracle: ORACLE,
proofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1),
memRoot: state.memRoot
});
// Encapsulate execution to avoid stack-too-deep error
(v0, v1) = execSysRead(state, args);
} else if (syscall_no == sys.SYS_WRITE) {
sys.SysWriteParams memory args = sys.SysWriteParams({
_a0: a0,
_a1: a1,
_a2: a2,
_preimageKey: state.preimageKey,
_preimageOffset: state.preimageOffset,
_proofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1),
_memRoot: state.memRoot
});
(v0, v1, state.preimageKey, state.preimageOffset) = sys.handleSysWrite(args);
} else if (syscall_no == sys.SYS_FCNTL) {
(v0, v1) = sys.handleSysFcntl(a0, a1);
} else if (syscall_no == sys.SYS_GETTID) {
v0 = thread.threadID;
v1 = 0;
} else if (syscall_no == sys.SYS_EXIT) {
thread.exited = true;
thread.exitCode = uint8(a0);
if (lastThreadRemaining(state)) {
state.exited = true;
state.exitCode = uint8(a0);
}
updateCurrentThreadRoot();
return outputState();
} else if (syscall_no == sys.SYS_FUTEX) {
// args: a0 = addr, a1 = op, a2 = val, a3 = timeout
// Futex value is 32-bit, so clear the lower 2 bits to get an effective address targeting a 4-byte value
uint64 effFutexAddr = a0 & 0xFFFFFFFFFFFFFFFC;
if (a1 == sys.FUTEX_WAIT_PRIVATE) {
uint32 futexVal = getFutexValue(effFutexAddr);
uint32 targetVal = uint32(a2);
if (futexVal != targetVal) {
v0 = sys.EAGAIN;
v1 = sys.SYS_ERROR_SIGNAL;
} else {
return syscallYield(state, thread);
}
} else if (a1 == sys.FUTEX_WAKE_PRIVATE) {
return syscallYield(state, thread);
} else {
v0 = sys.EINVAL;
v1 = sys.SYS_ERROR_SIGNAL;
}
} else if (syscall_no == sys.SYS_SCHED_YIELD || syscall_no == sys.SYS_NANOSLEEP) {
return syscallYield(state, thread);
} else if (syscall_no == sys.SYS_OPEN) {
v0 = sys.EBADF;
v1 = sys.SYS_ERROR_SIGNAL;
} else if (syscall_no == sys.SYS_CLOCKGETTIME) {
if (a0 == sys.CLOCK_GETTIME_REALTIME_FLAG || a0 == sys.CLOCK_GETTIME_MONOTONIC_FLAG) {
v0 = 0;
v1 = 0;
uint64 secs = 0;
uint64 nsecs = 0;
if (a0 == sys.CLOCK_GETTIME_MONOTONIC_FLAG) {
secs = uint64(state.step / sys.HZ);
nsecs = uint64((state.step % sys.HZ) * (1_000_000_000 / sys.HZ));
}
uint64 effAddr = a1 & arch.ADDRESS_MASK;
// First verify the effAddr path
if (
!MIPS64Memory.isValidProof(
state.memRoot, effAddr, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1)
)
) {
revert InvalidMemoryProof();
}
// Recompute the new root after updating effAddr
state.memRoot =
MIPS64Memory.writeMem(effAddr, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1), secs);
handleMemoryUpdate(state, effAddr);
// Verify the second memory proof against the newly computed root
if (
!MIPS64Memory.isValidProof(
state.memRoot, effAddr + 8, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 2)
)
) {
revert InvalidSecondMemoryProof();
}
state.memRoot =
MIPS64Memory.writeMem(effAddr + 8, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 2), nsecs);
handleMemoryUpdate(state, effAddr + 8);
} else {
v0 = sys.EINVAL;
v1 = sys.SYS_ERROR_SIGNAL;
}
} else if (syscall_no == sys.SYS_GETPID) {
v0 = 0;
v1 = 0;
} else if (syscall_no == sys.SYS_GETRANDOM) {
if (st.featuresForVersion(STATE_VERSION).supportWorkingSysGetRandom) {
(v0, v1, state.memRoot) = syscallGetRandom(state, a0, a1);
}
// Otherwise, ignored (noop)
} else if (syscall_no == sys.SYS_MUNMAP) {
// ignored
} else if (syscall_no == sys.SYS_MPROTECT) {
if (!st.featuresForVersion(STATE_VERSION).supportNoopMprotect) {
revert("MIPS64: unimplemented syscall");
}
} else if (syscall_no == sys.SYS_GETAFFINITY) {
// ignored
} else if (syscall_no == sys.SYS_MADVISE) {
// ignored
} else if (syscall_no == sys.SYS_RTSIGPROCMASK) {
// ignored
} else if (syscall_no == sys.SYS_SIGALTSTACK) {
// ignored
} else if (syscall_no == sys.SYS_RTSIGACTION) {
// ignored
} else if (syscall_no == sys.SYS_PRLIMIT64) {
// ignored
} else if (syscall_no == sys.SYS_CLOSE) {
// ignored
} else if (syscall_no == sys.SYS_PREAD64) {
// ignored
} else if (syscall_no == sys.SYS_STAT) {
// ignored
} else if (syscall_no == sys.SYS_FSTAT) {
// ignored
} else if (syscall_no == sys.SYS_OPENAT) {
// ignored
} else if (syscall_no == sys.SYS_READLINK) {
// ignored
} else if (syscall_no == sys.SYS_READLINKAT) {
// ignored
} else if (syscall_no == sys.SYS_IOCTL) {
// ignored
} else if (syscall_no == sys.SYS_EPOLLCREATE1) {
// ignored
} else if (syscall_no == sys.SYS_PIPE2) {
// ignored
} else if (syscall_no == sys.SYS_EPOLLCTL) {
// ignored
} else if (syscall_no == sys.SYS_EPOLLPWAIT) {
// ignored
} else if (syscall_no == sys.SYS_UNAME) {
// ignored
} else if (syscall_no == sys.SYS_GETUID) {
// ignored
} else if (syscall_no == sys.SYS_GETGID) {
// ignored
} else if (syscall_no == sys.SYS_MINCORE) {
// ignored
} else if (syscall_no == sys.SYS_TGKILL) {
// ignored
} else if (syscall_no == sys.SYS_SETITIMER) {
// ignored
} else if (syscall_no == sys.SYS_TIMERCREATE) {
// ignored
} else if (syscall_no == sys.SYS_TIMERSETTIME) {
// ignored
} else if (syscall_no == sys.SYS_TIMERDELETE) {
// ignored
} else if (syscall_no == sys.SYS_GETRLIMIT) {
// ignored
} else if (syscall_no == sys.SYS_LSEEK) {
// ignored
} else if (syscall_no == sys.SYS_EVENTFD2) {
if (!st.featuresForVersion(STATE_VERSION).supportMinimalSysEventFd2) {
revert("MIPS64: unimplemented syscall");
}
// a0 = initial value, a1 = flags
// Validate flags
if (a1 & sys.EFD_NONBLOCK == 0) {
// The non-block flag was not set, but we only support non-block requests, so error
v0 = sys.EINVAL;
v1 = sys.SYS_ERROR_SIGNAL;
} else {
v0 = sys.FD_EVENTFD;
}
} else {
revert("MIPS64: unimplemented syscall");
}
st.CpuScalars memory cpu = getCpuScalars(thread);
sys.handleSyscallUpdates(cpu, thread.registers, v0, v1);
setStateCpuScalars(thread, cpu);
updateCurrentThreadRoot();
out_ = outputState();
}
}
function syscallGetRandom(
State memory _state,
uint64 _a0,
uint64 _a1
)
internal
pure
returns (uint64 v0_, uint64 v1_, bytes32 memRoot_)
{
uint64 effAddr = _a0 & arch.ADDRESS_MASK;
uint256 memProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1);
uint64 memVal = MIPS64Memory.readMem(_state.memRoot, effAddr, memProofOffset);
// Generate some pseudorandom data
uint64 randomWord = splitmix64(_state.step);
// Calculate number of bytes to write
uint64 targetByteIndex = _a0 - effAddr;
uint64 maxBytes = arch.WORD_SIZE_BYTES - targetByteIndex;
uint64 byteCount = _a1;
if (maxBytes < byteCount) {
byteCount = maxBytes;
}
// Write random data into target memory location
uint64 randDataMask = uint64((1 << (byteCount * 8)) - 1);
// Shift left to align with index 0, then shift right to target correct index
randDataMask <<= (arch.WORD_SIZE_BYTES - byteCount) * 8;
randDataMask >>= targetByteIndex * 8;
uint64 newMemVal = (memVal & ~randDataMask) | (randomWord & randDataMask);
memRoot_ = MIPS64Memory.writeMem(effAddr, memProofOffset, newMemVal);
handleMemoryUpdate(_state, effAddr);
v0_ = byteCount;
v1_ = 0;
}
// splitmix64 generates a pseudorandom 64-bit value.
// See canonical implementation: https://prng.di.unimi.it/splitmix64.c
function splitmix64(uint64 _seed) internal pure returns (uint64) {
unchecked {
uint64 z = _seed + 0x9e3779b97f4a7c15;
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
}
function syscallYield(State memory _state, ThreadState memory _thread) internal returns (bytes32 out_) {
uint64 v0 = 0;
uint64 v1 = 0;
st.CpuScalars memory cpu = getCpuScalars(_thread);
sys.handleSyscallUpdates(cpu, _thread.registers, v0, v1);
setStateCpuScalars(_thread, cpu);
preemptThread(_state, _thread);
return outputState();
}
function execSysRead(
State memory _state,
sys.SysReadParams memory _args
)
internal
view
returns (uint64 v0_, uint64 v1_)
{
bool memUpdated;
uint64 memAddr;
(v0_, v1_, _state.preimageOffset, _state.memRoot, memUpdated, memAddr) = sys.handleSysRead(_args);
if (memUpdated) {
handleMemoryUpdate(_state, memAddr);
}
}
/// @notice Computes the hash of the MIPS state.
/// @return out_ The hashed MIPS state.
function outputState() internal returns (bytes32 out_) {
uint32 exited;
assembly {
// copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data
function copyMem(from, to, size) -> fromOut, toOut {
mstore(to, mload(add(from, sub(32, size))))
fromOut := add(from, 32)
toOut := add(to, size)
}
// From points to the MIPS State
let from := STATE_MEM_OFFSET
// Copy to the free memory pointer
let start := mload(0x40)
let to := start
// Copy state to free memory
from, to := copyMem(from, to, 32) // memRoot
from, to := copyMem(from, to, 32) // preimageKey
from, to := copyMem(from, to, 8) // preimageOffset
from, to := copyMem(from, to, 8) // heap
from, to := copyMem(from, to, 1) // llReservationStatus
from, to := copyMem(from, to, 8) // llAddress
from, to := copyMem(from, to, 8) // llOwnerThread
let exitCode := mload(from)
from, to := copyMem(from, to, 1) // exitCode
exited := mload(from)
from, to := copyMem(from, to, 1) // exited
from, to := copyMem(from, to, 8) // step
from, to := copyMem(from, to, 8) // stepsSinceLastContextSwitch
from, to := copyMem(from, to, 1) // traverseRight
from, to := copyMem(from, to, 32) // leftThreadStack
from, to := copyMem(from, to, 32) // rightThreadStack
from, to := copyMem(from, to, 8) // nextThreadID
// Clean up end of memory
mstore(to, 0)
// Log the resulting MIPS state, for debugging
log0(start, sub(to, start))
// Determine the VM status
let status := 0
switch exited
case 1 {
switch exitCode
// VMStatusValid
case 0 { status := 0 }
// VMStatusInvalid
case 1 { status := 1 }
// VMStatusPanic
default { status := 2 }
}
// VMStatusUnfinished
default { status := 3 }
// Compute the hash of the resulting MIPS state and set the status byte
out_ := keccak256(start, sub(to, start))
out_ := or(and(not(shl(248, 0xFF)), out_), shl(248, status))
}
st.assertExitedIsValid(exited);
}
/// @notice Updates the current thread stack root via inner thread root in calldata
function updateCurrentThreadRoot() internal pure {
State memory state;
ThreadState memory thread;
assembly {
state := STATE_MEM_OFFSET
thread := TC_MEM_OFFSET
}
bytes32 updatedRoot = computeThreadRoot(loadCalldataInnerThreadRoot(), thread);
if (state.traverseRight) {
state.rightThreadStack = updatedRoot;
} else {
state.leftThreadStack = updatedRoot;
}
}
/// @notice Preempts the current thread for another and updates the VM state.
/// It reads the inner thread root from calldata to update the current thread stack root.
function preemptThread(
State memory _state,
ThreadState memory _thread
)
internal
pure
returns (bool changedDirections_)
{
// pop thread from the current stack and push to the other stack
if (_state.traverseRight) {
require(_state.rightThreadStack != EMPTY_THREAD_ROOT, "MIPS64: empty right thread stack");
_state.rightThreadStack = loadCalldataInnerThreadRoot();
_state.leftThreadStack = computeThreadRoot(_state.leftThreadStack, _thread);
} else {
require(_state.leftThreadStack != EMPTY_THREAD_ROOT, "MIPS64: empty left thread stack");
_state.leftThreadStack = loadCalldataInnerThreadRoot();
_state.rightThreadStack = computeThreadRoot(_state.rightThreadStack, _thread);
}
bytes32 current = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack;
if (current == EMPTY_THREAD_ROOT) {
_state.traverseRight = !_state.traverseRight;
changedDirections_ = true;
}
_state.stepsSinceLastContextSwitch = 0;
}
/// @notice Pushes a thread to the current thread stack.
function pushThread(State memory _state, ThreadState memory _thread) internal pure {
if (_state.traverseRight) {
_state.rightThreadStack = computeThreadRoot(_state.rightThreadStack, _thread);
} else {
_state.leftThreadStack = computeThreadRoot(_state.leftThreadStack, _thread);
}
_state.stepsSinceLastContextSwitch = 0;
}
/// @notice Removes the current thread from the stack.
function popThread(State memory _state) internal pure {
if (_state.traverseRight) {
_state.rightThreadStack = loadCalldataInnerThreadRoot();
} else {
_state.leftThreadStack = loadCalldataInnerThreadRoot();
}
bytes32 current = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack;
if (current == EMPTY_THREAD_ROOT) {
_state.traverseRight = !_state.traverseRight;
}
_state.stepsSinceLastContextSwitch = 0;
}
/// @notice Returns true if the number of threads is 1
function lastThreadRemaining(State memory _state) internal pure returns (bool out_) {
bytes32 inactiveStack = _state.traverseRight ? _state.leftThreadStack : _state.rightThreadStack;
bool currentStackIsAlmostEmpty = loadCalldataInnerThreadRoot() == EMPTY_THREAD_ROOT;
return inactiveStack == EMPTY_THREAD_ROOT && currentStackIsAlmostEmpty;
}
function computeThreadRoot(bytes32 _currentRoot, ThreadState memory _thread) internal pure returns (bytes32 out_) {
// w_i = hash(w_0 ++ hash(thread))
bytes32 threadRoot = outputThreadState(_thread);
out_ = keccak256(abi.encodePacked(_currentRoot, threadRoot));
}
function outputThreadState(ThreadState memory _thread) internal pure returns (bytes32 out_) {
assembly {
// copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data
function copyMem(from, to, size) -> fromOut, toOut {
mstore(to, mload(add(from, sub(32, size))))
fromOut := add(from, 32)
toOut := add(to, size)
}
// From points to the ThreadState
let from := _thread
// Copy to the free memory pointer
let start := mload(0x40)
let to := start
// Copy state to free memory
from, to := copyMem(from, to, 8) // threadID
from, to := copyMem(from, to, 1) // exitCode
from, to := copyMem(from, to, 1) // exited
from, to := copyMem(from, to, 8) // pc
from, to := copyMem(from, to, 8) // nextPC
from, to := copyMem(from, to, 8) // lo
from, to := copyMem(from, to, 8) // hi
from := mload(from) // offset to registers
// Copy registers
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { from, to := copyMem(from, to, 8) }
// Clean up end of memory
mstore(to, 0)
// Compute the hash of the resulting ThreadState
out_ := keccak256(start, sub(to, start))
}
}
function getCpuScalars(ThreadState memory _tc) internal pure returns (st.CpuScalars memory cpu_) {
cpu_ = st.CpuScalars({ pc: _tc.pc, nextPC: _tc.nextPC, lo: _tc.lo, hi: _tc.hi });
}
function setStateCpuScalars(ThreadState memory _tc, st.CpuScalars memory _cpu) internal pure {
_tc.pc = _cpu.pc;
_tc.nextPC = _cpu.nextPC;
_tc.lo = _cpu.lo;
_tc.hi = _cpu.hi;
}
/// @notice Validates the thread witness in calldata against the current thread.
function validateCalldataThreadWitness(State memory _state, ThreadState memory _thread) internal pure {
bytes32 witnessRoot = computeThreadRoot(loadCalldataInnerThreadRoot(), _thread);
bytes32 expectedRoot = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack;
require(expectedRoot == witnessRoot, "MIPS64: invalid thread witness");
}
/// @notice Sets the thread context from calldata.
function setThreadStateFromCalldata(ThreadState memory _thread) internal pure {
uint256 s = 0;
assembly {
s := calldatasize()
}
// verify we have enough calldata
require(
s >= (THREAD_PROOF_OFFSET + PACKED_THREAD_STATE_SIZE), "MIPS64: insufficient calldata for thread witness"
);
unchecked {
assembly {
function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut {
// calldata is packed, thus starting left-aligned, shift-right to pad and right-align
let w := shr(shl(3, sub(32, size)), calldataload(callOffset))
mstore(memOffset, w)
callOffsetOut := add(callOffset, size)
memOffsetOut := add(memOffset, 32)
}
let c := THREAD_PROOF_OFFSET
let m := _thread
c, m := putField(c, m, 8) // threadID
c, m := putField(c, m, 1) // exitCode
c, m := putField(c, m, 1) // exited
c, m := putField(c, m, 8) // pc
c, m := putField(c, m, 8) // nextPC
c, m := putField(c, m, 8) // lo
c, m := putField(c, m, 8) // hi
m := mload(m) // offset to registers
// Unpack register calldata into memory
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { c, m := putField(c, m, 8) }
}
}
}
/// @notice Loads the inner root for the current thread hash onion from calldata.
function loadCalldataInnerThreadRoot() internal pure returns (bytes32 innerThreadRoot_) {
uint256 s = 0;
assembly {
s := calldatasize()
innerThreadRoot_ := calldataload(add(THREAD_PROOF_OFFSET, PACKED_THREAD_STATE_SIZE))
}
// verify we have enough calldata
require(
s >= (THREAD_PROOF_OFFSET + (PACKED_THREAD_STATE_SIZE + 32)),
"MIPS64: insufficient calldata for thread witness"
);
}
/// @notice Loads a 32-bit futex value at _vAddr
function getFutexValue(uint64 _vAddr) internal pure returns (uint32 out_) {
State memory state;
assembly {
state := STATE_MEM_OFFSET
}
uint64 subword = loadSubWord(state, _vAddr, 4, false);
return uint32(subword);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title LibKeccak
/// @notice An EVM implementation of the Keccak-f[1600] permutation.
/// @author clabby <https://github.com/clabby>
/// @custom:attribution geohot <https://github.com/geohot>
library LibKeccak {
/// @notice The block size of the Keccak-f[1600] permutation, 1088 bits (136 bytes).
uint256 internal constant BLOCK_SIZE_BYTES = 136;
/// @notice The round constants for the keccak256 hash function. Packed in memory for efficient reading during the
/// permutation.
bytes internal constant ROUND_CONSTANTS = abi.encode(
0x00000000000000010000000000008082800000000000808a8000000080008000, // r1,r2,r3,r4
0x000000000000808b000000008000000180000000800080818000000000008009, // r5,r6,r7,r8
0x000000000000008a00000000000000880000000080008009000000008000000a, // r9,r10,r11,r12
0x000000008000808b800000000000008b80000000000080898000000000008003, // r13,r14,r15,r16
0x80000000000080028000000000000080000000000000800a800000008000000a, // r17,r18,r19,r20
0x8000000080008081800000000000808000000000800000018000000080008008 // r21,r22,r23,r24
);
/// @notice A mask for 64-bit values.
uint64 private constant U64_MASK = 0xFFFFFFFFFFFFFFFF;
/// @notice The 5x5 state matrix for the keccak-f[1600] permutation.
struct StateMatrix {
uint64[25] state;
}
/// @notice Performs the Keccak-f[1600] permutation on the given 5x5 state matrix.
function permutation(StateMatrix memory _stateMatrix) internal pure {
// Pull the round constants into memory to avoid reallocation in the unrolled permutation loop.
bytes memory roundConstants = ROUND_CONSTANTS;
assembly {
// Add 32 to the state matrix pointer to skip the data location field.
let stateMatrixPtr := add(_stateMatrix, 0x20)
let rcPtr := add(roundConstants, 0x20)
// set a state element in the passed `StateMatrix` struct memory ptr.
function setStateElem(ptr, idx, data) {
mstore(add(ptr, shl(0x05, idx)), and(data, U64_MASK))
}
// fetch a state element from the passed `StateMatrix` struct memory ptr.
function stateElem(ptr, idx) -> elem {
elem := mload(add(ptr, shl(0x05, idx)))
}
// 64 bit logical shift
function shl64(a, b) -> val {
val := and(shl(a, b), U64_MASK)
}
// Performs an indivudual rho + pi computation, to be used in the full `thetaRhoPi` chain.
function rhoPi(ptr, destIdx, srcIdx, fact, dt) {
let xs1 := xor(stateElem(ptr, srcIdx), dt)
let res := xor(shl(fact, xs1), shr(sub(64, fact), xs1))
setStateElem(ptr, destIdx, res)
}
// xor a column in the state matrix
function xorColumn(ptr, col) -> val {
val :=
xor(
xor(xor(stateElem(ptr, col), stateElem(ptr, add(col, 5))), stateElem(ptr, add(col, 10))),
xor(stateElem(ptr, add(col, 15)), stateElem(ptr, add(col, 20)))
)
}
// Performs the `theta`, `rho`, and `pi` steps of the Keccak-f[1600] permutation on
// the passed `StateMatrix` struct memory ptr.
function thetaRhoPi(ptr) {
// Theta
let C0 := xorColumn(ptr, 0)
let C1 := xorColumn(ptr, 1)
let C2 := xorColumn(ptr, 2)
let C3 := xorColumn(ptr, 3)
let C4 := xorColumn(ptr, 4)
let D0 := xor(xor(shl64(1, C1), shr(63, C1)), C4)
let D1 := xor(xor(shl64(1, C2), shr(63, C2)), C0)
let D2 := xor(xor(shl64(1, C3), shr(63, C3)), C1)
let D3 := xor(xor(shl64(1, C4), shr(63, C4)), C2)
let D4 := xor(xor(shl64(1, C0), shr(63, C0)), C3)
let xs1 := xor(stateElem(ptr, 1), D1)
let A1 := xor(shl(1, xs1), shr(63, xs1))
let _ptr := ptr
setStateElem(_ptr, 0, xor(stateElem(_ptr, 0), D0))
rhoPi(_ptr, 1, 6, 44, D1)
rhoPi(_ptr, 6, 9, 20, D4)
rhoPi(_ptr, 9, 22, 61, D2)
rhoPi(_ptr, 22, 14, 39, D4)
rhoPi(_ptr, 14, 20, 18, D0)
rhoPi(_ptr, 20, 2, 62, D2)
rhoPi(_ptr, 2, 12, 43, D2)
rhoPi(_ptr, 12, 13, 25, D3)
rhoPi(_ptr, 13, 19, 8, D4)
rhoPi(_ptr, 19, 23, 56, D3)
rhoPi(_ptr, 23, 15, 41, D0)
rhoPi(_ptr, 15, 4, 27, D4)
rhoPi(_ptr, 4, 24, 14, D4)
rhoPi(_ptr, 24, 21, 2, D1)
rhoPi(_ptr, 21, 8, 55, D3)
rhoPi(_ptr, 8, 16, 45, D1)
rhoPi(_ptr, 16, 5, 36, D0)
rhoPi(_ptr, 5, 3, 28, D3)
rhoPi(_ptr, 3, 18, 21, D3)
rhoPi(_ptr, 18, 17, 15, D2)
rhoPi(_ptr, 17, 11, 10, D1)
rhoPi(_ptr, 11, 7, 6, D2)
rhoPi(_ptr, 7, 10, 3, D0)
setStateElem(_ptr, 10, A1)
}
// Inner `chi` function, unrolled in `chi` for performance.
function innerChi(ptr, start) {
let A0 := stateElem(ptr, start)
let A1 := stateElem(ptr, add(start, 1))
let A2 := stateElem(ptr, add(start, 2))
let A3 := stateElem(ptr, add(start, 3))
let A4 := stateElem(ptr, add(start, 4))
setStateElem(ptr, start, xor(A0, and(not(A1), A2)))
setStateElem(ptr, add(start, 1), xor(A1, and(not(A2), A3)))
setStateElem(ptr, add(start, 2), xor(A2, and(not(A3), A4)))
setStateElem(ptr, add(start, 3), xor(A3, and(not(A4), A0)))
setStateElem(ptr, add(start, 4), xor(A4, and(not(A0), A1)))
}
// Performs the `chi` step of the Keccak-f[1600] permutation on the passed `StateMatrix` struct memory ptr
function chi(ptr) {
innerChi(ptr, 0)
innerChi(ptr, 5)
innerChi(ptr, 10)
innerChi(ptr, 15)
innerChi(ptr, 20)
}
// Perform the full Keccak-f[1600] permutation on a `StateMatrix` struct memory ptr for a given round.
function permute(ptr, roundsPtr, round) {
// Theta, Rho, Pi, Chi
thetaRhoPi(ptr)
chi(ptr)
// Iota
let roundConst := shr(192, mload(add(roundsPtr, shl(0x03, round))))
setStateElem(ptr, 0, xor(stateElem(ptr, 0), roundConst))
}
// Unroll the permutation loop.
permute(stateMatrixPtr, rcPtr, 0)
permute(stateMatrixPtr, rcPtr, 1)
permute(stateMatrixPtr, rcPtr, 2)
permute(stateMatrixPtr, rcPtr, 3)
permute(stateMatrixPtr, rcPtr, 4)
permute(stateMatrixPtr, rcPtr, 5)
permute(stateMatrixPtr, rcPtr, 6)
permute(stateMatrixPtr, rcPtr, 7)
permute(stateMatrixPtr, rcPtr, 8)
permute(stateMatrixPtr, rcPtr, 9)
permute(stateMatrixPtr, rcPtr, 10)
permute(stateMatrixPtr, rcPtr, 11)
permute(stateMatrixPtr, rcPtr, 12)
permute(stateMatrixPtr, rcPtr, 13)
permute(stateMatrixPtr, rcPtr, 14)
permute(stateMatrixPtr, rcPtr, 15)
permute(stateMatrixPtr, rcPtr, 16)
permute(stateMatrixPtr, rcPtr, 17)
permute(stateMatrixPtr, rcPtr, 18)
permute(stateMatrixPtr, rcPtr, 19)
permute(stateMatrixPtr, rcPtr, 20)
permute(stateMatrixPtr, rcPtr, 21)
permute(stateMatrixPtr, rcPtr, 22)
permute(stateMatrixPtr, rcPtr, 23)
}
}
/// @notice Absorb a fixed-sized block into the sponge.
function absorb(StateMatrix memory _stateMatrix, bytes memory _input) internal pure {
assembly {
// The input must be 1088 bits long.
if iszero(eq(mload(_input), BLOCK_SIZE_BYTES)) { revert(0, 0) }
let dataPtr := add(_input, 0x20)
let statePtr := add(_stateMatrix, 0x20)
// set a state element in the passed `StateMatrix` struct memory ptr.
function setStateElem(ptr, idx, data) {
mstore(add(ptr, shl(0x05, idx)), and(data, U64_MASK))
}
// fetch a state element from the passed `StateMatrix` struct memory ptr.
function stateElem(ptr, idx) -> elem {
elem := mload(add(ptr, shl(0x05, idx)))
}
// Inner sha3 absorb XOR function
function absorbInner(stateMatrixPtr, inputPtr, idx) {
let boWord := mload(add(inputPtr, shl(3, idx)))
let res :=
or(
or(
or(shl(56, byte(7, boWord)), shl(48, byte(6, boWord))),
or(shl(40, byte(5, boWord)), shl(32, byte(4, boWord)))
),
or(
or(shl(24, byte(3, boWord)), shl(16, byte(2, boWord))),
or(shl(8, byte(1, boWord)), byte(0, boWord))
)
)
setStateElem(stateMatrixPtr, idx, xor(stateElem(stateMatrixPtr, idx), res))
}
// Unroll the input XOR loop.
absorbInner(statePtr, dataPtr, 0)
absorbInner(statePtr, dataPtr, 1)
absorbInner(statePtr, dataPtr, 2)
absorbInner(statePtr, dataPtr, 3)
absorbInner(statePtr, dataPtr, 4)
absorbInner(statePtr, dataPtr, 5)
absorbInner(statePtr, dataPtr, 6)
absorbInner(statePtr, dataPtr, 7)
absorbInner(statePtr, dataPtr, 8)
absorbInner(statePtr, dataPtr, 9)
absorbInner(statePtr, dataPtr, 10)
absorbInner(statePtr, dataPtr, 11)
absorbInner(statePtr, dataPtr, 12)
absorbInner(statePtr, dataPtr, 13)
absorbInner(statePtr, dataPtr, 14)
absorbInner(statePtr, dataPtr, 15)
absorbInner(statePtr, dataPtr, 16)
}
}
/// @notice Squeezes the final keccak256 digest from the passed `StateMatrix`.
function squeeze(StateMatrix memory _stateMatrix) internal pure returns (bytes32 hash_) {
assembly {
// 64 bit logical shift
function shl64(a, b) -> val {
val := and(shl(a, b), U64_MASK)
}
// convert a big endian 64-bit value to a little endian 64-bit value.
function toLE(beVal) -> leVal {
beVal := or(and(shl64(8, beVal), 0xFF00FF00FF00FF00), and(shr(8, beVal), 0x00FF00FF00FF00FF))
beVal := or(and(shl64(16, beVal), 0xFFFF0000FFFF0000), and(shr(16, beVal), 0x0000FFFF0000FFFF))
leVal := or(shl64(32, beVal), shr(32, beVal))
}
// fetch a state element from the passed `StateMatrix` struct memory ptr.
function stateElem(ptr, idx) -> elem {
elem := mload(add(ptr, shl(0x05, idx)))
}
let stateMatrixPtr := add(_stateMatrix, 0x20)
hash_ :=
or(
or(shl(192, toLE(stateElem(stateMatrixPtr, 0))), shl(128, toLE(stateElem(stateMatrixPtr, 1)))),
or(shl(64, toLE(stateElem(stateMatrixPtr, 2))), toLE(stateElem(stateMatrixPtr, 3)))
)
}
}
/// @notice Pads input data to an even multiple of the Keccak-f[1600] permutation block size, 1088 bits (136 bytes).
function pad(bytes calldata _data) internal pure returns (bytes memory padded_) {
assembly {
padded_ := mload(0x40)
// Grab the original length of `_data`
let len := _data.length
let dataPtr := add(padded_, 0x20)
let endPtr := add(dataPtr, len)
// Copy the data into memory.
calldatacopy(dataPtr, _data.offset, len)
let modBlockSize := mod(len, BLOCK_SIZE_BYTES)
switch modBlockSize
case false {
// Clean the full padding block. It is possible that this memory is dirty, since solidity sometimes does
// not update the free memory pointer when allocating memory, for example with external calls. To do
// this, we read out-of-bounds from the calldata, which will always return 0 bytes.
calldatacopy(endPtr, calldatasize(), BLOCK_SIZE_BYTES)
// If the input is a perfect multiple of the block size, then we add a full extra block of padding.
mstore8(endPtr, 0x01)
mstore8(sub(add(endPtr, BLOCK_SIZE_BYTES), 0x01), 0x80)
// Update the length of the data to include the padding.
mstore(padded_, add(len, BLOCK_SIZE_BYTES))
}
default {
// If the input is not a perfect multiple of the block size, then we add a partial block of padding.
// This should entail a set bit after the input, followed by as many zero bits as necessary to fill
// the block, followed by a single 1 bit in the lowest-order bit of the final block.
let remaining := sub(BLOCK_SIZE_BYTES, modBlockSize)
let newLen := add(len, remaining)
let paddedEndPtr := add(dataPtr, newLen)
// Clean the remainder to ensure that the intermediate data between the padding bits is 0. It is
// possible that this memory is dirty, since solidity sometimes does not update the free memory pointer
// when allocating memory, for example with external calls. To do this, we read out-of-bounds from the
// calldata, which will always return 0 bytes.
let partialRemainder := sub(paddedEndPtr, endPtr)
calldatacopy(endPtr, calldatasize(), partialRemainder)
// Store the padding bits.
mstore8(sub(paddedEndPtr, 0x01), 0x80)
mstore8(endPtr, or(byte(0x00, mload(endPtr)), 0x01))
// Update the length of the data to include the padding. The length should be a multiple of the
// block size after this.
mstore(padded_, newLen)
}
// Update the free memory pointer.
mstore(0x40, add(padded_, and(add(mload(padded_), 0x3F), not(0x1F))))
}
}
/// @notice Pads input data to an even multiple of the Keccak-f[1600] permutation block size, 1088 bits (136 bytes).
function padMemory(bytes memory _data) internal pure returns (bytes memory padded_) {
assembly {
padded_ := mload(0x40)
// Grab the original length of `_data`
let len := mload(_data)
let dataPtr := add(padded_, 0x20)
let endPtr := add(dataPtr, len)
// Copy the data.
let originalDataPtr := add(_data, 0x20)
for { let i := 0x00 } lt(i, len) { i := add(i, 0x20) } {
mstore(add(dataPtr, i), mload(add(originalDataPtr, i)))
}
let modBlockSize := mod(len, BLOCK_SIZE_BYTES)
switch modBlockSize
case false {
// Clean the full padding block. It is possible that this memory is dirty, since solidity sometimes does
// not update the free memory pointer when allocating memory, for example with external calls. To do
// this, we read out-of-bounds from the calldata, which will always return 0 bytes.
calldatacopy(endPtr, calldatasize(), BLOCK_SIZE_BYTES)
// If the input is a perfect multiple of the block size, then we add a full extra block of padding.
mstore8(sub(add(endPtr, BLOCK_SIZE_BYTES), 0x01), 0x80)
mstore8(endPtr, 0x01)
// Update the length of the data to include the padding.
mstore(padded_, add(len, BLOCK_SIZE_BYTES))
}
default {
// If the input is not a perfect multiple of the block size, then we add a partial block of padding.
// This should entail a set bit after the input, followed by as many zero bits as necessary to fill
// the block, followed by a single 1 bit in the lowest-order bit of the final block.
let remaining := sub(BLOCK_SIZE_BYTES, modBlockSize)
let newLen := add(len, remaining)
let paddedEndPtr := add(dataPtr, newLen)
// Clean the remainder to ensure that the intermediate data between the padding bits is 0. It is
// possible that this memory is dirty, since solidity sometimes does not update the free memory pointer
// when allocating memory, for example with external calls. To do this, we read out-of-bounds from the
// calldata, which will always return 0 bytes.
let partialRemainder := sub(paddedEndPtr, endPtr)
calldatacopy(endPtr, calldatasize(), partialRemainder)
// Store the padding bits.
mstore8(sub(paddedEndPtr, 0x01), 0x80)
mstore8(endPtr, or(byte(0x00, mload(endPtr)), 0x01))
// Update the length of the data to include the padding. The length should be a multiple of the
// block size after this.
mstore(padded_, newLen)
}
// Update the free memory pointer.
mstore(0x40, add(padded_, and(add(mload(padded_), 0x3F), not(0x1F))))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { LibKeccak } from "@lib-keccak/LibKeccak.sol";
import { LPPMetaData } from "src/cannon/libraries/CannonTypes.sol";
interface IPreimageOracle {
struct Leaf {
bytes input;
uint256 index;
bytes32 stateCommitment;
}
error ActiveProposal();
error AlreadyFinalized();
error AlreadyInitialized();
error BadProposal();
error BondTransferFailed();
error InsufficientBond();
error InvalidInputSize();
error InvalidPreimage();
error InvalidProof();
error NotEOA();
error NotInitialized();
error PartOffsetOOB();
error PostStateMatches();
error StatesNotContiguous();
error TreeSizeOverflow();
error WrongStartingBlock();
function KECCAK_TREE_DEPTH() external view returns (uint256);
function MAX_LEAF_COUNT() external view returns (uint256);
function MIN_BOND_SIZE() external view returns (uint256);
function PRECOMPILE_CALL_RESERVED_GAS() external view returns (uint256);
function addLeavesLPP(
uint256 _uuid,
uint256 _inputStartBlock,
bytes memory _input,
bytes32[] memory _stateCommitments,
bool _finalize
)
external;
function challengeFirstLPP(
address _claimant,
uint256 _uuid,
Leaf memory _postState,
bytes32[] memory _postStateProof
)
external;
function challengeLPP(
address _claimant,
uint256 _uuid,
LibKeccak.StateMatrix memory _stateMatrix,
Leaf memory _preState,
bytes32[] memory _preStateProof,
Leaf memory _postState,
bytes32[] memory _postStateProof
)
external;
function challengePeriod() external view returns (uint256 challengePeriod_);
function getTreeRootLPP(address _owner, uint256 _uuid) external view returns (bytes32 treeRoot_);
function initLPP(uint256 _uuid, uint32 _partOffset, uint32 _claimedSize) external payable;
function loadBlobPreimagePart(
uint256 _z,
uint256 _y,
bytes memory _commitment,
bytes memory _proof,
uint256 _partOffset
)
external;
function loadKeccak256PreimagePart(uint256 _partOffset, bytes memory _preimage) external;
function loadLocalData(
uint256 _ident,
bytes32 _localContext,
bytes32 _word,
uint256 _size,
uint256 _partOffset
)
external
returns (bytes32 key_);
function loadPrecompilePreimagePart(
uint256 _partOffset,
address _precompile,
uint64 _requiredGas,
bytes memory _input
)
external;
function loadSha256PreimagePart(uint256 _partOffset, bytes memory _preimage) external;
function minProposalSize() external view returns (uint256 minProposalSize_);
function preimageLengths(bytes32) external view returns (uint256);
function preimagePartOk(bytes32, uint256) external view returns (bool);
function preimageParts(bytes32, uint256) external view returns (bytes32);
function proposalBlocks(address, uint256, uint256) external view returns (uint64);
function proposalBlocksLen(address _claimant, uint256 _uuid) external view returns (uint256 len_);
function proposalBonds(address, uint256) external view returns (uint256);
function proposalBranches(address, uint256, uint256) external view returns (bytes32);
function proposalCount() external view returns (uint256 count_);
function proposalMetadata(address, uint256) external view returns (LPPMetaData);
function proposalParts(address, uint256) external view returns (bytes32);
function proposals(uint256) external view returns (address claimant, uint256 uuid); // nosemgrep:
// sol-style-return-arg-fmt
function readPreimage(bytes32 _key, uint256 _offset) external view returns (bytes32 dat_, uint256 datLen_);
function squeezeLPP(
address _claimant,
uint256 _uuid,
LibKeccak.StateMatrix memory _stateMatrix,
Leaf memory _preState,
bytes32[] memory _preStateProof,
Leaf memory _postState,
bytes32[] memory _postStateProof
)
external;
function version() external view returns (string memory);
function zeroHashes(uint256) external view returns (bytes32);
function __constructor__(uint256 _minProposalSize, uint256 _challengePeriod) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ISemver
/// @notice ISemver is a simple contract for ensuring that contracts are
/// versioned using semantic versioning.
interface ISemver {
/// @notice Getter for the semantic version of the contract. This is not
/// meant to be used onchain but instead meant to be used by offchain
/// tooling.
/// @return Semver contract version as a string.
function version() external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
/// @title PreimageKeyLib
/// @notice Shared utilities for localizing local keys in the preimage oracle.
library PreimageKeyLib {
/// @notice Generates a context-specific local key for the given local data identifier.
/// @dev See `localize` for a description of the localization operation.
/// @param _ident The identifier of the local data. [0, 32) bytes in size.
/// @param _localContext The local context for the key.
/// @return key_ The context-specific local key.
function localizeIdent(uint256 _ident, bytes32 _localContext) internal view returns (bytes32 key_) {
assembly {
// Set the type byte in the given identifier to `1` (Local). We only care about
// the [1, 32) bytes in this value.
key_ := or(shl(248, 1), and(_ident, not(shl(248, 0xFF))))
}
// Localize the key with the given local context.
key_ = localize(key_, _localContext);
}
/// @notice Localizes a given local data key for the caller's context.
/// @dev The localization operation is defined as:
/// localize(k) = H(k .. sender .. local_context) & ~(0xFF << 248) | (0x01 << 248)
/// where H is the Keccak-256 hash function.
/// @param _key The local data key to localize.
/// @param _localContext The local context for the key.
/// @return localizedKey_ The localized local data key.
function localize(bytes32 _key, bytes32 _localContext) internal view returns (bytes32 localizedKey_) {
assembly {
// Grab the current free memory pointer to restore later.
let ptr := mload(0x40)
// Store the local data key and caller next to each other in memory for hashing.
mstore(0, _key)
mstore(0x20, caller())
mstore(0x40, _localContext)
// Localize the key with the above `localize` operation.
localizedKey_ := or(and(keccak256(0, 0x60), not(shl(248, 0xFF))), shl(248, 1))
// Restore the free memory pointer.
mstore(0x40, ptr)
}
}
/// @notice Computes and returns the key for a global keccak pre-image.
/// @param _preimage The pre-image.
/// @return key_ The pre-image key.
function keccak256PreimageKey(bytes memory _preimage) internal pure returns (bytes32 key_) {
assembly {
// Grab the size of the `_preimage`
let size := mload(_preimage)
// Compute the pre-image keccak256 hash (aka the pre-image key)
let h := keccak256(add(_preimage, 0x20), size)
// Mask out prefix byte, replace with type 2 byte
key_ := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
}
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @notice Thrown when a passed part offset is out of bounds. error PartOffsetOOB(); /// @notice Thrown when insufficient gas is provided when loading precompile preimages. error NotEnoughGas(); /// @notice Thrown when a merkle proof fails to verify. error InvalidProof(); /// @notice Thrown when the prestate preimage doesn't match the claimed preimage. error InvalidPreimage(); /// @notice Thrown when a leaf with an invalid input size is added. error InvalidInputSize(); /// @notice Thrown when data is submitted out of order in a large preimage proposal. error WrongStartingBlock(); /// @notice Thrown when the pre and post states passed aren't contiguous. error StatesNotContiguous(); /// @notice Thrown when the permutation yields the expected result. error PostStateMatches(); /// @notice Thrown when the preimage is too large to fit in the tree. error TreeSizeOverflow(); /// @notice Thrown when the preimage proposal has already been finalized. error AlreadyFinalized(); /// @notice Thrown when the proposal has not matured past the challenge period. error ActiveProposal(); /// @notice Thrown when attempting to finalize a proposal that has been challenged. error BadProposal(); /// @notice Thrown when attempting to add leaves to a preimage proposal that has not been initialized. error NotInitialized(); /// @notice Thrown when attempting to re-initialize an existing large preimage proposal. error AlreadyInitialized(); /// @notice Thrown when the caller of a function is not an EOA. error NotEOA(); /// @notice Thrown when an insufficient bond is provided for a large preimage proposal. error InsufficientBond(); /// @notice Thrown when a bond transfer fails. error BondTransferFailed(); /// @notice Thrown when the value of the exited boolean is not 0 or 1. error InvalidExitedValue(); /// @notice Thrown when reading an invalid memory error InvalidMemoryProof(); /// @notice Thrown when the second memory location is invalid error InvalidSecondMemoryProof(); /// @notice Thrown when an RMW instruction is expected, but a different instruction is provided. error InvalidRMWInstruction(); /// @notice Thrown when the state version set is not supported. error UnsupportedStateVersion();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
using LPPMetadataLib for LPPMetaData global;
/// @notice Packed LPP metadata.
/// ┌─────────────┬────────────────────────────────────────────┐
/// │ Bit Offsets │ Description │
/// ├─────────────┼────────────────────────────────────────────┤
/// │ [0, 64) │ Timestamp (Finalized - All data available) │
/// │ [64, 96) │ Part Offset │
/// │ [96, 128) │ Claimed Size │
/// │ [128, 160) │ Blocks Processed (Inclusive of Padding) │
/// │ [160, 192) │ Bytes Processed (Non-inclusive of Padding) │
/// │ [192, 256) │ Countered │
/// └─────────────┴────────────────────────────────────────────┘
type LPPMetaData is bytes32;
/// @notice LPP metadata UDT extension functions.
library LPPMetadataLib {
uint256 private constant U64_MASK = 0xFFFFFFFFFFFFFFFF;
uint256 private constant U32_MASK = 0xFFFFFFFF;
function setTimestamp(LPPMetaData _self, uint64 _timestamp) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(shl(192, _timestamp), and(_self, not(shl(192, U64_MASK))))
}
}
function setPartOffset(LPPMetaData _self, uint32 _partOffset) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(shl(160, _partOffset), and(_self, not(shl(160, U32_MASK))))
}
}
function setClaimedSize(LPPMetaData _self, uint32 _claimedSize) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(shl(128, _claimedSize), and(_self, not(shl(128, U32_MASK))))
}
}
function setBlocksProcessed(LPPMetaData _self, uint32 _blocksProcessed) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(shl(96, _blocksProcessed), and(_self, not(shl(96, U32_MASK))))
}
}
function setBytesProcessed(LPPMetaData _self, uint32 _bytesProcessed) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(shl(64, _bytesProcessed), and(_self, not(shl(64, U32_MASK))))
}
}
function setCountered(LPPMetaData _self, bool _countered) internal pure returns (LPPMetaData self_) {
assembly {
self_ := or(_countered, and(_self, not(U64_MASK)))
}
}
function timestamp(LPPMetaData _self) internal pure returns (uint64 timestamp_) {
assembly {
timestamp_ := shr(192, _self)
}
}
function partOffset(LPPMetaData _self) internal pure returns (uint64 partOffset_) {
assembly {
partOffset_ := and(shr(160, _self), U32_MASK)
}
}
function claimedSize(LPPMetaData _self) internal pure returns (uint32 claimedSize_) {
assembly {
claimedSize_ := and(shr(128, _self), U32_MASK)
}
}
function blocksProcessed(LPPMetaData _self) internal pure returns (uint32 blocksProcessed_) {
assembly {
blocksProcessed_ := and(shr(96, _self), U32_MASK)
}
}
function bytesProcessed(LPPMetaData _self) internal pure returns (uint32 bytesProcessed_) {
assembly {
bytesProcessed_ := and(shr(64, _self), U32_MASK)
}
}
function countered(LPPMetaData _self) internal pure returns (bool countered_) {
assembly {
countered_ := and(_self, U64_MASK)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library MIPS64Arch {
uint64 internal constant WORD_SIZE = 64;
uint64 internal constant WORD_SIZE_BYTES = 8;
uint64 internal constant EXT_MASK = 0x7;
uint64 internal constant ADDRESS_MASK = 0xFFFFFFFFFFFFFFF8;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Libraries
import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol";
import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol";
import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol";
library MIPS64Instructions {
uint32 internal constant OP_LOAD_LINKED = 0x30;
uint32 internal constant OP_STORE_CONDITIONAL = 0x38;
uint32 internal constant OP_LOAD_LINKED64 = 0x34;
uint32 internal constant OP_STORE_CONDITIONAL64 = 0x3C;
uint32 internal constant OP_LOAD_DOUBLE_LEFT = 0x1A;
uint32 internal constant OP_LOAD_DOUBLE_RIGHT = 0x1B;
uint32 internal constant REG_RA = 31;
uint64 internal constant U64_MASK = 0xFFFFFFFFFFFFFFFF;
uint32 internal constant U32_MASK = 0xFFffFFff;
error InvalidPC();
struct CoreStepLogicParams {
/// @param opcode The opcode value parsed from insn.
st.CpuScalars cpu;
/// @param registers The CPU registers.
uint64[32] registers;
/// @param memRoot The current merkle root of the memory.
bytes32 memRoot;
/// @param memProofOffset The offset in calldata specify where the memory merkle proof is located.
uint256 memProofOffset;
/// @param insn The current MIPS instruction at the pc.
uint32 insn;
/// @param cpu The CPU scalar fields.
uint32 opcode;
/// @param fun The function value parsed from insn.
uint32 fun;
/// @param stateVersion The state version.
uint256 stateVersion;
}
struct ExecuteMipsInstructionParams {
/// @param insn The current MIPS instruction at the pc.
uint32 insn;
/// @param opcode The opcode value parsed from insn.
uint32 opcode;
/// @param fun The function value parsed from insn.
uint32 fun;
/// @param rs The source register 1 value.
uint64 rs;
/// @param rt The source register 2 value.
uint64 rt;
/// @param mem The value fetched from memory for the current instruction.
uint64 mem;
/// @param stateVersion The state version.
uint256 stateVersion;
}
/// @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(
uint64 _pc,
bytes32 _memRoot,
uint256 _insnProofOffset
)
internal
pure
returns (uint32 insn_, uint32 opcode_, uint32 fun_)
{
unchecked {
if (_pc & 0x3 != 0) {
revert InvalidPC();
}
uint64 word = MIPS64Memory.readMem(_memRoot, _pc & arch.ADDRESS_MASK, _insnProofOffset);
insn_ = uint32(selectSubWord(_pc, word, 4, false));
opcode_ = insn_ >> 26; // First 6-bits
fun_ = insn_ & 0x3f; // Last 6-bits
return (insn_, opcode_, fun_);
}
}
/// @notice Execute core MIPS step logic.
/// @return newMemRoot_ The updated merkle root of memory after any modifications, may be unchanged.
/// @return memUpdated_ True if memory was modified.
/// @return effMemAddr_ Holds the effective address that was updated if memUpdated_ is true.
function execMipsCoreStepLogic(CoreStepLogicParams memory _args)
internal
pure
returns (bytes32 newMemRoot_, bool memUpdated_, uint64 effMemAddr_)
{
unchecked {
newMemRoot_ = _args.memRoot;
memUpdated_ = false;
effMemAddr_ = 0;
// j-type j/jal
if (_args.opcode == 2 || _args.opcode == 3) {
// Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset
uint64 target = (_args.cpu.nextPC & signExtend(0xF0000000, 32)) | uint64((_args.insn & 0x03FFFFFF) << 2);
handleJump(_args, _args.opcode == 2 ? 0 : REG_RA, target);
return (newMemRoot_, memUpdated_, effMemAddr_);
}
// register fetch
uint64 rs = 0; // source register 1 value
uint64 rt = 0; // source register 2 / temp value
uint64 rtReg = uint64((_args.insn >> 16) & 0x1F);
// R-type or I-type (stores rt)
rs = _args.registers[(_args.insn >> 21) & 0x1F];
uint64 rdReg = rtReg;
// 64-bit opcodes lwu, ldl, ldr
if (_args.opcode == 0x27 || _args.opcode == 0x1A || _args.opcode == 0x1B) {
rt = _args.registers[rtReg];
rdReg = rtReg;
} else if (_args.opcode == 0 || _args.opcode == 0x1c) {
// R-type (stores rd)
rt = _args.registers[rtReg];
rdReg = uint64((_args.insn >> 11) & 0x1F);
} else if (_args.opcode < 0x20) {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if (_args.opcode == 0xC || _args.opcode == 0xD || _args.opcode == 0xe) {
// ZeroExtImm
rt = uint64(_args.insn & 0xFFFF);
} else {
// SignExtImm
rt = signExtendImmediate(_args.insn);
}
} else if (_args.opcode >= 0x28 || _args.opcode == 0x22 || _args.opcode == 0x26) {
// store rt value with store
rt = _args.registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
if ((_args.opcode >= 4 && _args.opcode < 8) || _args.opcode == 1) {
handleBranch({
_cpu: _args.cpu,
_registers: _args.registers,
_opcode: _args.opcode,
_insn: _args.insn,
_rtReg: rtReg,
_rs: rs
});
return (newMemRoot_, memUpdated_, effMemAddr_);
}
uint64 storeAddr = U64_MASK;
// memory fetch (all I-type)
// we do the load for stores also
uint64 mem = 0;
if (_args.opcode >= 0x20 || _args.opcode == OP_LOAD_DOUBLE_LEFT || _args.opcode == OP_LOAD_DOUBLE_RIGHT) {
// M[R[rs]+SignExtImm]
rs += signExtendImmediate(_args.insn);
uint64 addr = rs & arch.ADDRESS_MASK;
mem = MIPS64Memory.readMem(_args.memRoot, addr, _args.memProofOffset);
if (_args.opcode >= 0x28) {
// store for 32-bit
// for 64-bit: ld (0x37) is the only non-store opcode >= 0x28
if (_args.opcode != 0x37) {
// store
storeAddr = addr;
// store opcodes don't write back to a register
rdReg = 0;
}
}
}
// ALU
// Note: swr outputs more than 8 bytes without the u64_mask
ExecuteMipsInstructionParams memory params = ExecuteMipsInstructionParams({
insn: _args.insn,
opcode: _args.opcode,
fun: _args.fun,
rs: rs,
rt: rt,
mem: mem,
stateVersion: _args.stateVersion
});
uint64 val = executeMipsInstruction(params) & U64_MASK;
uint64 funSel = 0x20;
if (_args.opcode == 0 && _args.fun >= 8 && _args.fun < funSel) {
if (_args.fun == 8 || _args.fun == 9) {
// jr/jalr
handleJump(_args, _args.fun == 8 ? 0 : rdReg, rs);
return (newMemRoot_, memUpdated_, effMemAddr_);
}
if (_args.fun == 0xa) {
// movz
handleRd(_args.cpu, _args.registers, rdReg, rs, rt == 0);
return (newMemRoot_, memUpdated_, effMemAddr_);
}
if (_args.fun == 0xb) {
// movn
handleRd(_args.cpu, _args.registers, rdReg, rs, rt != 0);
return (newMemRoot_, memUpdated_, effMemAddr_);
}
// lo and hi registers
// can write back
if (_args.fun >= 0x10 && _args.fun < funSel) {
handleHiLo({
_cpu: _args.cpu,
_registers: _args.registers,
_fun: _args.fun,
_rs: rs,
_rt: rt,
_storeReg: rdReg
});
return (newMemRoot_, memUpdated_, effMemAddr_);
}
}
// write memory
if (storeAddr != U64_MASK) {
newMemRoot_ = MIPS64Memory.writeMem(storeAddr, _args.memProofOffset, val);
memUpdated_ = true;
effMemAddr_ = storeAddr;
}
// write back the value to destination register
handleRd(_args.cpu, _args.registers, rdReg, val, true);
return (newMemRoot_, memUpdated_, effMemAddr_);
}
}
function signExtendImmediate(uint32 _insn) internal pure returns (uint64 offset_) {
unchecked {
return signExtend(_insn & 0xFFFF, 16);
}
}
/// @notice Execute an instruction.
function executeMipsInstruction(ExecuteMipsInstructionParams memory _args) internal pure returns (uint64 out_) {
uint32 insn = _args.insn;
uint32 opcode = _args.opcode;
uint32 fun = _args.fun;
uint64 rs = _args.rs;
uint64 rt = _args.rt;
uint64 mem = _args.mem;
uint256 stateVersion = _args.stateVersion;
unchecked {
if (opcode == 0 || (opcode >= 8 && opcode < 0xF) || opcode == 0x18 || opcode == 0x19) {
assembly {
// transform ArithLogI to SPECIAL
switch opcode
// addi
case 0x8 { fun := 0x20 }
// addiu
case 0x9 { fun := 0x21 }
// stli
case 0xA { fun := 0x2A }
// sltiu
case 0xB { fun := 0x2B }
// andi
case 0xC { fun := 0x24 }
// ori
case 0xD { fun := 0x25 }
// xori
case 0xE { fun := 0x26 }
// daddi
case 0x18 { fun := 0x2C }
// daddiu
case 0x19 { fun := 0x2D }
}
// sll
if (fun == 0x00) {
uint32 shiftAmt = (insn >> 6) & 0x1F;
return signExtend((rt << shiftAmt) & U32_MASK, 32);
}
// srl
else if (fun == 0x02) {
return signExtend((rt & U32_MASK) >> ((insn >> 6) & 0x1F), 32);
}
// sra
else if (fun == 0x03) {
uint32 shamt = (insn >> 6) & 0x1F;
return signExtend((rt & U32_MASK) >> shamt, 32 - shamt);
}
// sllv
else if (fun == 0x04) {
uint64 shiftAmt = rs & 0x1F;
return signExtend((rt << shiftAmt) & U32_MASK, 32);
}
// srlv
else if (fun == 0x6) {
return signExtend((rt & U32_MASK) >> (rs & 0x1F), 32);
}
// srav
else if (fun == 0x07) {
// shamt here is different than the typical shamt which comes from the
// instruction itself, here it comes from the rs register
uint64 shamt = rs & 0x1F;
return signExtend((rt & U32_MASK) >> shamt, 32 - shamt);
}
// functs in range [0x8, 0x1b] are handled specially by other functions
// Explicitly enumerate each funct in range to reduce code diff against Go Vm
// jr
else if (fun == 0x08) {
return rs;
}
// jalr
else if (fun == 0x09) {
return rs;
}
// movz
else if (fun == 0x0a) {
return rs;
}
// movn
else if (fun == 0x0b) {
return rs;
}
// syscall
else if (fun == 0x0c) {
return rs;
}
// 0x0d - break not supported
// sync
else if (fun == 0x0f) {
return rs;
}
// mfhi
else if (fun == 0x10) {
return rs;
}
// mthi
else if (fun == 0x11) {
return rs;
}
// mflo
else if (fun == 0x12) {
return rs;
}
// mtlo
else if (fun == 0x13) {
return rs;
}
// dsllv
else if (fun == 0x14) {
return rt;
}
// dsrlv
else if (fun == 0x16) {
return rt;
}
// dsrav
else if (fun == 0x17) {
return rt;
}
// mult
else if (fun == 0x18) {
return rs;
}
// multu
else if (fun == 0x19) {
return rs;
}
// div
else if (fun == 0x1a) {
return rs;
}
// divu
else if (fun == 0x1b) {
return rs;
}
// dmult
else if (fun == 0x1c) {
return rs;
}
// dmultu
else if (fun == 0x1d) {
return rs;
}
// ddiv
else if (fun == 0x1e) {
return rs;
}
// ddivu
else if (fun == 0x1f) {
return rs;
}
// The rest includes transformed R-type arith imm instructions
// add
else if (fun == 0x20) {
return signExtend(uint64(uint32(rs) + uint32(rt)), 32);
}
// addu
else if (fun == 0x21) {
return signExtend(uint64(uint32(rs) + uint32(rt)), 32);
}
// sub
else if (fun == 0x22) {
return signExtend(uint64(uint32(rs) - uint32(rt)), 32);
}
// subu
else if (fun == 0x23) {
return signExtend(uint64(uint32(rs) - uint32(rt)), 32);
}
// and
else if (fun == 0x24) {
return (rs & rt);
}
// or
else if (fun == 0x25) {
return (rs | rt);
}
// xor
else if (fun == 0x26) {
return (rs ^ rt);
}
// nor
else if (fun == 0x27) {
return ~(rs | rt);
}
// slti
else if (fun == 0x2a) {
return int64(rs) < int64(rt) ? 1 : 0;
}
// sltiu
else if (fun == 0x2b) {
return rs < rt ? 1 : 0;
}
// dadd
else if (fun == 0x2c) {
return (rs + rt);
}
// daddu
else if (fun == 0x2d) {
return (rs + rt);
}
// dsub
else if (fun == 0x2e) {
return (rs - rt);
}
// dsubu
else if (fun == 0x2f) {
return (rs - rt);
}
// dsll
else if (fun == 0x38) {
return rt << ((insn >> 6) & 0x1f);
}
// dsrl
else if (fun == 0x3A) {
return rt >> ((insn >> 6) & 0x1f);
}
// dsra
else if (fun == 0x3B) {
return uint64(int64(rt) >> ((insn >> 6) & 0x1f));
}
// dsll32
else if (fun == 0x3c) {
return rt << (((insn >> 6) & 0x1f) + 32);
}
// dsrl32
else if (fun == 0x3e) {
return rt >> (((insn >> 6) & 0x1f) + 32);
}
// dsra32
else if (fun == 0x3f) {
return uint64(int64(rt) >> (((insn >> 6) & 0x1f) + 32));
} else {
revert("MIPS64: invalid instruction");
}
} else {
// SPECIAL2
if (opcode == 0x1C) {
// mul
if (fun == 0x2) {
return signExtend(uint32(int32(uint32(rs)) * int32(uint32(rt))), 32);
}
// clz, clo
else if (fun == 0x20 || fun == 0x21) {
if (fun == 0x20) {
rs = ~rs;
}
uint32 i = 0;
while (rs & 0x80000000 != 0) {
i++;
rs <<= 1;
}
return i;
}
// dclz, dclo
else if (st.featuresForVersion(stateVersion).supportDclzDclo && (fun == 0x24 || fun == 0x25)) {
if (fun == 0x24) {
rs = ~rs;
}
uint32 i = 0;
while (rs & 0x80000000_00000000 != 0) {
i++;
rs <<= 1;
}
return i;
}
}
// lui
else if (opcode == 0x0F) {
return signExtend(rt << 16, 32);
}
// lb
else if (opcode == 0x20) {
return selectSubWord(rs, mem, 1, true);
}
// lh
else if (opcode == 0x21) {
return selectSubWord(rs, mem, 2, true);
}
// lwl
else if (opcode == 0x22) {
uint32 w = uint32(selectSubWord(rs, mem, 4, false));
uint32 val = w << uint32((rs & 3) * 8);
uint64 mask = uint64(U32_MASK << uint32((rs & 3) * 8));
return signExtend(((rt & ~mask) | uint64(val)) & U32_MASK, 32);
}
// lw
else if (opcode == 0x23) {
return selectSubWord(rs, mem, 4, true);
}
// lbu
else if (opcode == 0x24) {
return selectSubWord(rs, mem, 1, false);
}
// lhu
else if (opcode == 0x25) {
return selectSubWord(rs, mem, 2, false);
}
// lwr
else if (opcode == 0x26) {
uint32 w = uint32(selectSubWord(rs, mem, 4, false));
uint32 val = w >> (24 - (rs & 3) * 8);
uint32 mask = U32_MASK >> (24 - (rs & 3) * 8);
uint64 lwrResult = (uint32(rt) & ~mask) | val;
if (rs & 3 == 3) {
// loaded bit 31
return signExtend(uint64(lwrResult), 32);
} else {
// NOTE: cannon64 implementation specific: We leave the upper word untouched
uint64 rtMask = 0xFF_FF_FF_FF_00_00_00_00;
return ((rt & rtMask) | uint64(lwrResult));
}
}
// sb
else if (opcode == 0x28) {
return updateSubWord(rs, mem, 1, rt);
}
// sh
else if (opcode == 0x29) {
return updateSubWord(rs, mem, 2, rt);
}
// swl
else if (opcode == 0x2a) {
uint64 sr = (rs & 3) << 3;
uint64 val = ((rt & U32_MASK) >> sr) << (32 - ((rs & 0x4) << 3));
uint64 mask = (uint64(U32_MASK) >> sr) << (32 - ((rs & 0x4) << 3));
return (mem & ~mask) | val;
}
// sw
else if (opcode == 0x2b) {
return updateSubWord(rs, mem, 4, rt);
}
// swr
else if (opcode == 0x2e) {
uint32 w = uint32(selectSubWord(rs, mem, 4, false));
uint64 val = rt << (24 - (rs & 3) * 8);
uint64 mask = U32_MASK << uint32(24 - (rs & 3) * 8);
uint64 swrResult = (w & ~mask) | uint32(val);
return updateSubWord(rs, mem, 4, swrResult);
}
// MIPS64
// ldl
else if (opcode == 0x1a) {
uint64 sl = (rs & 0x7) << 3;
uint64 val = mem << sl;
uint64 mask = U64_MASK << sl;
return (val | (rt & ~mask));
}
// ldr
else if (opcode == 0x1b) {
uint64 sr = 56 - ((rs & 0x7) << 3);
uint64 val = mem >> sr;
uint64 mask = U64_MASK << (64 - sr);
return (val | (rt & mask));
}
// lwu
else if (opcode == 0x27) {
return ((mem >> (32 - ((rs & 0x4) << 3))) & U32_MASK);
}
// sdl
else if (opcode == 0x2c) {
uint64 sr = (rs & 0x7) << 3;
uint64 val = rt >> sr;
uint64 mask = U64_MASK >> sr;
return (val | (mem & ~mask));
}
// sdr
else if (opcode == 0x2d) {
uint64 sl = 56 - ((rs & 0x7) << 3);
uint64 val = rt << sl;
uint64 mask = U64_MASK << sl;
return (val | (mem & ~mask));
}
// ld
else if (opcode == 0x37) {
return mem;
}
// sd
else if (opcode == 0x3F) {
return rt;
} else {
revert("MIPS64: invalid instruction");
}
}
revert("MIPS64: invalid instruction");
}
}
/// @notice Extends the value leftwards with its most significant bit (sign extension).
function signExtend(uint64 _dat, uint64 _idx) internal pure returns (uint64 out_) {
unchecked {
bool isSigned = (_dat >> (_idx - 1)) & 1 != 0;
uint256 signed = ((1 << (arch.WORD_SIZE - _idx)) - 1) << _idx;
uint256 mask = (1 << _idx) - 1;
return uint64(_dat & mask | (isSigned ? signed : 0));
}
}
/// @notice Handles a branch instruction, updating the MIPS state PC where needed.
/// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo.
/// @param _registers Holds the current state of the cpu registers.
/// @param _opcode The opcode of the branch instruction.
/// @param _insn The instruction to be executed.
/// @param _rtReg The register to be used for the branch.
/// @param _rs The register to be compared with the branch register.
function handleBranch(
st.CpuScalars memory _cpu,
uint64[32] memory _registers,
uint32 _opcode,
uint32 _insn,
uint64 _rtReg,
uint64 _rs
)
internal
pure
{
unchecked {
bool shouldBranch = false;
if (_cpu.nextPC != _cpu.pc + 4) {
revert("MIPS64: branch in delay slot");
}
// beq/bne: Branch on equal / not equal
if (_opcode == 4 || _opcode == 5) {
uint64 rt = _registers[_rtReg];
shouldBranch = (_rs == rt && _opcode == 4) || (_rs != rt && _opcode == 5);
}
// blez: Branches if instruction is less than or equal to zero
else if (_opcode == 6) {
shouldBranch = int64(_rs) <= 0;
}
// bgtz: Branches if instruction is greater than zero
else if (_opcode == 7) {
shouldBranch = int64(_rs) > 0;
}
// bltz/bgez: Branch on less than zero / greater than or equal to zero
else if (_opcode == 1) {
// regimm
uint32 rtv = ((_insn >> 16) & 0x1F);
if (rtv == 0) {
shouldBranch = int64(_rs) < 0;
}
// bltzal
if (rtv == 0x10) {
shouldBranch = int64(_rs) < 0;
_registers[REG_RA] = _cpu.pc + 8; // always set regardless of branch taken
}
if (rtv == 1) {
shouldBranch = int64(_rs) >= 0;
}
// bgezal (i.e. bal mnemonic)
if (rtv == 0x11) {
shouldBranch = int64(_rs) >= 0;
_registers[REG_RA] = _cpu.pc + 8; // always set regardless of branch taken
}
}
// Update the state's previous PC
uint64 prevPC = _cpu.pc;
// Execute the delay slot first
_cpu.pc = _cpu.nextPC;
// If we should branch, update the PC to the branch target
// Otherwise, proceed to the next instruction
if (shouldBranch) {
_cpu.nextPC = prevPC + 4 + (signExtend(_insn & 0xFFFF, 16) << 2);
} else {
_cpu.nextPC = _cpu.nextPC + 4;
}
}
}
/// @notice Handles HI and LO register instructions. It also additionally handles doubleword variable shift
/// operations
/// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo.
/// @param _registers Holds the current state of the cpu registers.
/// @param _fun The function code of the instruction.
/// @param _rs The value of the RS register.
/// @param _rt The value of the RT register.
/// @param _storeReg The register to store the result in.
function handleHiLo(
st.CpuScalars memory _cpu,
uint64[32] memory _registers,
uint32 _fun,
uint64 _rs,
uint64 _rt,
uint64 _storeReg
)
internal
pure
{
unchecked {
uint64 val = 0;
// mfhi: Move the contents of the HI register into the destination
if (_fun == 0x10) {
val = _cpu.hi;
}
// mthi: Move the contents of the source into the HI register
else if (_fun == 0x11) {
_cpu.hi = _rs;
}
// mflo: Move the contents of the LO register into the destination
else if (_fun == 0x12) {
val = _cpu.lo;
}
// mtlo: Move the contents of the source into the LO register
else if (_fun == 0x13) {
_cpu.lo = _rs;
}
// mult: Multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_fun == 0x18) {
uint64 acc = uint64(int64(int32(uint32(_rs))) * int64(int32(uint32(_rt))));
_cpu.hi = signExtend(uint64(acc >> 32), 32);
_cpu.lo = signExtend(uint64(uint32(acc)), 32);
}
// multu: Unsigned multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_fun == 0x19) {
uint64 acc = uint64(uint32(_rs)) * uint64(uint32(_rt));
_cpu.hi = signExtend(uint64(acc >> 32), 32);
_cpu.lo = signExtend(uint64(uint32(acc)), 32);
}
// div: Divides `rs` by `rt`.
// Stores the quotient in LO
// And the remainder in HI
else if (_fun == 0x1a) {
if (uint32(_rt) == 0) {
revert("MIPS64: division by zero");
}
_cpu.hi = signExtend(uint32(int32(uint32(_rs)) % int32(uint32(_rt))), 32);
_cpu.lo = signExtend(uint32(int32(uint32(_rs)) / int32(uint32(_rt))), 32);
}
// divu: Unsigned divides `rs` by `rt`.
// Stores the quotient in LO
// And the remainder in HI
else if (_fun == 0x1b) {
if (uint32(_rt) == 0) {
revert("MIPS64: division by zero");
}
_cpu.hi = signExtend(uint64(uint32(_rs) % uint32(_rt)), 32);
_cpu.lo = signExtend(uint64(uint32(_rs) / uint32(_rt)), 32);
}
// dsllv
else if (_fun == 0x14) {
val = _rt << (_rs & 0x3F);
}
// dsrlv
else if (_fun == 0x16) {
val = _rt >> (_rs & 0x3F);
}
// dsrav
else if (_fun == 0x17) {
val = uint64(int64(_rt) >> (_rs & 0x3F));
}
// dmult
else if (_fun == 0x1c) {
int128 res = int128(int64(_rs)) * int128(int64(_rt));
_cpu.hi = uint64(int64(res >> 64));
_cpu.lo = uint64(uint128(res) & U64_MASK);
}
// dmultu
else if (_fun == 0x1d) {
uint128 res = uint128(_rs) * uint128(_rt);
_cpu.hi = uint64(res >> 64);
_cpu.lo = uint64(res);
}
// ddiv
else if (_fun == 0x1e) {
if (_rt == 0) {
revert("MIPS64: division by zero");
}
_cpu.hi = uint64(int64(_rs) % int64(_rt));
_cpu.lo = uint64(int64(_rs) / int64(_rt));
}
// ddivu
else if (_fun == 0x1f) {
if (_rt == 0) {
revert("MIPS64: division by zero");
}
_cpu.hi = _rs % _rt;
_cpu.lo = _rs / _rt;
}
// Store the result in the destination register, if applicable
if (_storeReg != 0) {
_registers[_storeReg] = val;
}
// Update the PC
_cpu.pc = _cpu.nextPC;
_cpu.nextPC = _cpu.nextPC + 4;
}
}
/// @notice Handles a jump instruction, updating the MIPS state PC where needed.
/// @dev The _cpuAndRegisters is stored in memory to avoid stack limit issues.
/// @param _cpuAndRegisters Holds the state of cpu scalars (pc, nextPC, hi, lo) and the current state of the cpu
/// registers.
/// @param _linkReg The register to store the link to the instruction after the delay slot instruction.
/// @param _dest The destination to jump to.
function handleJump(CoreStepLogicParams memory _cpuAndRegisters, uint64 _linkReg, uint64 _dest) internal pure {
unchecked {
if (_cpuAndRegisters.cpu.nextPC != _cpuAndRegisters.cpu.pc + 4) {
revert("MIPS64: jump in delay slot");
}
// Update the next PC to the jump destination.
uint64 prevPC = _cpuAndRegisters.cpu.pc;
_cpuAndRegisters.cpu.pc = _cpuAndRegisters.cpu.nextPC;
_cpuAndRegisters.cpu.nextPC = _dest;
// Update the link-register to the instruction after the delay slot instruction.
if (_linkReg != 0) {
_cpuAndRegisters.registers[_linkReg] = prevPC + 8;
}
}
}
/// @notice Handles a storing a value into a register.
/// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo.
/// @param _registers Holds the current state of the cpu registers.
/// @param _storeReg The register to store the value into.
/// @param _val The value to store.
/// @param _conditional Whether or not the store is conditional.
function handleRd(
st.CpuScalars memory _cpu,
uint64[32] memory _registers,
uint64 _storeReg,
uint64 _val,
bool _conditional
)
internal
pure
{
unchecked {
// The destination register must be valid.
require(_storeReg < 32, "MIPS64: valid register");
// Never write to reg 0, and it can be conditional (movz, movn).
if (_storeReg != 0 && _conditional) {
_registers[_storeReg] = _val;
}
// Update the PC.
_cpu.pc = _cpu.nextPC;
_cpu.nextPC = _cpu.nextPC + 4;
}
}
/// @notice Selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr
/// @param _vaddr The virtual address of the the subword.
/// @param _memWord The full word to select a subword from.
/// @param _byteLength The size of the subword.
/// @param _signExtend Whether to sign extend the selected subwrod.
function selectSubWord(
uint64 _vaddr,
uint64 _memWord,
uint64 _byteLength,
bool _signExtend
)
internal
pure
returns (uint64 retval_)
{
(uint64 dataMask, uint64 bitOffset, uint64 bitLength) = calculateSubWordMaskAndOffset(_vaddr, _byteLength);
retval_ = (_memWord >> bitOffset) & dataMask;
if (_signExtend) {
retval_ = signExtend(retval_, bitLength);
}
return retval_;
}
/// @notice Returns a word that has been updated by the specified subword at bit positions determined by the virtual
/// address
/// @param _vaddr The virtual address of the subword.
/// @param _memWord The full word to update.
/// @param _byteLength The size of the subword.
/// @param _value The subword that updates _memWord.
function updateSubWord(
uint64 _vaddr,
uint64 _memWord,
uint64 _byteLength,
uint64 _value
)
internal
pure
returns (uint64 word_)
{
(uint64 dataMask, uint64 bitOffset,) = calculateSubWordMaskAndOffset(_vaddr, _byteLength);
uint64 subWordValue = dataMask & _value;
uint64 memUpdateMask = dataMask << bitOffset;
return subWordValue << bitOffset | (~memUpdateMask) & _memWord;
}
function calculateSubWordMaskAndOffset(
uint64 _vaddr,
uint64 _byteLength
)
internal
pure
returns (uint64 dataMask_, uint64 bitOffset_, uint64 bitLength_)
{
uint64 bitLength = _byteLength << 3;
uint64 dataMask = ~uint64(0) >> (arch.WORD_SIZE - bitLength);
// Figure out sub-word index based on the low-order bits in vaddr
uint64 byteIndexMask = _vaddr & arch.EXT_MASK & ~(_byteLength - 1);
uint64 maxByteShift = arch.WORD_SIZE_BYTES - _byteLength;
uint64 byteIndex = _vaddr & byteIndexMask;
uint64 bitOffset = (maxByteShift - byteIndex) << 3;
return (dataMask, bitOffset, bitLength);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Libraries
import { InvalidMemoryProof } from "src/cannon/libraries/CannonErrors.sol";
library MIPS64Memory {
uint64 internal constant EXT_MASK = 0x7;
uint64 internal constant MEM_PROOF_LEAF_COUNT = 60;
uint256 internal constant U64_MASK = 0xFFFFFFFFFFFFFFFF;
/// @notice Reads a 64-bit word from memory.
/// @param _memRoot The current memory root
/// @param _addr The address to read from.
/// @param _proofOffset The offset of the memory proof in calldata.
/// @return out_ The hashed MIPS state.
function readMem(bytes32 _memRoot, uint64 _addr, uint256 _proofOffset) internal pure returns (uint64 out_) {
bool valid;
(out_, valid) = readMemUnchecked(_memRoot, _addr, _proofOffset);
if (!valid) {
revert InvalidMemoryProof();
}
}
/// @notice Reads a 64-bit word from memory.
/// @param _memRoot The current memory root
/// @param _addr The address to read from.
/// @param _proofOffset The offset of the memory proof in calldata.
/// @return out_ The hashed MIPS state.
/// valid_ Whether the proof is valid.
function readMemUnchecked(
bytes32 _memRoot,
uint64 _addr,
uint256 _proofOffset
)
internal
pure
returns (uint64 out_, bool valid_)
{
unchecked {
validateMemoryProofAvailability(_proofOffset);
assembly {
// Validate the address alignment.
if and(_addr, EXT_MASK) {
// revert InvalidAddress();
let ptr := mload(0x40)
mstore(ptr, shl(224, 0xe6c4247b))
revert(ptr, 0x4)
}
// Load the leaf value.
let leaf := calldataload(_proofOffset)
_proofOffset := add(_proofOffset, 32)
// Convenience function to hash two nodes together in scratch space.
function hashPair(a, b) -> h {
mstore(0, a)
mstore(32, b)
h := keccak256(0, 64)
}
// Start with the leaf node.
// Work back up by combining with siblings, to reconstruct the root.
let path := shr(5, _addr)
let node := leaf
let end := sub(MEM_PROOF_LEAF_COUNT, 1)
for { let i := 0 } lt(i, end) { i := add(i, 1) } {
let sibling := calldataload(_proofOffset)
_proofOffset := add(_proofOffset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
// Verify the root matches.
valid_ := eq(node, _memRoot)
if valid_ {
// Bits to shift = (32 - 8 - (addr % 32)) * 8
let shamt := shl(3, sub(sub(32, 8), and(_addr, 31)))
out_ := and(shr(shamt, leaf), U64_MASK)
}
}
}
}
/// @notice Writes a 64-bit word to memory.
/// This function first overwrites the part of the leaf.
/// Then it recomputes the memory merkle root.
/// @param _addr The address to write to.
/// @param _proofOffset The offset of the memory proof in calldata.
/// @param _val The value to write.
/// @return newMemRoot_ The new memory root after modification
function writeMem(uint64 _addr, uint256 _proofOffset, uint64 _val) internal pure returns (bytes32 newMemRoot_) {
unchecked {
validateMemoryProofAvailability(_proofOffset);
assembly {
// Validate the address alignment.
if and(_addr, EXT_MASK) {
// revert InvalidAddress();
let ptr := mload(0x40)
mstore(ptr, shl(224, 0xe6c4247b))
revert(ptr, 0x4)
}
// Load the leaf value.
let leaf := calldataload(_proofOffset)
let shamt := shl(3, sub(sub(32, 8), and(_addr, 31)))
// Mask out 8 bytes, and OR in the value
leaf := or(and(leaf, not(shl(shamt, U64_MASK))), shl(shamt, _val))
_proofOffset := add(_proofOffset, 32)
// Convenience function to hash two nodes together in scratch space.
function hashPair(a, b) -> h {
mstore(0, a)
mstore(32, b)
h := keccak256(0, 64)
}
// Start with the leaf node.
// Work back up by combining with siblings, to reconstruct the root.
let path := shr(5, _addr)
let node := leaf
let end := sub(MEM_PROOF_LEAF_COUNT, 1)
for { let i := 0 } lt(i, end) { i := add(i, 1) } {
let sibling := calldataload(_proofOffset)
_proofOffset := add(_proofOffset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
newMemRoot_ := node
}
return newMemRoot_;
}
}
/// @notice Verifies a memory proof.
/// @param _memRoot The expected memory root
/// @param _addr The _addr proven.
/// @param _proofOffset The offset of the memory proof in calldata.
/// @return valid_ True iff it is a valid proof.
function isValidProof(bytes32 _memRoot, uint64 _addr, uint256 _proofOffset) internal pure returns (bool valid_) {
(, valid_) = readMemUnchecked(_memRoot, _addr, _proofOffset);
}
/// @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)
/// Equal to the offset of the first memory proof (at _proofIndex 0).
/// @param _proofIndex The index of the proof in the calldata.
/// @return offset_ The offset of the memory proof at the given _proofIndex in the calldata.
function memoryProofOffset(uint256 _proofDataOffset, uint8 _proofIndex) internal pure returns (uint256 offset_) {
unchecked {
// A proof of 64-bit memory, with 32-byte leaf values, is (64-5)=59 bytes32 entries.
// And the leaf value itself needs to be encoded as well: (59 + 1) = 60 bytes32 entries.
offset_ = _proofDataOffset + (uint256(_proofIndex) * (MEM_PROOF_LEAF_COUNT * 32));
return 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
function validateMemoryProofAvailability(uint256 _proofStartOffset) internal pure {
unchecked {
uint256 s = 0;
assembly {
s := calldatasize()
}
// A memory proof consists of MEM_PROOF_LEAF_COUNT bytes32 values - verify we have enough calldata
require(
s >= (_proofStartOffset + MEM_PROOF_LEAF_COUNT * 32),
"MIPS64Memory: check that there is enough calldata"
);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Libraries
import { InvalidExitedValue } from "src/cannon/libraries/CannonErrors.sol";
library MIPS64State {
struct CpuScalars {
uint64 pc;
uint64 nextPC;
uint64 lo;
uint64 hi;
}
struct Features {
bool supportMinimalSysEventFd2;
bool supportDclzDclo;
bool supportNoopMprotect;
bool supportWorkingSysGetRandom;
}
function assertExitedIsValid(uint32 _exited) internal pure {
if (_exited > 1) {
revert InvalidExitedValue();
}
}
function featuresForVersion(uint256 _version) internal pure returns (Features memory features_) {
if (_version >= 7) {
features_.supportMinimalSysEventFd2 = true;
features_.supportDclzDclo = true;
features_.supportNoopMprotect = true;
}
if (_version >= 8) {
features_.supportWorkingSysGetRandom = true;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Libraries
import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol";
import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol";
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
import { PreimageKeyLib } from "src/cannon/PreimageKeyLib.sol";
import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol";
library MIPS64Syscalls {
struct SysReadParams {
/// @param _a0 The file descriptor.
uint64 a0;
/// @param _a1 The memory location where data should be read to.
uint64 a1;
/// @param _a2 The number of bytes to read from the file
uint64 a2;
/// @param _preimageKey The key of the preimage to read.
bytes32 preimageKey;
/// @param _preimageOffset The offset of the preimage to read.
uint64 preimageOffset;
/// @param _localContext The local context for the preimage key.
bytes32 localContext;
/// @param _oracle The address of the preimage oracle.
IPreimageOracle oracle;
/// @param _proofOffset The offset of the memory proof in calldata.
uint256 proofOffset;
/// @param _memRoot The current memory root.
bytes32 memRoot;
}
/// @custom:field _a0 The file descriptor.
/// @custom:field _a1 The memory address to read from.
/// @custom:field _a2 The number of bytes to read.
/// @custom:field _preimageKey The current preimaageKey.
/// @custom:field _preimageOffset The current preimageOffset.
/// @custom:field _proofOffset The offset of the memory proof in calldata.
/// @custom:field _memRoot The current memory root.
struct SysWriteParams {
uint64 _a0;
uint64 _a1;
uint64 _a2;
bytes32 _preimageKey;
uint64 _preimageOffset;
uint256 _proofOffset;
bytes32 _memRoot;
}
uint64 internal constant U64_MASK = 0xFFffFFffFFffFFff;
uint64 internal constant PAGE_ADDR_MASK = 4095;
uint64 internal constant PAGE_SIZE = 4096;
uint32 internal constant SYS_MMAP = 5009;
uint32 internal constant SYS_MPROTECT = 5010;
uint32 internal constant SYS_BRK = 5012;
uint32 internal constant SYS_CLONE = 5055;
uint32 internal constant SYS_EXIT_GROUP = 5205;
uint32 internal constant SYS_READ = 5000;
uint32 internal constant SYS_WRITE = 5001;
uint32 internal constant SYS_FCNTL = 5070;
uint32 internal constant SYS_EXIT = 5058;
uint32 internal constant SYS_SCHED_YIELD = 5023;
uint32 internal constant SYS_GETTID = 5178;
uint32 internal constant SYS_FUTEX = 5194;
uint32 internal constant SYS_OPEN = 5002;
uint32 internal constant SYS_NANOSLEEP = 5034;
uint32 internal constant SYS_CLOCKGETTIME = 5222;
uint32 internal constant SYS_GETPID = 5038;
uint32 internal constant SYS_GETRANDOM = 5313;
// no-op syscalls
uint32 internal constant SYS_MUNMAP = 5011;
uint32 internal constant SYS_GETAFFINITY = 5196;
uint32 internal constant SYS_MADVISE = 5027;
uint32 internal constant SYS_RTSIGPROCMASK = 5014;
uint32 internal constant SYS_SIGALTSTACK = 5129;
uint32 internal constant SYS_RTSIGACTION = 5013;
uint32 internal constant SYS_PRLIMIT64 = 5297;
uint32 internal constant SYS_CLOSE = 5003;
uint32 internal constant SYS_PREAD64 = 5016;
uint32 internal constant SYS_STAT = 5004;
uint32 internal constant SYS_FSTAT = 5005;
//uint32 internal constant SYS_FSTAT64 = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64
uint32 internal constant SYS_OPENAT = 5247;
uint32 internal constant SYS_READLINK = 5087;
uint32 internal constant SYS_READLINKAT = 5257;
uint32 internal constant SYS_IOCTL = 5015;
uint32 internal constant SYS_EPOLLCREATE1 = 5285;
uint32 internal constant SYS_PIPE2 = 5287;
uint32 internal constant SYS_EPOLLCTL = 5208;
uint32 internal constant SYS_EPOLLPWAIT = 5272;
uint32 internal constant SYS_UNAME = 5061;
//uint32 internal constant SYS_STAT64 = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64
uint32 internal constant SYS_GETUID = 5100;
uint32 internal constant SYS_GETGID = 5102;
//uint32 internal constant SYS_LLSEEK = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64
uint32 internal constant SYS_MINCORE = 5026;
uint32 internal constant SYS_TGKILL = 5225;
uint32 internal constant SYS_GETRLIMIT = 5095;
uint32 internal constant SYS_LSEEK = 5008;
uint32 internal constant SYS_EVENTFD2 = 5284;
// profiling-related syscalls - ignored
uint32 internal constant SYS_SETITIMER = 5036;
uint32 internal constant SYS_TIMERCREATE = 5216;
uint32 internal constant SYS_TIMERSETTIME = 5217;
uint32 internal constant SYS_TIMERDELETE = 5220;
uint32 internal constant FD_STDIN = 0;
uint32 internal constant FD_STDOUT = 1;
uint32 internal constant FD_STDERR = 2;
uint32 internal constant FD_HINT_READ = 3;
uint32 internal constant FD_HINT_WRITE = 4;
uint32 internal constant FD_PREIMAGE_READ = 5;
uint32 internal constant FD_PREIMAGE_WRITE = 6;
uint64 internal constant FD_EVENTFD = 100;
uint64 internal constant SYS_ERROR_SIGNAL = U64_MASK;
uint64 internal constant EBADF = 0x9;
uint64 internal constant EINVAL = 0x16;
uint64 internal constant EAGAIN = 0xb;
uint64 internal constant ETIMEDOUT = 0x91;
uint64 internal constant FUTEX_WAIT_PRIVATE = 128;
uint64 internal constant FUTEX_WAKE_PRIVATE = 129;
uint64 internal constant SCHED_QUANTUM = 100_000;
uint64 internal constant HZ = 10_000_000;
uint64 internal constant CLOCK_GETTIME_REALTIME_FLAG = 0;
uint64 internal constant CLOCK_GETTIME_MONOTONIC_FLAG = 1;
/// @notice Start of the data segment.
uint64 internal constant PROGRAM_BREAK = 0x00_00_40_00_00_00_00_00;
uint64 internal constant HEAP_END = 0x00_00_60_00_00_00_00_00;
// SYS_CLONE flags
uint64 internal constant CLONE_VM = 0x100;
uint64 internal constant CLONE_FS = 0x200;
uint64 internal constant CLONE_FILES = 0x400;
uint64 internal constant CLONE_SIGHAND = 0x800;
uint64 internal constant CLONE_PTRACE = 0x2000;
uint64 internal constant CLONE_VFORK = 0x4000;
uint64 internal constant CLONE_PARENT = 0x8000;
uint64 internal constant CLONE_THREAD = 0x10000;
uint64 internal constant CLONE_NEWNS = 0x20000;
uint64 internal constant CLONE_SYSVSEM = 0x40000;
uint64 internal constant CLONE_SETTLS = 0x80000;
uint64 internal constant CLONE_PARENTSETTID = 0x100000;
uint64 internal constant CLONE_CHILDCLEARTID = 0x200000;
uint64 internal constant CLONE_UNTRACED = 0x800000;
uint64 internal constant CLONE_CHILDSETTID = 0x1000000;
uint64 internal constant CLONE_STOPPED = 0x2000000;
uint64 internal constant CLONE_NEWUTS = 0x4000000;
uint64 internal constant CLONE_NEWIPC = 0x8000000;
uint64 internal constant VALID_SYS_CLONE_FLAGS =
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM | CLONE_THREAD;
// eventfd flags
// From:
// https://github.com/golang/go/blob/7a2cfb70b01f069c2125adcf7126d7f3376cb8b7/src/internal/runtime/syscall/defs_linux_mips64x.go#L18-L18
uint64 internal constant EFD_NONBLOCK = 0x80;
// FYI: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File
// https://refspecs.linuxfoundation.org/elf/mipsabi.pdf
uint32 internal constant REG_V0 = 2;
uint32 internal constant REG_A0 = 4;
uint32 internal constant REG_A1 = 5;
uint32 internal constant REG_A2 = 6;
uint32 internal constant REG_A3 = 7;
// FYI: https://web.archive.org/web/20231223163047/https://www.linux-mips.org/wiki/Syscall
uint32 internal constant REG_SYSCALL_NUM = REG_V0;
uint32 internal constant REG_SYSCALL_ERRNO = REG_A3;
uint32 internal constant REG_SYSCALL_RET1 = REG_V0;
uint32 internal constant REG_SYSCALL_PARAM1 = REG_A0;
uint32 internal constant REG_SYSCALL_PARAM2 = REG_A1;
uint32 internal constant REG_SYSCALL_PARAM3 = REG_A2;
// Constants copied from MIPS64Arch for use in Yul
uint64 internal constant WORD_SIZE_BYTES = 8;
uint64 internal constant EXT_MASK = 0x7;
/// @notice Extract syscall num and arguments from registers.
/// @param _registers The cpu registers.
/// @return sysCallNum_ The syscall number.
/// @return a0_ The first argument available to the syscall operation.
/// @return a1_ The second argument available to the syscall operation.
/// @return a2_ The third argument available to the syscall operation.
function getSyscallArgs(uint64[32] memory _registers)
internal
pure
returns (uint64 sysCallNum_, uint64 a0_, uint64 a1_, uint64 a2_)
{
unchecked {
sysCallNum_ = _registers[REG_SYSCALL_NUM];
a0_ = _registers[REG_SYSCALL_PARAM1];
a1_ = _registers[REG_SYSCALL_PARAM2];
a2_ = _registers[REG_SYSCALL_PARAM3];
return (sysCallNum_, a0_, a1_, a2_);
}
}
/// @notice Like a Linux mmap syscall. Allocates a page from the heap.
/// @param _a0 The address for the new mapping
/// @param _a1 The size of the new mapping
/// @param _heap The current value of the heap pointer
/// @return v0_ The address of the new mapping or error code on error
/// @return v1_ 0 if there is no error, non-zero on error
/// @return newHeap_ The new value for the heap, may be unchanged
function handleSysMmap(
uint64 _a0,
uint64 _a1,
uint64 _heap
)
internal
pure
returns (uint64 v0_, uint64 v1_, uint64 newHeap_)
{
unchecked {
v1_ = uint64(0);
newHeap_ = _heap;
uint64 sz = _a1;
if (sz & PAGE_ADDR_MASK != 0) {
// adjust size to align with page size
sz += PAGE_SIZE - (sz & PAGE_ADDR_MASK);
}
if (_a0 == 0) {
v0_ = _heap;
newHeap_ += sz;
// Fail if new heap exceeds memory limit, newHeap overflows to low memory, or sz overflows
if (newHeap_ > HEAP_END || newHeap_ < _heap || sz < _a1) {
v0_ = EINVAL;
v1_ = SYS_ERROR_SIGNAL;
return (v0_, v1_, _heap);
}
} else {
v0_ = _a0;
}
return (v0_, v1_, newHeap_);
}
}
/// @notice Like a Linux read syscall. Splits unaligned reads into aligned reads.
/// Args are provided as a struct to reduce stack pressure.
/// @return v0_ The number of bytes read, error code on error.
/// @return v1_ 0 if there is no error, non-zero on error
/// @return newPreimageOffset_ The new value for the preimage offset.
/// @return newMemRoot_ The new memory root.
function handleSysRead(SysReadParams memory _args)
internal
view
returns (
uint64 v0_,
uint64 v1_,
uint64 newPreimageOffset_,
bytes32 newMemRoot_,
bool memUpdated_,
uint64 memAddr_
)
{
unchecked {
v0_ = uint64(0);
v1_ = uint64(0);
newMemRoot_ = _args.memRoot;
newPreimageOffset_ = _args.preimageOffset;
memUpdated_ = false;
memAddr_ = 0;
// args: _a0 = fd, _a1 = addr, _a2 = count
// returns: v0_ = read, v1_ = err code
if (_args.a0 == FD_STDIN) {
// Leave v0_ and v1_ zero: read nothing, no error
}
// pre-image oracle read
else if (_args.a0 == FD_PREIMAGE_READ) {
uint64 effAddr = _args.a1 & arch.ADDRESS_MASK;
// verify proof is correct, and get the existing memory.
// mask the addr to align it to 4 bytes
uint64 mem = MIPS64Memory.readMem(_args.memRoot, effAddr, _args.proofOffset);
// If the preimage key is a local key, localize it in the context of the caller.
if (uint8(_args.preimageKey[0]) == 1) {
_args.preimageKey = PreimageKeyLib.localize(_args.preimageKey, _args.localContext);
}
(bytes32 dat, uint256 datLen) = _args.oracle.readPreimage(_args.preimageKey, _args.preimageOffset);
// Transform data for writing to memory
// We use assembly for more precise ops, and no var count limit
uint64 a1 = _args.a1;
uint64 a2 = _args.a2;
assembly {
let alignment := and(a1, EXT_MASK) // the read might not start at an aligned address
let space := sub(WORD_SIZE_BYTES, alignment) // remaining space in memory word
if lt(space, datLen) { datLen := space } // if less space than data, shorten data
if lt(a2, datLen) { datLen := a2 } // if requested to read less, read less
dat := shr(sub(256, mul(datLen, 8)), dat) // right-align data
// position data to insert into memory word
dat := shl(mul(sub(sub(WORD_SIZE_BYTES, datLen), alignment), 8), dat)
// mask all bytes after start
let mask := sub(shl(mul(sub(WORD_SIZE_BYTES, alignment), 8), 1), 1)
// mask of all bytes
let suffixMask := sub(shl(mul(sub(sub(WORD_SIZE_BYTES, alignment), datLen), 8), 1), 1)
// starting from end, maybe none
mask := and(mask, not(suffixMask)) // reduce mask to just cover the data we insert
mem := or(and(mem, not(mask)), dat) // clear masked part of original memory, and insert data
}
// Write memory back
newMemRoot_ = MIPS64Memory.writeMem(effAddr, _args.proofOffset, mem);
memUpdated_ = true;
memAddr_ = effAddr;
newPreimageOffset_ += uint64(datLen);
v0_ = uint64(datLen);
}
// hint response
else if (_args.a0 == FD_HINT_READ) {
// Don't read into memory, just say we read it all
// The result is ignored anyway
v0_ = _args.a2;
} else if (_args.a0 == FD_EVENTFD) {
// Always act in non blocking mode as if the counter has not been signalled
v0_ = EAGAIN;
v1_ = SYS_ERROR_SIGNAL;
} else {
v0_ = EBADF;
v1_ = SYS_ERROR_SIGNAL;
}
return (v0_, v1_, newPreimageOffset_, newMemRoot_, memUpdated_, memAddr_);
}
}
/// @notice Like a Linux write syscall. Splits unaligned writes into aligned writes.
/// @return v0_ The number of bytes written, or error code on error.
/// @return v1_ 0 if there is no error, non-zero on error
/// @return newPreimageKey_ The new preimageKey.
/// @return newPreimageOffset_ The new preimageOffset.
function handleSysWrite(SysWriteParams memory _args)
internal
pure
returns (uint64 v0_, uint64 v1_, bytes32 newPreimageKey_, uint64 newPreimageOffset_)
{
unchecked {
// args: _a0 = fd, _a1 = addr, _a2 = count
// returns: v0_ = written, v1_ = err code
v0_ = uint64(0);
v1_ = uint64(0);
newPreimageKey_ = _args._preimageKey;
newPreimageOffset_ = _args._preimageOffset;
if (_args._a0 == FD_STDOUT || _args._a0 == FD_STDERR || _args._a0 == FD_HINT_WRITE) {
v0_ = _args._a2; // tell program we have written everything
}
// pre-image oracle
else if (_args._a0 == FD_PREIMAGE_WRITE) {
// mask the addr to align it to 4 bytes
uint64 mem = MIPS64Memory.readMem(_args._memRoot, _args._a1 & arch.ADDRESS_MASK, _args._proofOffset);
bytes32 key = _args._preimageKey;
// Construct pre-image key from memory
// We use assembly for more precise ops, and no var count limit
uint64 _a1 = _args._a1;
uint64 _a2 = _args._a2;
assembly {
let alignment := and(_a1, EXT_MASK) // the read might not start at an aligned address
let space := sub(WORD_SIZE_BYTES, alignment) // remaining space in memory word
if lt(space, _a2) { _a2 := space } // if less space than data, shorten data
key := shl(mul(_a2, 8), key) // shift key, make space for new info
let mask := sub(shl(mul(_a2, 8), 1), 1) // mask for extracting value from memory
mem := and(shr(mul(sub(space, _a2), 8), mem), mask) // align value to right, mask it
key := or(key, mem) // insert into key
}
_args._a2 = _a2;
// Write pre-image key to oracle
newPreimageKey_ = key;
newPreimageOffset_ = 0; // reset offset, to read new pre-image data from the start
v0_ = _args._a2;
} else if (_args._a0 == FD_EVENTFD) {
// Always report that the write could not be completed
// This acts as if the counter has already reached the maximum value
v0_ = EAGAIN;
v1_ = SYS_ERROR_SIGNAL;
} else {
v0_ = EBADF;
v1_ = SYS_ERROR_SIGNAL;
}
return (v0_, v1_, newPreimageKey_, newPreimageOffset_);
}
}
/// @notice Like Linux fcntl (file control) syscall, but only supports minimal file-descriptor control commands, to
/// retrieve the file-descriptor R/W flags.
/// @param _a0 The file descriptor.
/// @param _a1 The control command.
/// @param v0_ The file status flag (only supported commands are F_GETFD and F_GETFL), or error code on error.
/// @param v1_ 0 if there is no error, non-zero on error
function handleSysFcntl(uint64 _a0, uint64 _a1) internal pure returns (uint64 v0_, uint64 v1_) {
unchecked {
v0_ = uint64(0);
v1_ = uint64(0);
// args: _a0 = fd, _a1 = cmd
if (_a1 == 1) {
// F_GETFD: get file descriptor flags
if (
_a0 == FD_STDIN || _a0 == FD_STDOUT || _a0 == FD_STDERR || _a0 == FD_PREIMAGE_READ
|| _a0 == FD_HINT_READ || _a0 == FD_PREIMAGE_WRITE || _a0 == FD_HINT_WRITE
) {
v0_ = 0; // No flags set
} else {
v0_ = EBADF;
v1_ = SYS_ERROR_SIGNAL;
}
} else if (_a1 == 3) {
// F_GETFL: get file status flags
if (_a0 == FD_STDIN || _a0 == FD_PREIMAGE_READ || _a0 == FD_HINT_READ) {
v0_ = 0; // O_RDONLY
} else if (_a0 == FD_STDOUT || _a0 == FD_STDERR || _a0 == FD_PREIMAGE_WRITE || _a0 == FD_HINT_WRITE) {
v0_ = 1; // O_WRONLY
} else {
v0_ = EBADF;
v1_ = SYS_ERROR_SIGNAL;
}
} else {
v0_ = EINVAL; // cmd not recognized by this kernel
v1_ = SYS_ERROR_SIGNAL;
}
return (v0_, v1_);
}
}
function handleSyscallUpdates(
st.CpuScalars memory _cpu,
uint64[32] memory _registers,
uint64 _v0,
uint64 _v1
)
internal
pure
{
unchecked {
// Write the results back to the state registers
_registers[REG_SYSCALL_RET1] = _v0;
_registers[REG_SYSCALL_ERRNO] = _v1;
// Update the PC and nextPC
_cpu.pc = _cpu.nextPC;
_cpu.nextPC = _cpu.nextPC + 4;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
using LibPosition for Position global;
/// @notice A `Position` represents a position of a claim within the game tree.
/// @dev This is represented as a "generalized index" where the high-order bit
/// is the level in the tree and the remaining bits is a unique bit pattern, allowing
/// a unique identifier for each node in the tree. Mathematically, it is calculated
/// as 2^{depth} + indexAtDepth.
type Position is uint128;
/// @title LibPosition
/// @notice This library contains helper functions for working with the `Position` type.
library LibPosition {
/// @notice the `MAX_POSITION_BITLEN` is the number of bits that the `Position` type, and the implementation of
/// its behavior within this library, can safely support.
uint8 internal constant MAX_POSITION_BITLEN = 126;
/// @notice Computes a generalized index (2^{depth} + indexAtDepth).
/// @param _depth The depth of the position.
/// @param _indexAtDepth The index at the depth of the position.
/// @return position_ The computed generalized index.
function wrap(uint8 _depth, uint128 _indexAtDepth) internal pure returns (Position position_) {
assembly {
// gindex = 2^{_depth} + _indexAtDepth
position_ := add(shl(_depth, 1), _indexAtDepth)
}
}
/// @notice Pulls the `depth` out of a `Position` type.
/// @param _position The generalized index to get the `depth` of.
/// @return depth_ The `depth` of the `position` gindex.
/// @custom:attribution Solady <https://github.com/Vectorized/Solady>
function depth(Position _position) internal pure returns (uint8 depth_) {
// Return the most significant bit offset, which signifies the depth of the gindex.
assembly {
depth_ := or(depth_, shl(6, lt(0xffffffffffffffff, shr(depth_, _position))))
depth_ := or(depth_, shl(5, lt(0xffffffff, shr(depth_, _position))))
// For the remaining 32 bits, use a De Bruijn lookup.
_position := shr(depth_, _position)
_position := or(_position, shr(1, _position))
_position := or(_position, shr(2, _position))
_position := or(_position, shr(4, _position))
_position := or(_position, shr(8, _position))
_position := or(_position, shr(16, _position))
depth_ :=
or(
depth_,
byte(
shr(251, mul(_position, shl(224, 0x07c4acdd))),
0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f
)
)
}
}
/// @notice Pulls the `indexAtDepth` out of a `Position` type.
/// The `indexAtDepth` is the left/right index of a position at a specific depth within
/// the binary tree, starting from index 0. For example, at gindex 2, the `depth` = 1
/// and the `indexAtDepth` = 0.
/// @param _position The generalized index to get the `indexAtDepth` of.
/// @return indexAtDepth_ The `indexAtDepth` of the `position` gindex.
function indexAtDepth(Position _position) internal pure returns (uint128 indexAtDepth_) {
// Return bits p_{msb-1}...p_{0}. This effectively pulls the 2^{depth} out of the gindex,
// leaving only the `indexAtDepth`.
uint256 msb = depth(_position);
assembly {
indexAtDepth_ := sub(_position, shl(msb, 1))
}
}
/// @notice Get the left child of `_position`.
/// @param _position The position to get the left position of.
/// @return left_ The position to the left of `position`.
function left(Position _position) internal pure returns (Position left_) {
assembly {
left_ := shl(1, _position)
}
}
/// @notice Get the right child of `_position`
/// @param _position The position to get the right position of.
/// @return right_ The position to the right of `position`.
function right(Position _position) internal pure returns (Position right_) {
assembly {
right_ := or(1, shl(1, _position))
}
}
/// @notice Get the parent position of `_position`.
/// @param _position The position to get the parent position of.
/// @return parent_ The parent position of `position`.
function parent(Position _position) internal pure returns (Position parent_) {
assembly {
parent_ := shr(1, _position)
}
}
/// @notice Get the deepest, right most gindex relative to the `position`. This is equivalent to
/// calling `right` on a position until the maximum depth is reached.
/// @param _position The position to get the relative deepest, right most gindex of.
/// @param _maxDepth The maximum depth of the game.
/// @return rightIndex_ The deepest, right most gindex relative to the `position`.
function rightIndex(Position _position, uint256 _maxDepth) internal pure returns (Position rightIndex_) {
uint256 msb = depth(_position);
assembly {
let remaining := sub(_maxDepth, msb)
rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1))
}
}
/// @notice Get the deepest, right most trace index relative to the `position`. This is
/// equivalent to calling `right` on a position until the maximum depth is reached and
/// then finding its index at depth.
/// @param _position The position to get the relative trace index of.
/// @param _maxDepth The maximum depth of the game.
/// @return traceIndex_ The trace index relative to the `position`.
function traceIndex(Position _position, uint256 _maxDepth) internal pure returns (uint256 traceIndex_) {
uint256 msb = depth(_position);
assembly {
let remaining := sub(_maxDepth, msb)
traceIndex_ := sub(or(shl(remaining, _position), sub(shl(remaining, 1), 1)), shl(_maxDepth, 1))
}
}
/// @notice Gets the position of the highest ancestor of `_position` that commits to the same
/// trace index.
/// @param _position The position to get the highest ancestor of.
/// @return ancestor_ The highest ancestor of `position` that commits to the same trace index.
function traceAncestor(Position _position) internal pure returns (Position ancestor_) {
// Create a field with only the lowest unset bit of `_position` set.
Position lsb;
assembly {
lsb := and(not(_position), add(_position, 1))
}
// Find the index of the lowest unset bit within the field.
uint256 msb = depth(lsb);
// The highest ancestor that commits to the same trace index is the original position
// shifted right by the index of the lowest unset bit.
assembly {
let a := shr(msb, _position)
// Bound the ancestor to the minimum gindex, 1.
ancestor_ := or(a, iszero(a))
}
}
/// @notice Gets the position of the highest ancestor of `_position` that commits to the same
/// trace index, while still being below `_upperBoundExclusive`.
/// @param _position The position to get the highest ancestor of.
/// @param _upperBoundExclusive The exclusive upper depth bound, used to inform where to stop in order
/// to not escape a sub-tree.
/// @return ancestor_ The highest ancestor of `position` that commits to the same trace index.
function traceAncestorBounded(
Position _position,
uint256 _upperBoundExclusive
)
internal
pure
returns (Position ancestor_)
{
// This function only works for positions that are below the upper bound.
if (_position.depth() <= _upperBoundExclusive) {
assembly {
// Revert with `ClaimAboveSplit()`
mstore(0x00, 0xb34b5c22)
revert(0x1C, 0x04)
}
}
// Grab the global trace ancestor.
ancestor_ = traceAncestor(_position);
// If the ancestor is above or at the upper bound, shift it to be below the upper bound.
// This should be a special case that only covers positions that commit to the final leaf
// in a sub-tree.
if (ancestor_.depth() <= _upperBoundExclusive) {
ancestor_ = ancestor_.rightIndex(_upperBoundExclusive + 1);
}
}
/// @notice Get the move position of `_position`, which is the left child of:
/// 1. `_position` if `_isAttack` is true.
/// 2. `_position | 1` if `_isAttack` is false.
/// @param _position The position to get the relative attack/defense position of.
/// @param _isAttack Whether or not the move is an attack move.
/// @return move_ The move position relative to `position`.
function move(Position _position, bool _isAttack) internal pure returns (Position move_) {
assembly {
move_ := shl(1, or(iszero(_isAttack), _position))
}
}
/// @notice Get the value of a `Position` type in the form of the underlying uint128.
/// @param _position The position to get the value of.
/// @return raw_ The value of the `position` as a uint128 type.
function raw(Position _position) internal pure returns (uint128 raw_) {
assembly {
raw_ := _position
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
// Libraries
import { Position } from "src/dispute/lib/LibPosition.sol";
using LibClaim for Claim global;
using LibHash for Hash global;
using LibDuration for Duration global;
using LibClock for Clock global;
using LibGameId for GameId global;
using LibTimestamp for Timestamp global;
using LibVMStatus for VMStatus global;
using LibGameType for GameType global;
/// @notice A `Clock` represents a packed `Duration` and `Timestamp`
/// @dev The packed layout of this type is as follows:
/// ┌────────────┬────────────────┐
/// │ Bits │ Value │
/// ├────────────┼────────────────┤
/// │ [0, 64) │ Duration │
/// │ [64, 128) │ Timestamp │
/// └────────────┴────────────────┘
type Clock is uint128;
/// @title LibClock
/// @notice This library contains helper functions for working with the `Clock` type.
library LibClock {
/// @notice Packs a `Duration` and `Timestamp` into a `Clock` type.
/// @param _duration The `Duration` to pack into the `Clock` type.
/// @param _timestamp The `Timestamp` to pack into the `Clock` type.
/// @return clock_ The `Clock` containing the `_duration` and `_timestamp`.
function wrap(Duration _duration, Timestamp _timestamp) internal pure returns (Clock clock_) {
assembly {
clock_ := or(shl(0x40, _duration), _timestamp)
}
}
/// @notice Pull the `Duration` out of a `Clock` type.
/// @param _clock The `Clock` type to pull the `Duration` out of.
/// @return duration_ The `Duration` pulled out of `_clock`.
function duration(Clock _clock) internal pure returns (Duration duration_) {
// Shift the high-order 64 bits into the low-order 64 bits, leaving only the `duration`.
assembly {
duration_ := shr(0x40, _clock)
}
}
/// @notice Pull the `Timestamp` out of a `Clock` type.
/// @param _clock The `Clock` type to pull the `Timestamp` out of.
/// @return timestamp_ The `Timestamp` pulled out of `_clock`.
function timestamp(Clock _clock) internal pure returns (Timestamp timestamp_) {
// Clean the high-order 192 bits by shifting the clock left and then right again, leaving
// only the `timestamp`.
assembly {
timestamp_ := shr(0xC0, shl(0xC0, _clock))
}
}
/// @notice Get the value of a `Clock` type in the form of the underlying uint128.
/// @param _clock The `Clock` type to get the value of.
/// @return clock_ The value of the `Clock` type as a uint128 type.
function raw(Clock _clock) internal pure returns (uint128 clock_) {
assembly {
clock_ := _clock
}
}
}
/// @notice A `GameId` represents a packed 4 byte game ID, a 8 byte timestamp, and a 20 byte address.
/// @dev The packed layout of this type is as follows:
/// ┌───────────┬───────────┐
/// │ Bits │ Value │
/// ├───────────┼───────────┤
/// │ [0, 32) │ Game Type │
/// │ [32, 96) │ Timestamp │
/// │ [96, 256) │ Address │
/// └───────────┴───────────┘
type GameId is bytes32;
/// @title LibGameId
/// @notice Utility functions for packing and unpacking GameIds.
library LibGameId {
/// @notice Packs values into a 32 byte GameId type.
/// @param _gameType The game type.
/// @param _timestamp The timestamp of the game's creation.
/// @param _gameProxy The game proxy address.
/// @return gameId_ The packed GameId.
function pack(
GameType _gameType,
Timestamp _timestamp,
address _gameProxy
)
internal
pure
returns (GameId gameId_)
{
assembly {
gameId_ := or(or(shl(224, _gameType), shl(160, _timestamp)), _gameProxy)
}
}
/// @notice Unpacks values from a 32 byte GameId type.
/// @param _gameId The packed GameId.
/// @return gameType_ The game type.
/// @return timestamp_ The timestamp of the game's creation.
/// @return gameProxy_ The game proxy address.
function unpack(GameId _gameId)
internal
pure
returns (GameType gameType_, Timestamp timestamp_, address gameProxy_)
{
assembly {
gameType_ := shr(224, _gameId)
timestamp_ := and(shr(160, _gameId), 0xFFFFFFFFFFFFFFFF)
gameProxy_ := and(_gameId, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
}
}
}
/// @notice A claim represents an MPT root representing the state of the fault proof program.
type Claim is bytes32;
/// @title LibClaim
/// @notice This library contains helper functions for working with the `Claim` type.
library LibClaim {
/// @notice Get the value of a `Claim` type in the form of the underlying bytes32.
/// @param _claim The `Claim` type to get the value of.
/// @return claim_ The value of the `Claim` type as a bytes32 type.
function raw(Claim _claim) internal pure returns (bytes32 claim_) {
assembly {
claim_ := _claim
}
}
/// @notice Hashes a claim and a position together.
/// @param _claim A Claim type.
/// @param _position The position of `claim`.
/// @param _challengeIndex The index of the claim being moved against.
/// @return claimHash_ A hash of abi.encodePacked(claim, position|challengeIndex);
function hashClaimPos(
Claim _claim,
Position _position,
uint256 _challengeIndex
)
internal
pure
returns (Hash claimHash_)
{
assembly {
mstore(0x00, _claim)
mstore(0x20, or(shl(128, _position), and(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _challengeIndex)))
claimHash_ := keccak256(0x00, 0x40)
}
}
}
/// @notice A dedicated duration type.
/// @dev Unit: seconds
type Duration is uint64;
/// @title LibDuration
/// @notice This library contains helper functions for working with the `Duration` type.
library LibDuration {
/// @notice Get the value of a `Duration` type in the form of the underlying uint64.
/// @param _duration The `Duration` type to get the value of.
/// @return duration_ The value of the `Duration` type as a uint64 type.
function raw(Duration _duration) internal pure returns (uint64 duration_) {
assembly {
duration_ := _duration
}
}
}
/// @notice A custom type for a generic hash.
type Hash is bytes32;
/// @title LibHash
/// @notice This library contains helper functions for working with the `Hash` type.
library LibHash {
/// @notice Get the value of a `Hash` type in the form of the underlying bytes32.
/// @param _hash The `Hash` type to get the value of.
/// @return hash_ The value of the `Hash` type as a bytes32 type.
function raw(Hash _hash) internal pure returns (bytes32 hash_) {
assembly {
hash_ := _hash
}
}
}
/// @notice A dedicated timestamp type.
type Timestamp is uint64;
/// @title LibTimestamp
/// @notice This library contains helper functions for working with the `Timestamp` type.
library LibTimestamp {
/// @notice Get the value of a `Timestamp` type in the form of the underlying uint64.
/// @param _timestamp The `Timestamp` type to get the value of.
/// @return timestamp_ The value of the `Timestamp` type as a uint64 type.
function raw(Timestamp _timestamp) internal pure returns (uint64 timestamp_) {
assembly {
timestamp_ := _timestamp
}
}
}
/// @notice A `VMStatus` represents the status of a VM execution.
type VMStatus is uint8;
/// @title LibVMStatus
/// @notice This library contains helper functions for working with the `VMStatus` type.
library LibVMStatus {
/// @notice Get the value of a `VMStatus` type in the form of the underlying uint8.
/// @param _vmstatus The `VMStatus` type to get the value of.
/// @return vmstatus_ The value of the `VMStatus` type as a uint8 type.
function raw(VMStatus _vmstatus) internal pure returns (uint8 vmstatus_) {
assembly {
vmstatus_ := _vmstatus
}
}
}
/// @notice A `GameType` represents the type of game being played.
type GameType is uint32;
/// @title LibGameType
/// @notice This library contains helper functions for working with the `GameType` type.
library LibGameType {
/// @notice Get the value of a `GameType` type in the form of the underlying uint32.
/// @param _gametype The `GameType` type to get the value of.
/// @return gametype_ The value of the `GameType` type as a uint32 type.
function raw(GameType _gametype) internal pure returns (uint32 gametype_) {
assembly {
gametype_ := _gametype
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
// Libraries
import {
Position,
Hash,
GameType,
VMStatus,
Timestamp,
Duration,
Clock,
GameId,
Claim,
LibGameId,
LibClock
} from "src/dispute/lib/LibUDT.sol";
/// @notice The current status of the dispute game.
enum GameStatus {
// The game is currently in progress, and has not been resolved.
IN_PROGRESS,
// The game has concluded, and the `rootClaim` was challenged successfully.
CHALLENGER_WINS,
// The game has concluded, and the `rootClaim` could not be contested.
DEFENDER_WINS
}
/// @notice The game's bond distribution type. Games are expected to start in the `UNDECIDED`
/// state, and then choose either `NORMAL` or `REFUND`.
enum BondDistributionMode {
// Bond distribution strategy has not been chosen.
UNDECIDED,
// Bonds should be distributed as normal.
NORMAL,
// Bonds should be refunded to claimants.
REFUND
}
/// @notice Represents an L2 root and the L2 sequence number at which it was generated.
/// @custom:field root The output root.
/// @custom:field l2SequenceNumber The L2 Sequence Number ( e.g. block number / timestamp) at which the root was
/// generated.
struct Proposal {
Hash root;
uint256 l2SequenceNumber;
}
/// @title GameTypes
/// @notice A library that defines the IDs of games that can be played.
library GameTypes {
/// @dev A dispute game type the uses the cannon vm.
GameType internal constant CANNON = GameType.wrap(0);
/// @dev A permissioned dispute game type that uses the cannon vm.
GameType internal constant PERMISSIONED_CANNON = GameType.wrap(1);
/// @notice A dispute game type that uses the asterisc vm.
GameType internal constant ASTERISC = GameType.wrap(2);
/// @notice A dispute game type that uses the asterisc vm with Kona.
GameType internal constant ASTERISC_KONA = GameType.wrap(3);
/// @notice A dispute game type that uses the cannon vm (Super Roots).
GameType internal constant SUPER_CANNON = GameType.wrap(4);
/// @notice A dispute game type that uses the permissioned cannon vm (Super Roots).
GameType internal constant SUPER_PERMISSIONED_CANNON = GameType.wrap(5);
/// @notice A dispute game type that uses OP Succinct
GameType internal constant OP_SUCCINCT = GameType.wrap(6);
/// @notice A dispute game type with short game duration for testing withdrawals.
/// Not intended for production use.
GameType internal constant FAST = GameType.wrap(254);
/// @notice A dispute game type that uses an alphabet vm.
/// Not intended for production use.
GameType internal constant ALPHABET = GameType.wrap(255);
/// @notice A dispute game type that uses RISC Zero's Kailua
GameType internal constant KAILUA = GameType.wrap(1337);
}
/// @title VMStatuses
/// @notice Named type aliases for the various valid VM status bytes.
library VMStatuses {
/// @notice The VM has executed successfully and the outcome is valid.
VMStatus internal constant VALID = VMStatus.wrap(0);
/// @notice The VM has executed successfully and the outcome is invalid.
VMStatus internal constant INVALID = VMStatus.wrap(1);
/// @notice The VM has paniced.
VMStatus internal constant PANIC = VMStatus.wrap(2);
/// @notice The VM execution is still in progress.
VMStatus internal constant UNFINISHED = VMStatus.wrap(3);
}
/// @title LocalPreimageKey
/// @notice Named type aliases for local `PreimageOracle` key identifiers.
library LocalPreimageKey {
/// @notice The identifier for the L1 head hash.
uint256 internal constant L1_HEAD_HASH = 0x01;
/// @notice The identifier for the starting output root.
uint256 internal constant STARTING_OUTPUT_ROOT = 0x02;
/// @notice The identifier for the disputed output root.
uint256 internal constant DISPUTED_OUTPUT_ROOT = 0x03;
/// @notice The identifier for the disputed L2 block number.
uint256 internal constant DISPUTED_L2_BLOCK_NUMBER = 0x04;
/// @notice The identifier for the chain ID.
uint256 internal constant CHAIN_ID = 0x05;
}{
"optimizer": {
"enabled": true,
"runs": 999999
},
"evmVersion": "london",
"metadata": {
"useLiteralContent": true,
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract ABI
API[{"inputs":[{"internalType":"contract IPreimageOracle","name":"_oracle","type":"address"},{"internalType":"uint256","name":"_stateVersion","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidExitedValue","type":"error"},{"inputs":[],"name":"InvalidMemoryProof","type":"error"},{"inputs":[],"name":"InvalidPC","type":"error"},{"inputs":[],"name":"InvalidRMWInstruction","type":"error"},{"inputs":[],"name":"InvalidSecondMemoryProof","type":"error"},{"inputs":[],"name":"UnsupportedStateVersion","type":"error"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IPreimageOracle","name":"oracle_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stateVersion","outputs":[{"internalType":"uint256","name":"stateVersion_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_stateData","type":"bytes"},{"internalType":"bytes","name":"_proof","type":"bytes"},{"internalType":"bytes32","name":"_localContext","type":"bytes32"}],"name":"step","outputs":[{"internalType":"bytes32","name":"postState_","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b50604051620056f8380380620056f883398101604081905262000034916200007d565b8060071415801562000047575080600814155b156200006657604051630fc5815160e11b815260040160405180910390fd5b6001600160a01b0390911660805260a052620000b9565b600080604083850312156200009157600080fd5b82516001600160a01b0381168114620000a957600080fd5b6020939093015192949293505050565b60805160a0516155f862000100600039600081816053015281816105ec015281816117e00152818161188d0152611efb01526000818160e9015261124501526155f86000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631219a4e41461005157806354fd4d50146100865780637dc0d1d0146100cf578063e14ced3214610113575b600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005b6040519081526020015b60405180910390f35b6100c26040518060400160405280600581526020017f312e382e3000000000000000000000000000000000000000000000000000000081525081565b60405161007d9190615361565b60405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260200161007d565b610073610121366004615416565b60006101308686868686610143565b905061013a610696565b95945050505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101c36152f7565b6000608083146101d257600080fd5b61026082146101e057600080fd5b604051610760146101f057600080fd5b608489146101fd57600080fd5b610164871461020b57600080fd5b508735608052602088013560a052604088013560c090811c81526048890135811c60e052605089013560f890811c6101005260518a0135821c6101205260598a0135821c6101405260618a0135811c6101605260628a0135811c61018081905260638b0135831c6101a052606b8b0135831c6101c05260738b013590911c6101e05260748a01356102005260948a01356102205260b48a013590911c610240526102b4816107e0565b826101000151156102d1576102c7610824565b935050505061013a565b7fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58361018001511480156103085750826101600151155b8061034457507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5836101a0015114801561034457508261016001515b156103d5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d49505336343a206163746976652074687265616420737461636b206973206560448201527f6d7074790000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6101208301805160010167ffffffffffffffff1690526103f482610944565b6103fe8383610a68565b8160400151156104195761041183610b0c565b6102c7610824565b620186a067ffffffffffffffff1683610140015167ffffffffffffffff161061044f576104468383610b97565b506102c7610824565b6101408301805160010167ffffffffffffffff16905260006102ae905060008060006104848660600151886000015186610d75565b9250925092508163ffffffff1660001480156104a657508063ffffffff16600c145b156104c2576104b489610dfb565b97505050505050505061013a565b63ffffffff8216603014806104dd575063ffffffff82166038145b156104ee576104b487878585612115565b63ffffffff821660341480610509575063ffffffff8216603c145b1561051a576104b487878585612115565b60006105a4876040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b604080516101008101825282815260e08a81015160208301528b5192820192909252610a2e606082015263ffffffff808816608083015286811660a0830152851660c08201527f000000000000000000000000000000000000000000000000000000000000000091810191909152909150600080610621836123ca565b918d52855167ffffffffffffffff9081166060808f01919091526020880151821660808f01526040880151821660a08f01528701511660c08d015292509050610668612989565b8115610678576106788b82612a46565b610680610824565b9b50505050505050505050505095945050505050565b604080516101e0808201835260008083526020830181905292820183905260608201839052608080830184905260a0830184905260c0830184905260e08301849052610100830184905261012083018490526101408301849052610160830184905261018083018490526101a083018490526101c0909201839052519091906107245781610180015161072b565b816101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb581036107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d49505336343a20706f73742d7374617465206163746976652074687265616460448201527f20737461636b20697320656d707479000000000000000000000000000000000060648201526084016103cc565b5050565b60018163ffffffff161115610821576040517f0136cc7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60408051608051815260a051602082015260d8519181019190915260f851604882015261011f5160508201526101385160518201526101585160598201526101605161017f5160618301526101805161019f5160628401526101b85160638401526101d851606b8401526101ff5160738401526102005160748401526102205160948401526102585160b4840152600060bc8085018281529194929361026093929183a06000935084600181146108de5760039450610906565b8180156108f657600181146108ff5760029550610904565b60009550610904565b600195505b505b505081900390207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f89190911b179150610940816107e0565b5090565b3661095361012a6101646154b9565b8110156109e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4d49505336343a20696e73756666696369656e742063616c6c6461746120666f60448201527f7220746872656164207769746e6573730000000000000000000000000000000060648201526084016103cc565b6101643560c090811c835261016c3560f890811c602085015261016d35901c604084015261016e35811c606084015261017635811c608084015261017e35811c60a084015261018635811c9083015260e082015161018e9060005b6020811015610a6157823560c01c8252600890920191602090910190600101610a3d565b5050505050565b6000610a7b610a75612a7e565b83612b31565b90506000836101600151610a9457836101800151610a9b565b836101a001515b9050818114610b06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d49505336343a20696e76616c696420746872656164207769746e657373000060448201526064016103cc565b50505050565b80610160015115610b2a57610b1f612a7e565b6101a0820152610b39565b610b32612a7e565b6101808201525b6000816101600151610b5057816101800151610b57565b816101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58103610b8b57610160820180511590525b50600061014090910152565b600082610160015115610c5b577fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5836101a0015103610c32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d49505336343a20656d7074792072696768742074687265616420737461636b60448201526064016103cc565b610c3a612a7e565b6101a0840152610180830151610c509083612b31565b610180840152610d0e565b7fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb583610180015103610ce9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d49505336343a20656d707479206c6566742074687265616420737461636b0060448201526064016103cc565b610cf1612a7e565b6101808401526101a0830151610d079083612b31565b6101a08401525b6000836101600151610d2557836101800151610d2c565b836101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58103610d645761016084018051159052600191505b506000610140909301929092525090565b600080806003861615610db4576040517f3f8200bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610dcb8667fffffffffffffff8891687612b73565b9050610ddb878260046000612bc5565b9350601a8463ffffffff16901c925083603f169150505b93509350939050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101829052610e7b6152f7565b608091506102609050600080600080610e978560e00151612c15565b935093509350935060008061139163ffffffff168667ffffffffffffffff1603610ee357610eca85858a60600151612c31565b67ffffffffffffffff1660608b0152909250905061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6c67ffffffffffffffff871601610f225765400000000000915061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec4167ffffffffffffffff8716016111795762050f0067ffffffffffffffff861614610f8c576001610100890152600260e0890152610f7e610824565b9a9950505050505050505050565b50506101c08601516000610f9e6152f7565b6101c089015167ffffffffffffffff9081168252600060208301819052604083018190526080808b018051841660608601525160040183169084015260a0808b015183169084015260c0808b0151909216918301919091525b602081101561104d578860e001518160208110611016576110166154d1565b60200201518260e001518260208110611031576110316154d1565b67ffffffffffffffff9092166020929092020152600101610ff7565b5060e0818101805167ffffffffffffffff8881166103a09092019190915281516000604091820181905292519093018290526101c08c018051600101821690528251608080820185528382526020808301859052828601859052606092830185905285518083018752838f015185168152918e015184169082015260a08d015183169481019490945260c08c0151909116908301529060e0808b015167ffffffffffffffff80881660408301528087169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808c01919091526020830151821660808c01526040830151821660a08c01528201511660c08a0152611157612989565b6111618a83612ce3565b611169610824565b9c9b505050505050505050505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebab67ffffffffffffffff8716016111cb57600161010089015260ff851660e08901526111c3612989565b610f7e610824565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7867ffffffffffffffff8716016112a557604080516101208101825267ffffffffffffffff8781168252868116602080840191909152868216838501528b01516060830152918a0151909116608082015260a081018b90527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1660c0820152610a2e60e082015288516101008201526112998982612d29565b909350915061200f9050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7767ffffffffffffffff87160161134d576040805160e08101825267ffffffffffffffff8781168252868116602080840191909152868216838501528b01516060830152918a01519091166080820152610a2e60a0820152885160c082015261132d81612d6f565b67ffffffffffffffff1660408d015260208c0152909350915061200f9050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3267ffffffffffffffff871601611392576113888585612f01565b909250905061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebc667ffffffffffffffff8716016113ce5750508451600061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3e67ffffffffffffffff871601611437576001604088015260ff8516602088015261141888613088565b1561142f57600161010089015260ff851660e08901525b6111c3612989565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebb667ffffffffffffffff8716016115585767fffffffffffffffc85167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8067ffffffffffffffff8616016114f85760006114af8261310b565b90508463ffffffff808316908216146114d657600b945067ffffffffffffffff93506114f1565b6114e08b8b613195565b9d9c50505050505050505050505050565b5050611552565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f67ffffffffffffffff861601611542576115338989613195565b9b9a5050505050505050505050565b6016925067ffffffffffffffff91505b5061200f565b67ffffffffffffffff861661139f148061157d575067ffffffffffffffff86166113aa145b1561158c57610f7e8888613195565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7667ffffffffffffffff8716016115d057506009905067ffffffffffffffff61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9a67ffffffffffffffff87160161176e5767ffffffffffffffff85161580611622575067ffffffffffffffff85166001145b1561175b5750600090508080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff8816016116825750506101208801516298968067ffffffffffffffff9091168181049190066064025b895167fffffffffffffff887169061169d9082610a2e6132ab565b6116d3576040517f8e77b2b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116e081610a2e856132b8565b8b526116ec8b82612a46565b8a516116fe90600883016111ae6132ab565b611734576040517f834c4cd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611744600882016111ae846132b8565b8b526117538b60088301612a46565b50505061200f565b506016905067ffffffffffffffff61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5267ffffffffffffffff8716016117aa5750600090508061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb3f67ffffffffffffffff871601611825576118047f0000000000000000000000000000000000000000000000000000000000000000613387565b6060015115611820576118188886866133da565b8a5290925090505b61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6d67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6e67ffffffffffffffff87160161191b576118b17f0000000000000000000000000000000000000000000000000000000000000000613387565b60400151611820576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebb467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5d67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6a67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebf767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb4f67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7567ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7367ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb8167ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec2167ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb7767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeba867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb6867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1267ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5e67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeba067ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9f67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9c67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7067ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5c67ffffffffffffffff871601611fad57611f1f7f0000000000000000000000000000000000000000000000000000000000000000613387565b51611f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b60808416600003611fa457506016905067ffffffffffffffff61200f565b6064915061200f565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b6000612099886040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b60e0808a015167ffffffffffffffff80871660408301528086169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808b01919091526020830151821660808b01526040830151821660a08b01528201511660c089015261210d612989565b611533610824565b60e08301516000908190601f601586901c1660208110612137576121376154d1565b60200201519050601f601085901c16600061215186613567565b830190506001600463ffffffff871660341480612174575063ffffffff8716603c145b1561218157506002905060085b885160009063ffffffff8916603014806121a1575063ffffffff89166034145b156121db576121b38c8685600161357e565b60ff851660808e015267ffffffffffffffff80871660a08f0152821660c08e015291506122de565b63ffffffff8916603814806121f6575063ffffffff8916603c145b156122ac578360ff168c6080015160ff1614801561222b57508067ffffffffffffffff168c60c0015167ffffffffffffffff16145b801561224e57508467ffffffffffffffff168c60a0015167ffffffffffffffff16145b156122a357600060808d0181905260a08d0181905260c08d015260008b60e001518763ffffffff1660208110612286576122866154d1565b602002015190506122998d8786846135be565b60019250506122de565b600091506122de565b6040517fecf79d0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123688c6040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b9050612382818d60e001518963ffffffff16866001613618565b805167ffffffffffffffff9081166060808f01919091526020830151821660808f01526040830151821660a08f01528201511660c08d01526123c2612989565b6114e0610824565b604081015160a0820151600090819063ffffffff16600214806123f757508360a0015163ffffffff166003145b1561245b57608084015160009060021b630ffffffc1661241c63f000000060206136fc565b86600001516020015116179050612455858660a0015163ffffffff1660021461244657601f612449565b60005b63ffffffff1683613776565b50612982565b60808401516020808601516000928392601f601083901c8116939260151c16908110612489576124896154d1565b6020020151925060008190508760a0015163ffffffff16602714806124b857508760a0015163ffffffff16601a145b806124cd57508760a0015163ffffffff16601b145b156125015787602001518267ffffffffffffffff16602081106124f2576124f26154d1565b6020020151925081905061263e565b60a088015163ffffffff16158061252257508760a0015163ffffffff16601c145b156125615787602001518267ffffffffffffffff1660208110612547576125476154d1565b60200201516080890151909350600b1c601f16905061263e565b60208860a0015163ffffffff1610156125d5578760a0015163ffffffff16600c148061259757508760a0015163ffffffff16600d145b806125ac57508760a0015163ffffffff16600e145b156125c157608088015161ffff16925061263e565b6125ce8860800151613567565b925061263e565b60288860a0015163ffffffff161015806125f957508760a0015163ffffffff166022145b8061260e57508760a0015163ffffffff166026145b1561263e5787602001518267ffffffffffffffff1660208110612633576126336154d1565b602002015192508190505b60048860a0015163ffffffff1610158015612663575060088860a0015163ffffffff16105b8061267857508760a0015163ffffffff166001145b156126a45761269b886000015189602001518a60a001518b608001518689613860565b50505050612982565b600067ffffffffffffffff9050600060208a60a0015163ffffffff161015806126d7575060a08a015163ffffffff16601a145b806126ec575060a08a015163ffffffff16601b145b15612754576126fe8a60800151613567565b86019550600067fffffffffffffff8871690506127248b60400151828d60600151612b73565b915060288b60a0015163ffffffff1610612752578a60a0015163ffffffff1660371461275257809250600093505b505b60006040518060e001604052808c6080015163ffffffff1681526020018c60a0015163ffffffff1681526020018c60c0015163ffffffff1681526020018867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018367ffffffffffffffff1681526020018c60e001518152509050600067ffffffffffffffff6127df83613ad3565b60a08e01519116915060209063ffffffff16158015612809575060088d60c0015163ffffffff1610155b801561282857508067ffffffffffffffff168d60c0015163ffffffff16105b15612938578c60c0015163ffffffff166008148061285057508c60c0015163ffffffff166009145b156128885761287a8d8e60c0015163ffffffff166008146128715787612874565b60005b8b613776565b505050505050505050612982565b8c60c0015163ffffffff16600a036128b9578c5160208e015161287a9190888c67ffffffffffffffff8d1615613618565b8c60c0015163ffffffff16600b036128eb578c5160208e015161287a9190888c67ffffffffffffffff8d161515613618565b60108d60c0015163ffffffff161015801561291957508067ffffffffffffffff168d60c0015163ffffffff16105b156129385761287a8d600001518e602001518f60c001518c8c8b61478d565b67ffffffffffffffff8581161461296257612958858e60600151846132b8565b9b5060019a508499505b6129788d600001518e6020015188856001613618565b5050505050505050505b9193909250565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810191909152612a0a6152f7565b50608090506102606000612a1f610a75612a7e565b905082610160015115612a39576101a08301819052505050565b6101808301819052505050565b60a082015167fffffffffffffff81667ffffffffffffffff8216036107dc5760006080830181905260a0830181905260c08301525050565b61028e3536612a9061012a602061552f565b612aa29063ffffffff166101646154b9565b811015610940576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4d49505336343a20696e73756666696369656e742063616c6c6461746120666f60448201527f7220746872656164207769746e6573730000000000000000000000000000000060648201526084016103cc565b600080612b3d83614d67565b60408051602081018790529081018290529091506060016040516020818303038152906040528051906020012091505092915050565b600080612b81858585614df0565b909250905080612bbd576040517f8e77b2b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600080600080612bd58887614ec8565b925092509250828267ffffffffffffffff168867ffffffffffffffff16901c1693508415612c0a57612c0784826136fc565b93505b505050949350505050565b6040810151608082015160a083015160c08401515b9193509193565b6000808284610fff811615612c4b57610fff811661100003015b8667ffffffffffffffff16600003612cd557849350908101906560000000000067ffffffffffffffff83161180612c9557508467ffffffffffffffff168267ffffffffffffffff16105b80612cb357508567ffffffffffffffff168167ffffffffffffffff16105b15612cd057506016925067ffffffffffffffff9150839050610df2565b612cd9565b8693505b5093509350939050565b81610160015115612d0857612cfd826101a0015182612b31565b6101a0830152610b8b565b612d1782610180015182612b31565b61018083015250600061014090910152565b600080600080612d3885614f4c565b918b5267ffffffffffffffff90921660408b0152929650909450925090508115612d6657612d668682612a46565b50509250929050565b6060810151608082015182516000928392909167ffffffffffffffff1660011480612da55750845167ffffffffffffffff166002145b80612dbb5750845167ffffffffffffffff166004145b15612dcc5784604001519350612c2a565b845167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa01612ea6576000612e218660c0015167fffffffffffffff88860200151168860a00151612b73565b60608701516020880151604089015192935090916007821660080381811015612e48578091505b67ffffffffffffffff821660408b018190529850600880830294851b600190951b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192909103029390931c9290921617925060009150612c2a9050565b845167ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c01612eec57600b935067ffffffffffffffff9250612c2a565b60099567ffffffffffffffff95509193509150565b60008067ffffffffffffffff8316600103612fc15767ffffffffffffffff84161580612f37575067ffffffffffffffff84166001145b80612f4c575067ffffffffffffffff84166002145b80612f61575067ffffffffffffffff84166005145b80612f76575067ffffffffffffffff84166003145b80612f8b575067ffffffffffffffff84166006145b80612fa0575067ffffffffffffffff84166004145b15612fae5760009150613081565b506009905067ffffffffffffffff613081565b8267ffffffffffffffff166003036130725767ffffffffffffffff84161580612ff4575067ffffffffffffffff84166005145b80613009575067ffffffffffffffff84166003145b156130175760009150613081565b67ffffffffffffffff84166001148061303a575067ffffffffffffffff84166002145b8061304f575067ffffffffffffffff84166006145b80613064575067ffffffffffffffff84166004145b15612fae5760019150613081565b506016905067ffffffffffffffff5b9250929050565b6000808261016001516130a057826101a001516130a7565b8261018001515b905060007fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb56130d4612a7e565b1490507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5821480156131035750805b949350505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290525060806000613103828560048461357e565b6000808080613222856040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b60e08087015167ffffffffffffffff80871660408301528086169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808801919091526020830151821660808801526040830151821660a08801528201511660c08601526132988686610b97565b506132a1610824565b9695505050505050565b600061013a848484614df0565b60006132c38361522a565b60078416156132f7576040517fe6c4247b000000000000000000000000000000000000000000000000000000008152600481fd5b6020830192601f851660180360031b83811b913567ffffffffffffffff90911b191617600585901c603b60005b8181101561337b5760208701963583821c600116801561334b576001811461336057613371565b60008681526020839052604090209550613371565b600082815260208790526040902095505b5050600101613324565b50919695505050505050565b604080516080810182526000808252602082018190529181018290526060810191909152600782106133c55760018082526020820181905260408201525b600882106133d557600160608201525b919050565b6000808067fffffffffffffff885168161340d6133fb61012a6101646154b9565b6134069060206154b9565b6107800190565b9050600061342089600001518484612b73565b905060006134908a610120015160008082679e3779b97f4a7c15019050601e8167ffffffffffffffff16901c811867bf58476d1ce4e5b9029050601b8167ffffffffffffffff16901c81186794d049bb133111eb029050601f8167ffffffffffffffff16901c8118915050919050565b9050600061349e858b615557565b905060006134ad826008615557565b90508967ffffffffffffffff80821690831610156134c85750805b600060016134d7836008615580565b67ffffffffffffffff166001901b6134ef91906155b0565b90506134fc826008615557565b613507906008615580565b67ffffffffffffffff91821691161b613521846008615580565b67ffffffffffffffff91821691161c80198616858216176135438989836132b8565b995061354f8f8a612a46565b50909d60009d50979b50969950505050505050505050565b600061357861ffff831660106136fc565b92915050565b600067fffffffffffffff884168161359d6133fb61012a6101646154b9565b905060006135b088600001518484612b73565b9050612c0787828888612bc5565b67fffffffffffffff8831660006135dc6133fb61012a6101646154b9565b905060006135ef87600001518484612b73565b905060006135ff878388886152bf565b905061360c8484836132b8565b90975250505050505050565b60208367ffffffffffffffff161061368c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d49505336343a2076616c69642072656769737465720000000000000000000060448201526064016103cc565b67ffffffffffffffff8316158015906136a25750805b156136d95781848467ffffffffffffffff16602081106136c4576136c46154d1565b67ffffffffffffffff90921660209290920201525b5050505060208101805167ffffffffffffffff8082169093526004019091169052565b6000600167ffffffffffffffff8481167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85810183169190911c83161515926040869003831681901b820192861692831b921b018261375c57600061375e565b815b90861667ffffffffffffffff16179250505092915050565b8251805160209091015167ffffffffffffffff908116600490920116146137f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d49505336343a206a756d7020696e2064656c617920736c6f7400000000000060448201526064016103cc565b8251805160208083015167ffffffffffffffff908116909352855184841691015290831615610b06578060080184602001518467ffffffffffffffff1660208110613846576138466154d1565b67ffffffffffffffff909216602092909202015250505050565b6000866000015160040167ffffffffffffffff16876020015167ffffffffffffffff16146138ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4d49505336343a206272616e636820696e2064656c617920736c6f740000000060448201526064016103cc565b8463ffffffff166004148061390557508463ffffffff166005145b15613990576000868467ffffffffffffffff1660208110613928576139286154d1565b602002015190508067ffffffffffffffff168367ffffffffffffffff1614801561395857508563ffffffff166004145b8061398857508067ffffffffffffffff168367ffffffffffffffff161415801561398857508563ffffffff166005145b915050613a6a565b8463ffffffff166006036139ad5760008260070b13159050613a6a565b8463ffffffff166007036139c95760008260070b139050613a6a565b8463ffffffff16600103613a6a57601f601085901c1660008190036139f25760008360070b1291505b8063ffffffff16601003613a2057875160080167ffffffffffffffff166103e08801526000600784900b1291505b8063ffffffff16600103613a395760008360070b121591505b8063ffffffff16601103613a6857875160080167ffffffffffffffff166103e08801526000600784900b121591505b505b8651602088015167ffffffffffffffff1688528115613ab3576002613a9461ffff871660106136fc565b67ffffffffffffffff90811690911b8201600401166020890152613ac9565b60208801805160040167ffffffffffffffff1690525b5050505050505050565b8051602082015160408301516060840151608085015160a086015160c087015160009695949392919063ffffffff86161580613b27575060088663ffffffff1610158015613b275750600f8663ffffffff16105b80613b3857508563ffffffff166018145b80613b4957508563ffffffff166019145b15614298578560088114613b9c5760098114613ba557600a8114613bae57600b8114613bb757600c8114613bc057600d8114613bc957600e8114613bd25760188114613bdb5760198114613be457613be9565b60209550613be9565b60219550613be9565b602a9550613be9565b602b9550613be9565b60249550613be9565b60259550613be9565b60269550613be9565b602c9550613be9565b602d95505b508463ffffffff16600003613c1d57601f600688901c16610f7e67ffffffffffffffff8516821b63ffffffff1660206136fc565b8463ffffffff16600203613c5257613c4563ffffffff8416601f60068a901c161c60206136fc565b9998505050505050505050565b8463ffffffff16600303613c8157601f600688901c16610f7e63ffffffff858116831c906020849003166136fc565b8463ffffffff16600403613cb057601f8416610f7e67ffffffffffffffff8516821b63ffffffff1660206136fc565b8463ffffffff16600603613cd457613c4563ffffffff8416601f86161c60206136fc565b8463ffffffff16600703613cfc57601f8416610f7e63ffffffff8516821c60208390036136fc565b8463ffffffff16600803613d17575091979650505050505050565b8463ffffffff16600903613d32575091979650505050505050565b8463ffffffff16600a03613d4d575091979650505050505050565b8463ffffffff16600b03613d68575091979650505050505050565b8463ffffffff16600c03613d83575091979650505050505050565b8463ffffffff16600f03613d9e575091979650505050505050565b8463ffffffff16601003613db9575091979650505050505050565b8463ffffffff16601103613dd4575091979650505050505050565b8463ffffffff16601203613def575091979650505050505050565b8463ffffffff16601303613e0a575091979650505050505050565b8463ffffffff16601403613e25575090979650505050505050565b8463ffffffff16601603613e40575090979650505050505050565b8463ffffffff16601703613e5b575090979650505050505050565b8463ffffffff16601803613e76575091979650505050505050565b8463ffffffff16601903613e91575091979650505050505050565b8463ffffffff16601a03613eac575091979650505050505050565b8463ffffffff16601b03613ec7575091979650505050505050565b8463ffffffff16601c03613ee2575091979650505050505050565b8463ffffffff16601d03613efd575091979650505050505050565b8463ffffffff16601e03613f18575091979650505050505050565b8463ffffffff16601f03613f33575091979650505050505050565b8463ffffffff16602003613f5457613c4583850163ffffffff1660206136fc565b8463ffffffff16602103613f7557613c4583850163ffffffff1660206136fc565b8463ffffffff16602203613f9657613c4583850363ffffffff1660206136fc565b8463ffffffff16602303613fb757613c4583850363ffffffff1660206136fc565b8463ffffffff16602403613fd15750501695945050505050565b8463ffffffff16602503613feb5750501795945050505050565b8463ffffffff166026036140055750501895945050505050565b8463ffffffff16602703614020575050171995945050505050565b8463ffffffff16602a03614055578260070b8460070b12614042576000614045565b60015b60ff169998505050505050505050565b8463ffffffff16602b03614085578267ffffffffffffffff168467ffffffffffffffff1610614042576000614045565b8463ffffffff16602c0361409f5750500195945050505050565b8463ffffffff16602d036140b95750500195945050505050565b8463ffffffff16602e036140d4575050900395945050505050565b8463ffffffff16602f036140ef575050900395945050505050565b8463ffffffff1660380361411f57505067ffffffffffffffff1660069490941c601f169390931b95945050505050565b8463ffffffff16603a0361414f57505067ffffffffffffffff1660069490941c601f169390931c95945050505050565b8463ffffffff16603b0361417857505060070b60069490941c601f169390931d95945050505050565b8463ffffffff16603c036141b85760068763ffffffff16901c601f1660200163ffffffff168367ffffffffffffffff16901b975050505050505050919050565b8463ffffffff16603e036141f85760068763ffffffff16901c601f1660200163ffffffff168367ffffffffffffffff16901c975050505050505050919050565b8463ffffffff16603f036142315760068763ffffffff16901c601f1660200163ffffffff168360070b901d975050505050505050919050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d49505336343a20696e76616c696420696e737472756374696f6e000000000060448201526064016103cc565b614231565b8563ffffffff16601c036143a2578463ffffffff166002036142c757613c4583850263ffffffff1660206136fc565b8463ffffffff16602014806142e257508463ffffffff166021145b15614332578463ffffffff166020036142f9579219925b60005b638000000085161561431f576801fffffffffffffffe600195861b1694016142fc565b63ffffffff169998505050505050505050565b61433b81613387565b60200151801561436157508463ffffffff166024148061436157508463ffffffff166025145b15614293578463ffffffff16602403614378579219925b60005b67800000000000000085161561431f576801fffffffffffffffe600195861b16940161437b565b8563ffffffff16600f036143c957613c4560108467ffffffffffffffff16901b60206136fc565b8563ffffffff166020036143e457613c458483600180612bc5565b8563ffffffff1660210361440057613c45848360026001612bc5565b8563ffffffff1660220361445157600061441e858460046000612bc5565b905063ffffffff80821660086003881602821690811b919081901b811690611169908219881681169084161760206136fc565b8563ffffffff1660230361446d57613c45848360046001612bc5565b8563ffffffff1660240361448957613c45848360016000612bc5565b8563ffffffff166025036144a557613c45848360026000612bc5565b8563ffffffff166026036145235760006144c3858460046000612bc5565b905063ffffffff80821660038781166008810260180367ffffffffffffffff1692831c939283901c92831989168517169103614504576114e08160206136fc565b67ffffffff00000000969096169095179b9a5050505050505050505050565b8563ffffffff1660280361453e57613c4584836001866152bf565b8563ffffffff1660290361455957613c4584836002866152bf565b8563ffffffff16602a036145ad575063ffffffff601860039490941b93841681811c67ffffffffffffffff9081166020968716909603811695861b199390931693909116901c1690911b1795945050505050565b8563ffffffff16602b036145c857613c4584836004866152bf565b8563ffffffff16602e036146285760006145e6858460046000612bc5565b905067ffffffffffffffff848116600860038816026018039182161b9063ffffffff90811681901b811690811984168116908316176114e088876004846152bf565b8563ffffffff16601a0361465d575067ffffffffffffffff90811660039390931b60381692831b921b19161795945050505050565b8563ffffffff16601b036146a1575067ffffffffffffffff90811660039390931b60389081169081900382169390931c60089390930181161b161795945050505050565b8563ffffffff166027036146de575067ffffffffffffffff908116602060039490941b8416909303169190911c63ffffffff169695505050505050565b8563ffffffff16602c03614718575067ffffffffffffffff91821660039390931b60381692831c9190921c19919091161795945050505050565b8563ffffffff16602d03614758575067ffffffffffffffff603860039490941b8416909303831683811b19919091169190921690911b1795945050505050565b8563ffffffff166037036147725750979650505050505050565b8563ffffffff16603f03614231575090979650505050505050565b60008463ffffffff166010036147a857506060860151614cff565b8463ffffffff166011036147cb5767ffffffffffffffff84166060880152614cff565b8463ffffffff166012036147e457506040860151614cff565b8463ffffffff166013036148075767ffffffffffffffff84166040880152614cff565b8463ffffffff166018036148705760008360030b8560030b02905061483b60208267ffffffffffffffff16901c60206136fc565b67ffffffffffffffff16606089015261485b63ffffffff821660206136fc565b67ffffffffffffffff16604089015250614cff565b8463ffffffff166019036148aa5760008363ffffffff168563ffffffff1602905061483b60208267ffffffffffffffff16901c60206136fc565b8463ffffffff16601a03614998578263ffffffff16600003614928576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b61494e8360030b8560030b8161494057614940615500565b0763ffffffff1660206136fc565b67ffffffffffffffff166060880152614984600384810b9086900b8161497657614976615500565b0563ffffffff1660206136fc565b67ffffffffffffffff166040880152614cff565b8463ffffffff16601b03614a7a578263ffffffff16600003614a16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b614a428363ffffffff168563ffffffff1681614a3457614a34615500565b0663ffffffff1660206136fc565b67ffffffffffffffff16606088015261498463ffffffff80851690861681614a6c57614a6c615500565b0463ffffffff1660206136fc565b8463ffffffff16601403614a9e575067ffffffffffffffff8216603f84161b614cff565b8463ffffffff16601603614ac2575067ffffffffffffffff8216603f84161c614cff565b8463ffffffff16601703614ae05750600782900b603f84161d614cff565b8463ffffffff16601c03614b1d5767ffffffffffffffff600785810b9085900b02600f81900b604090811d831660608b0152911690880152614cff565b8463ffffffff16601d03614b525767ffffffffffffffff84811681851602604081811c831660608b0152911690880152614cff565b8463ffffffff16601e03614c24578267ffffffffffffffff16600003614bd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b8260070b8460070b81614be957614be9615500565b0767ffffffffffffffff166060880152600783810b9085900b81614c0f57614c0f615500565b0567ffffffffffffffff166040880152614cff565b8463ffffffff16601f03614cff578267ffffffffffffffff16600003614ca6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b8267ffffffffffffffff168467ffffffffffffffff1681614cc957614cc9615500565b0667ffffffffffffffff908116606089015283811690851681614cee57614cee615500565b0467ffffffffffffffff1660408801525b67ffffffffffffffff821615614d415780868367ffffffffffffffff1660208110614d2c57614d2c6154d1565b67ffffffffffffffff90921660209290920201525b50505060208401805167ffffffffffffffff808216909652600401909416909352505050565b60405160188201518152603f8201516008820152605f82015160098201526078820151600a8201526098820151601282015260b8820151601a82015260d8820151602282015260e0820151600091602a8101835b6020811015614ddf5760188401518252602090930192600890910190600101614dbb565b506000815281900390209392505050565b600080614dfc8361522a565b6007841615614e30576040517fe6c4247b000000000000000000000000000000000000000000000000000000008152600481fd5b602083019235600585901c81603b60005b81811015614e985760208801973584821c6001168015614e685760018114614e7d57614e8e565b60008581526020839052604090209450614e8e565b600082815260208690526040902094505b5050600101614e41565b505087149250508115614ebf57601f851660180360031b81901c67ffffffffffffffff1692505b50935093915050565b600080806807fffffffffffffff8600385901b1681614ee8826040615557565b67ffffffffffffffff9081161c90506000614f04600188615557565b19881660071690506000614f19886008615557565b905088821660006003614f2c8385615557565b959c67ffffffffffffffff909616901b9a50949850929650505050505050565b610100810151608082015182516000928392918390819067ffffffffffffffff161561522157865167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0161518d57600067fffffffffffffff888602001511690506000614fcd896101000151838b60e00151612b73565b60608a015190915060001a60010361504f5761504989606001518a60a0015160408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b60608a01525b6000808a60c0015173ffffffffffffffffffffffffffffffffffffffff1663e03110e18c606001518d608001516040518363ffffffff1660e01b81526004016150ac92919091825267ffffffffffffffff16602082015260400190565b6040805180830381865afa1580156150c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150ec91906155c7565b60208d015160408e01519294509092509060078216600881900384811015615112578094505b508382101561511f578193505b8460088502610100031c9450846008828660080303021b9450600180600883600803021b036001806008878560080303021b03915081198116905085811988161796505050615173868e60e00151876132b8565b929b50505096890196955060019450919250615221915050565b865167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd016151cb5786604001519550615221565b865167ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c0161521157600b955067ffffffffffffffff9450615221565b6009955067ffffffffffffffff94505b91939550919395565b3661078082018110156107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4d49505336344d656d6f72793a20636865636b2074686174207468657265206960448201527f7320656e6f7567682063616c6c6461746100000000000000000000000000000060648201526084016103cc565b60008060006152ce8786614ec8565b5067ffffffffffffffff868316811691811691821b9216901b1987161792505050949350505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915260e0810161533d615342565b905290565b6040518061040001604052806020906020820280368337509192915050565b600060208083528351808285015260005b8181101561538e57858101830151858201604001528201615372565b818111156153a0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60008083601f8401126153e657600080fd5b50813567ffffffffffffffff8111156153fe57600080fd5b60208301915083602082850101111561308157600080fd5b60008060008060006060868803121561542e57600080fd5b853567ffffffffffffffff8082111561544657600080fd5b61545289838a016153d4565b9097509550602088013591508082111561546b57600080fd5b50615478888289016153d4565b96999598509660400135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156154cc576154cc61548a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600063ffffffff80831681851680830382111561554e5761554e61548a565b01949350505050565b600067ffffffffffffffff838116908316818110156155785761557861548a565b039392505050565b600067ffffffffffffffff808316818516818304811182151516156155a7576155a761548a565b02949350505050565b6000828210156155c2576155c261548a565b500390565b600080604083850312156155da57600080fd5b50508051602090910151909290915056fea164736f6c634300080f000a0000000000000000000000001fb8cdfc6831fc866ed9c51af8817da5c287add30000000000000000000000000000000000000000000000000000000000000007
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80631219a4e41461005157806354fd4d50146100865780637dc0d1d0146100cf578063e14ced3214610113575b600080fd5b7f00000000000000000000000000000000000000000000000000000000000000075b6040519081526020015b60405180910390f35b6100c26040518060400160405280600581526020017f312e382e3000000000000000000000000000000000000000000000000000000081525081565b60405161007d9190615361565b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001fb8cdfc6831fc866ed9c51af8817da5c287add316815260200161007d565b610073610121366004615416565b60006101308686868686610143565b905061013a610696565b95945050505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101c36152f7565b6000608083146101d257600080fd5b61026082146101e057600080fd5b604051610760146101f057600080fd5b608489146101fd57600080fd5b610164871461020b57600080fd5b508735608052602088013560a052604088013560c090811c81526048890135811c60e052605089013560f890811c6101005260518a0135821c6101205260598a0135821c6101405260618a0135811c6101605260628a0135811c61018081905260638b0135831c6101a052606b8b0135831c6101c05260738b013590911c6101e05260748a01356102005260948a01356102205260b48a013590911c610240526102b4816107e0565b826101000151156102d1576102c7610824565b935050505061013a565b7fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58361018001511480156103085750826101600151155b8061034457507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5836101a0015114801561034457508261016001515b156103d5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4d49505336343a206163746976652074687265616420737461636b206973206560448201527f6d7074790000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6101208301805160010167ffffffffffffffff1690526103f482610944565b6103fe8383610a68565b8160400151156104195761041183610b0c565b6102c7610824565b620186a067ffffffffffffffff1683610140015167ffffffffffffffff161061044f576104468383610b97565b506102c7610824565b6101408301805160010167ffffffffffffffff16905260006102ae905060008060006104848660600151886000015186610d75565b9250925092508163ffffffff1660001480156104a657508063ffffffff16600c145b156104c2576104b489610dfb565b97505050505050505061013a565b63ffffffff8216603014806104dd575063ffffffff82166038145b156104ee576104b487878585612115565b63ffffffff821660341480610509575063ffffffff8216603c145b1561051a576104b487878585612115565b60006105a4876040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b604080516101008101825282815260e08a81015160208301528b5192820192909252610a2e606082015263ffffffff808816608083015286811660a0830152851660c08201527f000000000000000000000000000000000000000000000000000000000000000791810191909152909150600080610621836123ca565b918d52855167ffffffffffffffff9081166060808f01919091526020880151821660808f01526040880151821660a08f01528701511660c08d015292509050610668612989565b8115610678576106788b82612a46565b610680610824565b9b50505050505050505050505095945050505050565b604080516101e0808201835260008083526020830181905292820183905260608201839052608080830184905260a0830184905260c0830184905260e08301849052610100830184905261012083018490526101408301849052610160830184905261018083018490526101a083018490526101c0909201839052519091906107245781610180015161072b565b816101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb581036107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4d49505336343a20706f73742d7374617465206163746976652074687265616460448201527f20737461636b20697320656d707479000000000000000000000000000000000060648201526084016103cc565b5050565b60018163ffffffff161115610821576040517f0136cc7600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b60408051608051815260a051602082015260d8519181019190915260f851604882015261011f5160508201526101385160518201526101585160598201526101605161017f5160618301526101805161019f5160628401526101b85160638401526101d851606b8401526101ff5160738401526102005160748401526102205160948401526102585160b4840152600060bc8085018281529194929361026093929183a06000935084600181146108de5760039450610906565b8180156108f657600181146108ff5760029550610904565b60009550610904565b600195505b505b505081900390207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660f89190911b179150610940816107e0565b5090565b3661095361012a6101646154b9565b8110156109e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4d49505336343a20696e73756666696369656e742063616c6c6461746120666f60448201527f7220746872656164207769746e6573730000000000000000000000000000000060648201526084016103cc565b6101643560c090811c835261016c3560f890811c602085015261016d35901c604084015261016e35811c606084015261017635811c608084015261017e35811c60a084015261018635811c9083015260e082015161018e9060005b6020811015610a6157823560c01c8252600890920191602090910190600101610a3d565b5050505050565b6000610a7b610a75612a7e565b83612b31565b90506000836101600151610a9457836101800151610a9b565b836101a001515b9050818114610b06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d49505336343a20696e76616c696420746872656164207769746e657373000060448201526064016103cc565b50505050565b80610160015115610b2a57610b1f612a7e565b6101a0820152610b39565b610b32612a7e565b6101808201525b6000816101600151610b5057816101800151610b57565b816101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58103610b8b57610160820180511590525b50600061014090910152565b600082610160015115610c5b577fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5836101a0015103610c32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d49505336343a20656d7074792072696768742074687265616420737461636b60448201526064016103cc565b610c3a612a7e565b6101a0840152610180830151610c509083612b31565b610180840152610d0e565b7fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb583610180015103610ce9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d49505336343a20656d707479206c6566742074687265616420737461636b0060448201526064016103cc565b610cf1612a7e565b6101808401526101a0830151610d079083612b31565b6101a08401525b6000836101600151610d2557836101800151610d2c565b836101a001515b90507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58103610d645761016084018051159052600191505b506000610140909301929092525090565b600080806003861615610db4576040517f3f8200bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610dcb8667fffffffffffffff8891687612b73565b9050610ddb878260046000612bc5565b9350601a8463ffffffff16901c925083603f169150505b93509350939050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101829052610e7b6152f7565b608091506102609050600080600080610e978560e00151612c15565b935093509350935060008061139163ffffffff168667ffffffffffffffff1603610ee357610eca85858a60600151612c31565b67ffffffffffffffff1660608b0152909250905061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6c67ffffffffffffffff871601610f225765400000000000915061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec4167ffffffffffffffff8716016111795762050f0067ffffffffffffffff861614610f8c576001610100890152600260e0890152610f7e610824565b9a9950505050505050505050565b50506101c08601516000610f9e6152f7565b6101c089015167ffffffffffffffff9081168252600060208301819052604083018190526080808b018051841660608601525160040183169084015260a0808b015183169084015260c0808b0151909216918301919091525b602081101561104d578860e001518160208110611016576110166154d1565b60200201518260e001518260208110611031576110316154d1565b67ffffffffffffffff9092166020929092020152600101610ff7565b5060e0818101805167ffffffffffffffff8881166103a09092019190915281516000604091820181905292519093018290526101c08c018051600101821690528251608080820185528382526020808301859052828601859052606092830185905285518083018752838f015185168152918e015184169082015260a08d015183169481019490945260c08c0151909116908301529060e0808b015167ffffffffffffffff80881660408301528087169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808c01919091526020830151821660808c01526040830151821660a08c01528201511660c08a0152611157612989565b6111618a83612ce3565b611169610824565b9c9b505050505050505050505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebab67ffffffffffffffff8716016111cb57600161010089015260ff851660e08901526111c3612989565b610f7e610824565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7867ffffffffffffffff8716016112a557604080516101208101825267ffffffffffffffff8781168252868116602080840191909152868216838501528b01516060830152918a0151909116608082015260a081018b90527f0000000000000000000000001fb8cdfc6831fc866ed9c51af8817da5c287add373ffffffffffffffffffffffffffffffffffffffff1660c0820152610a2e60e082015288516101008201526112998982612d29565b909350915061200f9050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7767ffffffffffffffff87160161134d576040805160e08101825267ffffffffffffffff8781168252868116602080840191909152868216838501528b01516060830152918a01519091166080820152610a2e60a0820152885160c082015261132d81612d6f565b67ffffffffffffffff1660408d015260208c0152909350915061200f9050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3267ffffffffffffffff871601611392576113888585612f01565b909250905061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebc667ffffffffffffffff8716016113ce5750508451600061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3e67ffffffffffffffff871601611437576001604088015260ff8516602088015261141888613088565b1561142f57600161010089015260ff851660e08901525b6111c3612989565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebb667ffffffffffffffff8716016115585767fffffffffffffffc85167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8067ffffffffffffffff8616016114f85760006114af8261310b565b90508463ffffffff808316908216146114d657600b945067ffffffffffffffff93506114f1565b6114e08b8b613195565b9d9c50505050505050505050505050565b5050611552565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f67ffffffffffffffff861601611542576115338989613195565b9b9a5050505050505050505050565b6016925067ffffffffffffffff91505b5061200f565b67ffffffffffffffff861661139f148061157d575067ffffffffffffffff86166113aa145b1561158c57610f7e8888613195565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7667ffffffffffffffff8716016115d057506009905067ffffffffffffffff61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9a67ffffffffffffffff87160161176e5767ffffffffffffffff85161580611622575067ffffffffffffffff85166001145b1561175b5750600090508080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff67ffffffffffffffff8816016116825750506101208801516298968067ffffffffffffffff9091168181049190066064025b895167fffffffffffffff887169061169d9082610a2e6132ab565b6116d3576040517f8e77b2b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116e081610a2e856132b8565b8b526116ec8b82612a46565b8a516116fe90600883016111ae6132ab565b611734576040517f834c4cd400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611744600882016111ae846132b8565b8b526117538b60088301612a46565b50505061200f565b506016905067ffffffffffffffff61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5267ffffffffffffffff8716016117aa5750600090508061200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb3f67ffffffffffffffff871601611825576118047f0000000000000000000000000000000000000000000000000000000000000007613387565b6060015115611820576118188886866133da565b8a5290925090505b61200f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6d67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6e67ffffffffffffffff87160161191b576118b17f0000000000000000000000000000000000000000000000000000000000000007613387565b60400151611820576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebb467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5d67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6a67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebf767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb4f67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7567ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7367ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb8167ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec2167ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb7767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec6967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeba867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb6867ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3b67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1267ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5e67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9767ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec5467ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeba067ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9f67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb9c67ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1967ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec7067ffffffffffffffff8716011561200f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb5c67ffffffffffffffff871601611fad57611f1f7f0000000000000000000000000000000000000000000000000000000000000007613387565b51611f86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b60808416600003611fa457506016905067ffffffffffffffff61200f565b6064915061200f565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4d49505336343a20756e696d706c656d656e7465642073797363616c6c00000060448201526064016103cc565b6000612099886040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b60e0808a015167ffffffffffffffff80871660408301528086169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808b01919091526020830151821660808b01526040830151821660a08b01528201511660c089015261210d612989565b611533610824565b60e08301516000908190601f601586901c1660208110612137576121376154d1565b60200201519050601f601085901c16600061215186613567565b830190506001600463ffffffff871660341480612174575063ffffffff8716603c145b1561218157506002905060085b885160009063ffffffff8916603014806121a1575063ffffffff89166034145b156121db576121b38c8685600161357e565b60ff851660808e015267ffffffffffffffff80871660a08f0152821660c08e015291506122de565b63ffffffff8916603814806121f6575063ffffffff8916603c145b156122ac578360ff168c6080015160ff1614801561222b57508067ffffffffffffffff168c60c0015167ffffffffffffffff16145b801561224e57508467ffffffffffffffff168c60a0015167ffffffffffffffff16145b156122a357600060808d0181905260a08d0181905260c08d015260008b60e001518763ffffffff1660208110612286576122866154d1565b602002015190506122998d8786846135be565b60019250506122de565b600091506122de565b6040517fecf79d0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123688c6040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b9050612382818d60e001518963ffffffff16866001613618565b805167ffffffffffffffff9081166060808f01919091526020830151821660808f01526040830151821660a08f01528201511660c08d01526123c2612989565b6114e0610824565b604081015160a0820151600090819063ffffffff16600214806123f757508360a0015163ffffffff166003145b1561245b57608084015160009060021b630ffffffc1661241c63f000000060206136fc565b86600001516020015116179050612455858660a0015163ffffffff1660021461244657601f612449565b60005b63ffffffff1683613776565b50612982565b60808401516020808601516000928392601f601083901c8116939260151c16908110612489576124896154d1565b6020020151925060008190508760a0015163ffffffff16602714806124b857508760a0015163ffffffff16601a145b806124cd57508760a0015163ffffffff16601b145b156125015787602001518267ffffffffffffffff16602081106124f2576124f26154d1565b6020020151925081905061263e565b60a088015163ffffffff16158061252257508760a0015163ffffffff16601c145b156125615787602001518267ffffffffffffffff1660208110612547576125476154d1565b60200201516080890151909350600b1c601f16905061263e565b60208860a0015163ffffffff1610156125d5578760a0015163ffffffff16600c148061259757508760a0015163ffffffff16600d145b806125ac57508760a0015163ffffffff16600e145b156125c157608088015161ffff16925061263e565b6125ce8860800151613567565b925061263e565b60288860a0015163ffffffff161015806125f957508760a0015163ffffffff166022145b8061260e57508760a0015163ffffffff166026145b1561263e5787602001518267ffffffffffffffff1660208110612633576126336154d1565b602002015192508190505b60048860a0015163ffffffff1610158015612663575060088860a0015163ffffffff16105b8061267857508760a0015163ffffffff166001145b156126a45761269b886000015189602001518a60a001518b608001518689613860565b50505050612982565b600067ffffffffffffffff9050600060208a60a0015163ffffffff161015806126d7575060a08a015163ffffffff16601a145b806126ec575060a08a015163ffffffff16601b145b15612754576126fe8a60800151613567565b86019550600067fffffffffffffff8871690506127248b60400151828d60600151612b73565b915060288b60a0015163ffffffff1610612752578a60a0015163ffffffff1660371461275257809250600093505b505b60006040518060e001604052808c6080015163ffffffff1681526020018c60a0015163ffffffff1681526020018c60c0015163ffffffff1681526020018867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018367ffffffffffffffff1681526020018c60e001518152509050600067ffffffffffffffff6127df83613ad3565b60a08e01519116915060209063ffffffff16158015612809575060088d60c0015163ffffffff1610155b801561282857508067ffffffffffffffff168d60c0015163ffffffff16105b15612938578c60c0015163ffffffff166008148061285057508c60c0015163ffffffff166009145b156128885761287a8d8e60c0015163ffffffff166008146128715787612874565b60005b8b613776565b505050505050505050612982565b8c60c0015163ffffffff16600a036128b9578c5160208e015161287a9190888c67ffffffffffffffff8d1615613618565b8c60c0015163ffffffff16600b036128eb578c5160208e015161287a9190888c67ffffffffffffffff8d161515613618565b60108d60c0015163ffffffff161015801561291957508067ffffffffffffffff168d60c0015163ffffffff16105b156129385761287a8d600001518e602001518f60c001518c8c8b61478d565b67ffffffffffffffff8581161461296257612958858e60600151846132b8565b9b5060019a508499505b6129788d600001518e6020015188856001613618565b5050505050505050505b9193909250565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810191909152612a0a6152f7565b50608090506102606000612a1f610a75612a7e565b905082610160015115612a39576101a08301819052505050565b6101808301819052505050565b60a082015167fffffffffffffff81667ffffffffffffffff8216036107dc5760006080830181905260a0830181905260c08301525050565b61028e3536612a9061012a602061552f565b612aa29063ffffffff166101646154b9565b811015610940576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4d49505336343a20696e73756666696369656e742063616c6c6461746120666f60448201527f7220746872656164207769746e6573730000000000000000000000000000000060648201526084016103cc565b600080612b3d83614d67565b60408051602081018790529081018290529091506060016040516020818303038152906040528051906020012091505092915050565b600080612b81858585614df0565b909250905080612bbd576040517f8e77b2b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600080600080612bd58887614ec8565b925092509250828267ffffffffffffffff168867ffffffffffffffff16901c1693508415612c0a57612c0784826136fc565b93505b505050949350505050565b6040810151608082015160a083015160c08401515b9193509193565b6000808284610fff811615612c4b57610fff811661100003015b8667ffffffffffffffff16600003612cd557849350908101906560000000000067ffffffffffffffff83161180612c9557508467ffffffffffffffff168267ffffffffffffffff16105b80612cb357508567ffffffffffffffff168167ffffffffffffffff16105b15612cd057506016925067ffffffffffffffff9150839050610df2565b612cd9565b8693505b5093509350939050565b81610160015115612d0857612cfd826101a0015182612b31565b6101a0830152610b8b565b612d1782610180015182612b31565b61018083015250600061014090910152565b600080600080612d3885614f4c565b918b5267ffffffffffffffff90921660408b0152929650909450925090508115612d6657612d668682612a46565b50509250929050565b6060810151608082015182516000928392909167ffffffffffffffff1660011480612da55750845167ffffffffffffffff166002145b80612dbb5750845167ffffffffffffffff166004145b15612dcc5784604001519350612c2a565b845167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa01612ea6576000612e218660c0015167fffffffffffffff88860200151168860a00151612b73565b60608701516020880151604089015192935090916007821660080381811015612e48578091505b67ffffffffffffffff821660408b018190529850600880830294851b600190951b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192909103029390931c9290921617925060009150612c2a9050565b845167ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c01612eec57600b935067ffffffffffffffff9250612c2a565b60099567ffffffffffffffff95509193509150565b60008067ffffffffffffffff8316600103612fc15767ffffffffffffffff84161580612f37575067ffffffffffffffff84166001145b80612f4c575067ffffffffffffffff84166002145b80612f61575067ffffffffffffffff84166005145b80612f76575067ffffffffffffffff84166003145b80612f8b575067ffffffffffffffff84166006145b80612fa0575067ffffffffffffffff84166004145b15612fae5760009150613081565b506009905067ffffffffffffffff613081565b8267ffffffffffffffff166003036130725767ffffffffffffffff84161580612ff4575067ffffffffffffffff84166005145b80613009575067ffffffffffffffff84166003145b156130175760009150613081565b67ffffffffffffffff84166001148061303a575067ffffffffffffffff84166002145b8061304f575067ffffffffffffffff84166006145b80613064575067ffffffffffffffff84166004145b15612fae5760019150613081565b506016905067ffffffffffffffff5b9250929050565b6000808261016001516130a057826101a001516130a7565b8261018001515b905060007fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb56130d4612a7e565b1490507fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5821480156131035750805b949350505050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290525060806000613103828560048461357e565b6000808080613222856040805160808101825260008082526020820181905291810182905260608101919091526040518060800160405280836060015167ffffffffffffffff168152602001836080015167ffffffffffffffff1681526020018360a0015167ffffffffffffffff1681526020018360c0015167ffffffffffffffff168152509050919050565b60e08087015167ffffffffffffffff80871660408301528086169190920152602082018051808316845260040190911690529050805167ffffffffffffffff9081166060808801919091526020830151821660808801526040830151821660a08801528201511660c08601526132988686610b97565b506132a1610824565b9695505050505050565b600061013a848484614df0565b60006132c38361522a565b60078416156132f7576040517fe6c4247b000000000000000000000000000000000000000000000000000000008152600481fd5b6020830192601f851660180360031b83811b913567ffffffffffffffff90911b191617600585901c603b60005b8181101561337b5760208701963583821c600116801561334b576001811461336057613371565b60008681526020839052604090209550613371565b600082815260208790526040902095505b5050600101613324565b50919695505050505050565b604080516080810182526000808252602082018190529181018290526060810191909152600782106133c55760018082526020820181905260408201525b600882106133d557600160608201525b919050565b6000808067fffffffffffffff885168161340d6133fb61012a6101646154b9565b6134069060206154b9565b6107800190565b9050600061342089600001518484612b73565b905060006134908a610120015160008082679e3779b97f4a7c15019050601e8167ffffffffffffffff16901c811867bf58476d1ce4e5b9029050601b8167ffffffffffffffff16901c81186794d049bb133111eb029050601f8167ffffffffffffffff16901c8118915050919050565b9050600061349e858b615557565b905060006134ad826008615557565b90508967ffffffffffffffff80821690831610156134c85750805b600060016134d7836008615580565b67ffffffffffffffff166001901b6134ef91906155b0565b90506134fc826008615557565b613507906008615580565b67ffffffffffffffff91821691161b613521846008615580565b67ffffffffffffffff91821691161c80198616858216176135438989836132b8565b995061354f8f8a612a46565b50909d60009d50979b50969950505050505050505050565b600061357861ffff831660106136fc565b92915050565b600067fffffffffffffff884168161359d6133fb61012a6101646154b9565b905060006135b088600001518484612b73565b9050612c0787828888612bc5565b67fffffffffffffff8831660006135dc6133fb61012a6101646154b9565b905060006135ef87600001518484612b73565b905060006135ff878388886152bf565b905061360c8484836132b8565b90975250505050505050565b60208367ffffffffffffffff161061368c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d49505336343a2076616c69642072656769737465720000000000000000000060448201526064016103cc565b67ffffffffffffffff8316158015906136a25750805b156136d95781848467ffffffffffffffff16602081106136c4576136c46154d1565b67ffffffffffffffff90921660209290920201525b5050505060208101805167ffffffffffffffff8082169093526004019091169052565b6000600167ffffffffffffffff8481167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85810183169190911c83161515926040869003831681901b820192861692831b921b018261375c57600061375e565b815b90861667ffffffffffffffff16179250505092915050565b8251805160209091015167ffffffffffffffff908116600490920116146137f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d49505336343a206a756d7020696e2064656c617920736c6f7400000000000060448201526064016103cc565b8251805160208083015167ffffffffffffffff908116909352855184841691015290831615610b06578060080184602001518467ffffffffffffffff1660208110613846576138466154d1565b67ffffffffffffffff909216602092909202015250505050565b6000866000015160040167ffffffffffffffff16876020015167ffffffffffffffff16146138ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4d49505336343a206272616e636820696e2064656c617920736c6f740000000060448201526064016103cc565b8463ffffffff166004148061390557508463ffffffff166005145b15613990576000868467ffffffffffffffff1660208110613928576139286154d1565b602002015190508067ffffffffffffffff168367ffffffffffffffff1614801561395857508563ffffffff166004145b8061398857508067ffffffffffffffff168367ffffffffffffffff161415801561398857508563ffffffff166005145b915050613a6a565b8463ffffffff166006036139ad5760008260070b13159050613a6a565b8463ffffffff166007036139c95760008260070b139050613a6a565b8463ffffffff16600103613a6a57601f601085901c1660008190036139f25760008360070b1291505b8063ffffffff16601003613a2057875160080167ffffffffffffffff166103e08801526000600784900b1291505b8063ffffffff16600103613a395760008360070b121591505b8063ffffffff16601103613a6857875160080167ffffffffffffffff166103e08801526000600784900b121591505b505b8651602088015167ffffffffffffffff1688528115613ab3576002613a9461ffff871660106136fc565b67ffffffffffffffff90811690911b8201600401166020890152613ac9565b60208801805160040167ffffffffffffffff1690525b5050505050505050565b8051602082015160408301516060840151608085015160a086015160c087015160009695949392919063ffffffff86161580613b27575060088663ffffffff1610158015613b275750600f8663ffffffff16105b80613b3857508563ffffffff166018145b80613b4957508563ffffffff166019145b15614298578560088114613b9c5760098114613ba557600a8114613bae57600b8114613bb757600c8114613bc057600d8114613bc957600e8114613bd25760188114613bdb5760198114613be457613be9565b60209550613be9565b60219550613be9565b602a9550613be9565b602b9550613be9565b60249550613be9565b60259550613be9565b60269550613be9565b602c9550613be9565b602d95505b508463ffffffff16600003613c1d57601f600688901c16610f7e67ffffffffffffffff8516821b63ffffffff1660206136fc565b8463ffffffff16600203613c5257613c4563ffffffff8416601f60068a901c161c60206136fc565b9998505050505050505050565b8463ffffffff16600303613c8157601f600688901c16610f7e63ffffffff858116831c906020849003166136fc565b8463ffffffff16600403613cb057601f8416610f7e67ffffffffffffffff8516821b63ffffffff1660206136fc565b8463ffffffff16600603613cd457613c4563ffffffff8416601f86161c60206136fc565b8463ffffffff16600703613cfc57601f8416610f7e63ffffffff8516821c60208390036136fc565b8463ffffffff16600803613d17575091979650505050505050565b8463ffffffff16600903613d32575091979650505050505050565b8463ffffffff16600a03613d4d575091979650505050505050565b8463ffffffff16600b03613d68575091979650505050505050565b8463ffffffff16600c03613d83575091979650505050505050565b8463ffffffff16600f03613d9e575091979650505050505050565b8463ffffffff16601003613db9575091979650505050505050565b8463ffffffff16601103613dd4575091979650505050505050565b8463ffffffff16601203613def575091979650505050505050565b8463ffffffff16601303613e0a575091979650505050505050565b8463ffffffff16601403613e25575090979650505050505050565b8463ffffffff16601603613e40575090979650505050505050565b8463ffffffff16601703613e5b575090979650505050505050565b8463ffffffff16601803613e76575091979650505050505050565b8463ffffffff16601903613e91575091979650505050505050565b8463ffffffff16601a03613eac575091979650505050505050565b8463ffffffff16601b03613ec7575091979650505050505050565b8463ffffffff16601c03613ee2575091979650505050505050565b8463ffffffff16601d03613efd575091979650505050505050565b8463ffffffff16601e03613f18575091979650505050505050565b8463ffffffff16601f03613f33575091979650505050505050565b8463ffffffff16602003613f5457613c4583850163ffffffff1660206136fc565b8463ffffffff16602103613f7557613c4583850163ffffffff1660206136fc565b8463ffffffff16602203613f9657613c4583850363ffffffff1660206136fc565b8463ffffffff16602303613fb757613c4583850363ffffffff1660206136fc565b8463ffffffff16602403613fd15750501695945050505050565b8463ffffffff16602503613feb5750501795945050505050565b8463ffffffff166026036140055750501895945050505050565b8463ffffffff16602703614020575050171995945050505050565b8463ffffffff16602a03614055578260070b8460070b12614042576000614045565b60015b60ff169998505050505050505050565b8463ffffffff16602b03614085578267ffffffffffffffff168467ffffffffffffffff1610614042576000614045565b8463ffffffff16602c0361409f5750500195945050505050565b8463ffffffff16602d036140b95750500195945050505050565b8463ffffffff16602e036140d4575050900395945050505050565b8463ffffffff16602f036140ef575050900395945050505050565b8463ffffffff1660380361411f57505067ffffffffffffffff1660069490941c601f169390931b95945050505050565b8463ffffffff16603a0361414f57505067ffffffffffffffff1660069490941c601f169390931c95945050505050565b8463ffffffff16603b0361417857505060070b60069490941c601f169390931d95945050505050565b8463ffffffff16603c036141b85760068763ffffffff16901c601f1660200163ffffffff168367ffffffffffffffff16901b975050505050505050919050565b8463ffffffff16603e036141f85760068763ffffffff16901c601f1660200163ffffffff168367ffffffffffffffff16901c975050505050505050919050565b8463ffffffff16603f036142315760068763ffffffff16901c601f1660200163ffffffff168360070b901d975050505050505050919050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d49505336343a20696e76616c696420696e737472756374696f6e000000000060448201526064016103cc565b614231565b8563ffffffff16601c036143a2578463ffffffff166002036142c757613c4583850263ffffffff1660206136fc565b8463ffffffff16602014806142e257508463ffffffff166021145b15614332578463ffffffff166020036142f9579219925b60005b638000000085161561431f576801fffffffffffffffe600195861b1694016142fc565b63ffffffff169998505050505050505050565b61433b81613387565b60200151801561436157508463ffffffff166024148061436157508463ffffffff166025145b15614293578463ffffffff16602403614378579219925b60005b67800000000000000085161561431f576801fffffffffffffffe600195861b16940161437b565b8563ffffffff16600f036143c957613c4560108467ffffffffffffffff16901b60206136fc565b8563ffffffff166020036143e457613c458483600180612bc5565b8563ffffffff1660210361440057613c45848360026001612bc5565b8563ffffffff1660220361445157600061441e858460046000612bc5565b905063ffffffff80821660086003881602821690811b919081901b811690611169908219881681169084161760206136fc565b8563ffffffff1660230361446d57613c45848360046001612bc5565b8563ffffffff1660240361448957613c45848360016000612bc5565b8563ffffffff166025036144a557613c45848360026000612bc5565b8563ffffffff166026036145235760006144c3858460046000612bc5565b905063ffffffff80821660038781166008810260180367ffffffffffffffff1692831c939283901c92831989168517169103614504576114e08160206136fc565b67ffffffff00000000969096169095179b9a5050505050505050505050565b8563ffffffff1660280361453e57613c4584836001866152bf565b8563ffffffff1660290361455957613c4584836002866152bf565b8563ffffffff16602a036145ad575063ffffffff601860039490941b93841681811c67ffffffffffffffff9081166020968716909603811695861b199390931693909116901c1690911b1795945050505050565b8563ffffffff16602b036145c857613c4584836004866152bf565b8563ffffffff16602e036146285760006145e6858460046000612bc5565b905067ffffffffffffffff848116600860038816026018039182161b9063ffffffff90811681901b811690811984168116908316176114e088876004846152bf565b8563ffffffff16601a0361465d575067ffffffffffffffff90811660039390931b60381692831b921b19161795945050505050565b8563ffffffff16601b036146a1575067ffffffffffffffff90811660039390931b60389081169081900382169390931c60089390930181161b161795945050505050565b8563ffffffff166027036146de575067ffffffffffffffff908116602060039490941b8416909303169190911c63ffffffff169695505050505050565b8563ffffffff16602c03614718575067ffffffffffffffff91821660039390931b60381692831c9190921c19919091161795945050505050565b8563ffffffff16602d03614758575067ffffffffffffffff603860039490941b8416909303831683811b19919091169190921690911b1795945050505050565b8563ffffffff166037036147725750979650505050505050565b8563ffffffff16603f03614231575090979650505050505050565b60008463ffffffff166010036147a857506060860151614cff565b8463ffffffff166011036147cb5767ffffffffffffffff84166060880152614cff565b8463ffffffff166012036147e457506040860151614cff565b8463ffffffff166013036148075767ffffffffffffffff84166040880152614cff565b8463ffffffff166018036148705760008360030b8560030b02905061483b60208267ffffffffffffffff16901c60206136fc565b67ffffffffffffffff16606089015261485b63ffffffff821660206136fc565b67ffffffffffffffff16604089015250614cff565b8463ffffffff166019036148aa5760008363ffffffff168563ffffffff1602905061483b60208267ffffffffffffffff16901c60206136fc565b8463ffffffff16601a03614998578263ffffffff16600003614928576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b61494e8360030b8560030b8161494057614940615500565b0763ffffffff1660206136fc565b67ffffffffffffffff166060880152614984600384810b9086900b8161497657614976615500565b0563ffffffff1660206136fc565b67ffffffffffffffff166040880152614cff565b8463ffffffff16601b03614a7a578263ffffffff16600003614a16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b614a428363ffffffff168563ffffffff1681614a3457614a34615500565b0663ffffffff1660206136fc565b67ffffffffffffffff16606088015261498463ffffffff80851690861681614a6c57614a6c615500565b0463ffffffff1660206136fc565b8463ffffffff16601403614a9e575067ffffffffffffffff8216603f84161b614cff565b8463ffffffff16601603614ac2575067ffffffffffffffff8216603f84161c614cff565b8463ffffffff16601703614ae05750600782900b603f84161d614cff565b8463ffffffff16601c03614b1d5767ffffffffffffffff600785810b9085900b02600f81900b604090811d831660608b0152911690880152614cff565b8463ffffffff16601d03614b525767ffffffffffffffff84811681851602604081811c831660608b0152911690880152614cff565b8463ffffffff16601e03614c24578267ffffffffffffffff16600003614bd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b8260070b8460070b81614be957614be9615500565b0767ffffffffffffffff166060880152600783810b9085900b81614c0f57614c0f615500565b0567ffffffffffffffff166040880152614cff565b8463ffffffff16601f03614cff578267ffffffffffffffff16600003614ca6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4d49505336343a206469766973696f6e206279207a65726f000000000000000060448201526064016103cc565b8267ffffffffffffffff168467ffffffffffffffff1681614cc957614cc9615500565b0667ffffffffffffffff908116606089015283811690851681614cee57614cee615500565b0467ffffffffffffffff1660408801525b67ffffffffffffffff821615614d415780868367ffffffffffffffff1660208110614d2c57614d2c6154d1565b67ffffffffffffffff90921660209290920201525b50505060208401805167ffffffffffffffff808216909652600401909416909352505050565b60405160188201518152603f8201516008820152605f82015160098201526078820151600a8201526098820151601282015260b8820151601a82015260d8820151602282015260e0820151600091602a8101835b6020811015614ddf5760188401518252602090930192600890910190600101614dbb565b506000815281900390209392505050565b600080614dfc8361522a565b6007841615614e30576040517fe6c4247b000000000000000000000000000000000000000000000000000000008152600481fd5b602083019235600585901c81603b60005b81811015614e985760208801973584821c6001168015614e685760018114614e7d57614e8e565b60008581526020839052604090209450614e8e565b600082815260208690526040902094505b5050600101614e41565b505087149250508115614ebf57601f851660180360031b81901c67ffffffffffffffff1692505b50935093915050565b600080806807fffffffffffffff8600385901b1681614ee8826040615557565b67ffffffffffffffff9081161c90506000614f04600188615557565b19881660071690506000614f19886008615557565b905088821660006003614f2c8385615557565b959c67ffffffffffffffff909616901b9a50949850929650505050505050565b610100810151608082015182516000928392918390819067ffffffffffffffff161561522157865167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0161518d57600067fffffffffffffff888602001511690506000614fcd896101000151838b60e00151612b73565b60608a015190915060001a60010361504f5761504989606001518a60a0015160408051600093845233602052918152606090922091527effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b60608a01525b6000808a60c0015173ffffffffffffffffffffffffffffffffffffffff1663e03110e18c606001518d608001516040518363ffffffff1660e01b81526004016150ac92919091825267ffffffffffffffff16602082015260400190565b6040805180830381865afa1580156150c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150ec91906155c7565b60208d015160408e01519294509092509060078216600881900384811015615112578094505b508382101561511f578193505b8460088502610100031c9450846008828660080303021b9450600180600883600803021b036001806008878560080303021b03915081198116905085811988161796505050615173868e60e00151876132b8565b929b50505096890196955060019450919250615221915050565b865167ffffffffffffffff167ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd016151cb5786604001519550615221565b865167ffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c0161521157600b955067ffffffffffffffff9450615221565b6009955067ffffffffffffffff94505b91939550919395565b3661078082018110156107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4d49505336344d656d6f72793a20636865636b2074686174207468657265206960448201527f7320656e6f7567682063616c6c6461746100000000000000000000000000000060648201526084016103cc565b60008060006152ce8786614ec8565b5067ffffffffffffffff868316811691811691821b9216901b1987161792505050949350505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915260e0810161533d615342565b905290565b6040518061040001604052806020906020820280368337509192915050565b600060208083528351808285015260005b8181101561538e57858101830151858201604001528201615372565b818111156153a0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60008083601f8401126153e657600080fd5b50813567ffffffffffffffff8111156153fe57600080fd5b60208301915083602082850101111561308157600080fd5b60008060008060006060868803121561542e57600080fd5b853567ffffffffffffffff8082111561544657600080fd5b61545289838a016153d4565b9097509550602088013591508082111561546b57600080fd5b50615478888289016153d4565b96999598509660400135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156154cc576154cc61548a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600063ffffffff80831681851680830382111561554e5761554e61548a565b01949350505050565b600067ffffffffffffffff838116908316818110156155785761557861548a565b039392505050565b600067ffffffffffffffff808316818516818304811182151516156155a7576155a761548a565b02949350505050565b6000828210156155c2576155c261548a565b500390565b600080604083850312156155da57600080fd5b50508051602090910151909290915056fea164736f6c634300080f000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001fb8cdfc6831fc866ed9c51af8817da5c287add30000000000000000000000000000000000000000000000000000000000000007
-----Decoded View---------------
Arg [0] : _oracle (address): 0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3
Arg [1] : _stateVersion (uint256): 7
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000001fb8cdfc6831fc866ed9c51af8817da5c287add3
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000007
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.