Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
628f5b90
Commit
628f5b90
authored
Sep 26, 2021
by
George Hotz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
factor into MIPSMemory, fix Tracer
parent
ec6d8872
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
178 additions
and
81 deletions
+178
-81
Challenge.sol
contracts/Challenge.sol
+7
-3
MIPS.sol
contracts/MIPS.sol
+12
-63
MIPSMemory.sol
contracts/MIPSMemory.sol
+62
-0
interpreter.go
minigeth/core/vm/interpreter.go
+13
-6
evm.sh
mipsevm/evm.sh
+2
-0
main.go
mipsevm/main.go
+82
-9
No files found.
contracts/Challenge.sol
View file @
628f5b90
...
...
@@ -5,6 +5,10 @@ import "./lib/Lib_RLPReader.sol";
interface IMIPS {
function Step(bytes32 stateHash) external view returns (bytes32);
function m() external pure returns (IMIPSMemory);
}
interface IMIPSMemory {
function ReadMemory(bytes32 stateHash, uint32 addr) external view returns (uint32);
function ReadBytes32(bytes32 stateHash, uint32 addr) external view returns (bytes32);
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
...
...
@@ -48,7 +52,7 @@ contract Challenge {
for (uint32 i = 0; i < 32; i += 4) {
uint256 tv = uint256(val>>(224-(i*8)));
stateHash = mips.WriteMemory(stateHash, addr+i, uint32(tv));
stateHash = mips.
m().
WriteMemory(stateHash, addr+i, uint32(tv));
}
return stateHash;
}
...
...
@@ -104,8 +108,8 @@ contract Challenge {
// confirm the finalSystemHash asserts the state you claim (in $t0-$t7) and the machine is stopped
// you must load these proofs into MIPS before calling this
// we disagree at the end
require(mips.ReadBytes32(finalSystemState, 0x30000800) == assertionRoot, "you are claiming a different state root in machine");
require(mips.ReadMemory(finalSystemState, 0xC0000080) == 0xDEAD0000, "machine is not stopped in final state (PC == 0xDEAD0000)");
require(mips.
m().
ReadBytes32(finalSystemState, 0x30000800) == assertionRoot, "you are claiming a different state root in machine");
require(mips.
m().
ReadMemory(finalSystemState, 0xC0000080) == 0xDEAD0000, "machine is not stopped in final state (PC == 0xDEAD0000)");
return newChallengeTrusted(startState, finalSystemState, stepCount);
}
...
...
contracts/MIPS.sol
View file @
628f5b90
...
...
@@ -10,74 +10,23 @@ pragma solidity ^0.7.3;
// If you are using the Preimage oracle, you call AddPreimage
// Then, you call Step. Step will revert if state is missing. If all state is present, it will return the next hash
contract MIPS {
// This state is global
mapping(bytes32 => mapping (uint32 => uint64)) public state;
mapping(bytes32 => bytes) public preimage;
function AddPreimage(bytes calldata anything) public {
preimage[keccak256(anything)] = anything;
}
interface IMIPSMemory {
function ReadMemory(bytes32 stateHash, uint32 addr) external view returns (uint32);
function ReadBytes32(bytes32 stateHash, uint32 addr) external view returns (bytes32);
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
}
function AddMerkleState(bytes32 stateHash, uint32 addr, uint32 value, string calldata proof) public {
// TODO: check proof
state[stateHash][addr] = (1 << 32) | value;
}
contract MIPS {
IMIPSMemory constant public m = IMIPSMemory(0x1338);
uint32 constant public REG_OFFSET = 0xc0000000;
uint32 constant public REG_PC = REG_OFFSET + 0x20*4;
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) public pure returns (bytes32) {
// TODO: does the stateHash mutation
require(addr & 3 == 0, "write memory must be 32-bit aligned");
}
// needed for preimage oracle
function ReadBytes32(bytes32 stateHash, uint32 addr) public view returns (bytes32) {
uint256 ret = 0;
for (uint32 i = 0; i < 32; i += 4) {
ret <<= 32;
ret |= uint256(ReadMemory(stateHash, addr+i));
}
return bytes32(ret);
}
function ReadMemory(bytes32 stateHash, uint32 addr) public view returns (uint32) {
require(addr & 3 == 0, "read memory must be 32-bit aligned");
// zero register is always 0
if (addr == REG_OFFSET) {
return 0;
}
// MMIO preimage oracle
if (addr >= 0x31000000 && addr < 0x32000000) {
bytes32 pihash = ReadBytes32(stateHash, 0x30001000);
if (addr == 0x31000000) {
return uint32(preimage[pihash].length);
}
uint offset = addr-0x31000004;
uint8 a0 = uint8(preimage[pihash][offset]);
uint8 a1 = uint8(preimage[pihash][offset+1]);
uint8 a2 = uint8(preimage[pihash][offset+2]);
uint8 a3 = uint8(preimage[pihash][offset+3]);
return (uint32(a0) << 24) |
(uint32(a1) << 16) |
(uint32(a2) << 8) |
(uint32(a3) << 0);
}
uint64 ret = state[stateHash][addr];
require((ret >> 32) == 1, "memory was not initialized");
return uint32(ret);
}
// compute the next state
// will revert if any required input state is missing
function Step(bytes32 stateHash) public view returns (bytes32) {
// instruction fetch
uint32 pc = ReadMemory(stateHash, REG_PC);
uint32 insn = ReadMemory(stateHash, pc);
uint32 pc =
m.
ReadMemory(stateHash, REG_PC);
uint32 insn =
m.
ReadMemory(stateHash, pc);
uint32 opcode = insn >> 26; // 6-bits
// decode
...
...
@@ -87,10 +36,10 @@ contract MIPS {
uint32 rt;
if (opcode != 2 && opcode != 3) { // J-type: j and jal have no register fetch
// R-type or I-type (stores rt)
rs = ReadMemory(stateHash, REG_OFFSET + ((insn >> 19) & 0x7C));
rs =
m.
ReadMemory(stateHash, REG_OFFSET + ((insn >> 19) & 0x7C));
if (opcode == 0) {
// R-type (stores rd)
rt = ReadMemory(stateHash, REG_OFFSET + ((insn >> 14) & 0x7C));
rt =
m.
ReadMemory(stateHash, REG_OFFSET + ((insn >> 14) & 0x7C));
}
}
...
...
@@ -100,7 +49,7 @@ contract MIPS {
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm]
uint32 SignExtImm = insn&0xFFFF | (insn&0x8000 != 0 ? 0xFFFF0000 : 0);
mem = ReadMemory(stateHash, (rs + SignExtImm) & 0xFFFFFFFC);
mem =
m.
ReadMemory(stateHash, (rs + SignExtImm) & 0xFFFFFFFC);
}
// execute
...
...
contracts/MIPSMemory.sol
0 → 100644
View file @
628f5b90
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.3;
contract MIPSMemory {
// This state is global
mapping(bytes32 => mapping (uint32 => uint64)) public state;
mapping(bytes32 => bytes) public preimage;
function AddPreimage(bytes calldata anything) public {
preimage[keccak256(anything)] = anything;
}
function AddMerkleState(bytes32 stateHash, uint32 addr, uint32 value, string calldata proof) public {
// TODO: check proof
state[stateHash][addr] = (1 << 32) | value;
}
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) public pure returns (bytes32) {
// TODO: does the stateHash mutation
require(addr & 3 == 0, "write memory must be 32-bit aligned");
}
// needed for preimage oracle
function ReadBytes32(bytes32 stateHash, uint32 addr) public view returns (bytes32) {
uint256 ret = 0;
for (uint32 i = 0; i < 32; i += 4) {
ret <<= 32;
ret |= uint256(ReadMemory(stateHash, addr+i));
}
return bytes32(ret);
}
function ReadMemory(bytes32 stateHash, uint32 addr) public view returns (uint32) {
require(addr & 3 == 0, "read memory must be 32-bit aligned");
// zero register is always 0
if (addr == 0xc0000000) {
return 0;
}
// MMIO preimage oracle
if (addr >= 0x31000000 && addr < 0x32000000) {
bytes32 pihash = ReadBytes32(stateHash, 0x30001000);
if (addr == 0x31000000) {
return uint32(preimage[pihash].length);
}
uint offset = addr-0x31000004;
uint8 a0 = uint8(preimage[pihash][offset]);
uint8 a1 = uint8(preimage[pihash][offset+1]);
uint8 a2 = uint8(preimage[pihash][offset+2]);
uint8 a3 = uint8(preimage[pihash][offset+3]);
return (uint32(a0) << 24) |
(uint32(a1) << 16) |
(uint32(a2) << 8) |
(uint32(a3) << 0);
}
uint64 ret = state[stateHash][addr];
require((ret >> 32) == 1, "memory was not initialized");
return uint32(ret);
}
}
\ No newline at end of file
minigeth/core/vm/interpreter.go
View file @
628f5b90
...
...
@@ -28,23 +28,30 @@ import (
)
// **** stub Tracer ****
type
Tracer
struct
{}
type
Tracer
interface
{
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
}
/*type StubTracer struct{}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func
(
jst
*
Tracer
)
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
func (jst *
Stub
Tracer) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
func
(
jst
*
Tracer
)
CaptureState
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
{
func (jst *
Stub
Tracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
}
// CaptureFault implements the Tracer interface to trace an execution fault
func
(
jst
*
Tracer
)
CaptureFault
(
env
*
EVM
,
pc
uint64
,
op
OpCode
,
gas
,
cost
uint64
,
scope
*
ScopeContext
,
depth
int
,
err
error
)
{
func (jst *
Stub
Tracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func
(
jst
*
Tracer
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
{
}
func (jst *
Stub
Tracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
}
*/
// Config are the configuration options for the Interpreter
type
Config
struct
{
...
...
mipsevm/evm.sh
0 → 100755
View file @
628f5b90
#!/bin/bash
(
cd
../
&&
npx hardhat compile
)
&&
go build
&&
./mipsevm
mipsevm/main.go
View file @
628f5b90
package
main
import
(
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
type
StateDB
struct
{
Bytecode
[]
byte
}
func
(
s
*
StateDB
)
AddAddressToAccessList
(
addr
common
.
Address
)
{}
...
...
@@ -27,7 +35,10 @@ func (b *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.
return
nil
}
func
(
s
*
StateDB
)
GetBalance
(
addr
common
.
Address
)
*
big
.
Int
{
return
common
.
Big0
}
func
(
s
*
StateDB
)
GetCode
(
addr
common
.
Address
)
[]
byte
{
return
[]
byte
{}
}
func
(
s
*
StateDB
)
GetCode
(
addr
common
.
Address
)
[]
byte
{
fmt
.
Println
(
"GetCode"
,
addr
)
return
s
.
Bytecode
}
func
(
s
*
StateDB
)
GetCodeHash
(
addr
common
.
Address
)
common
.
Hash
{
return
common
.
Hash
{}
}
func
(
s
*
StateDB
)
GetCodeSize
(
addr
common
.
Address
)
int
{
return
0
}
func
(
s
*
StateDB
)
GetCommittedState
(
addr
common
.
Address
,
hash
common
.
Hash
)
common
.
Hash
{
...
...
@@ -35,7 +46,10 @@ func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) commo
}
func
(
s
*
StateDB
)
GetNonce
(
addr
common
.
Address
)
uint64
{
return
0
}
func
(
s
*
StateDB
)
GetRefund
()
uint64
{
return
0
}
func
(
s
*
StateDB
)
GetState
(
addr
common
.
Address
,
hash
common
.
Hash
)
common
.
Hash
{
return
common
.
Hash
{}
}
func
(
s
*
StateDB
)
GetState
(
addr
common
.
Address
,
hash
common
.
Hash
)
common
.
Hash
{
fmt
.
Println
(
"GetState"
,
addr
,
hash
)
return
common
.
Hash
{}
}
func
(
s
*
StateDB
)
HasSuicided
(
addr
common
.
Address
)
bool
{
return
false
}
func
(
s
*
StateDB
)
PrepareAccessList
(
sender
common
.
Address
,
dst
*
common
.
Address
,
precompiles
[]
common
.
Address
,
list
types
.
AccessList
)
{
}
...
...
@@ -51,15 +65,74 @@ func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {}
func
(
s
*
StateDB
)
SubRefund
(
gas
uint64
)
{}
func
(
s
*
StateDB
)
Suicide
(
addr
common
.
Address
)
bool
{
return
true
}
// **** stub Tracer ****
type
Tracer
struct
{}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func
(
jst
*
Tracer
)
CaptureStart
(
env
*
vm
.
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
func
(
jst
*
Tracer
)
CaptureState
(
env
*
vm
.
EVM
,
pc
uint64
,
op
vm
.
OpCode
,
gas
,
cost
uint64
,
scope
*
vm
.
ScopeContext
,
rData
[]
byte
,
depth
int
,
err
error
)
{
fmt
.
Println
(
pc
,
op
,
gas
)
}
// CaptureFault implements the Tracer interface to trace an execution fault
func
(
jst
*
Tracer
)
CaptureFault
(
env
*
vm
.
EVM
,
pc
uint64
,
op
vm
.
OpCode
,
gas
,
cost
uint64
,
scope
*
vm
.
ScopeContext
,
depth
int
,
err
error
)
{
}
// CaptureEnd is called after the call finishes to finalize the tracing.
func
(
jst
*
Tracer
)
CaptureEnd
(
output
[]
byte
,
gasUsed
uint64
,
t
time
.
Duration
,
err
error
)
{
}
type
jsoncontract
struct
{
Bytecode
string
`json:"bytecode"`
DeployedBytecode
string
`json:"deployedBytecode"`
}
func
main
()
{
fmt
.
Println
(
"hello"
)
/*var parent types.Header
database := state.NewDatabase(parent)
statedb, _ := state.New(parent.Root, database, nil)*/
statedb
:=
&
StateDB
{}
var
jj
jsoncontract
mipsjson
,
_
:=
ioutil
.
ReadFile
(
"../artifacts/contracts/MIPS.sol/MIPS.json"
)
json
.
NewDecoder
(
bytes
.
NewReader
(
mipsjson
))
.
Decode
(
&
jj
)
bytecode
:=
common
.
Hex2Bytes
(
jj
.
DeployedBytecode
[
2
:
])
//fmt.Println(bytecode, jj.Bytecode)
bytecodehash
:=
crypto
.
Keccak256Hash
(
bytecode
)
statedb
:=
&
StateDB
{
Bytecode
:
bytecode
}
bc
:=
core
.
NewBlockChain
()
var
header
types
.
Header
header
.
Number
=
big
.
NewInt
(
13284469
)
header
.
Difficulty
=
common
.
Big0
author
:=
common
.
Address
{}
blockContext
:=
core
.
NewEVMBlockContext
(
&
header
,
bc
,
&
author
)
txContext
:=
vm
.
TxContext
{}
config
:=
vm
.
Config
{}
vm
:=
vm
.
NewEVM
(
vm
.
BlockContext
{},
vm
.
TxContext
{},
statedb
,
params
.
MainnetChainConfig
,
config
)
fmt
.
Println
(
vm
)
config
.
Debug
=
true
tracer
:=
Tracer
{}
config
.
Tracer
=
&
tracer
evm
:=
vm
.
NewEVM
(
blockContext
,
txContext
,
statedb
,
params
.
MainnetChainConfig
,
config
)
fmt
.
Println
(
evm
)
from
:=
common
.
Address
{}
to
:=
common
.
HexToAddress
(
"0x1337"
)
/*ret, gas, err := evm.Call(vm.AccountRef(from), to, []byte{}, 20000000, common.Big0)
fmt.Println(ret, gas, err)*/
interpreter
:=
vm
.
NewEVMInterpreter
(
evm
,
config
)
input
:=
[]
byte
{
0x69
,
0x37
,
0x33
,
0x72
}
// Step(bytes32)
input
=
append
(
input
,
common
.
Hash
{}
.
Bytes
()
...
)
contract
:=
vm
.
NewContract
(
vm
.
AccountRef
(
from
),
vm
.
AccountRef
(
to
),
common
.
Big0
,
20000000
)
//fmt.Println(bytecodehash, bytecode)
contract
.
SetCallCode
(
&
to
,
bytecodehash
,
bytecode
)
ret
,
err
:=
interpreter
.
Run
(
contract
,
input
,
false
)
fmt
.
Println
(
ret
,
err
,
contract
.
Gas
)
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment