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";
...
@@ -5,6 +5,10 @@ import "./lib/Lib_RLPReader.sol";
interface IMIPS {
interface IMIPS {
function Step(bytes32 stateHash) external view returns (bytes32);
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 ReadMemory(bytes32 stateHash, uint32 addr) external view returns (uint32);
function ReadBytes32(bytes32 stateHash, uint32 addr) external view returns (bytes32);
function ReadBytes32(bytes32 stateHash, uint32 addr) external view returns (bytes32);
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
...
@@ -48,7 +52,7 @@ contract Challenge {
...
@@ -48,7 +52,7 @@ contract Challenge {
for (uint32 i = 0; i < 32; i += 4) {
for (uint32 i = 0; i < 32; i += 4) {
uint256 tv = uint256(val>>(224-(i*8)));
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;
return stateHash;
}
}
...
@@ -104,8 +108,8 @@ contract Challenge {
...
@@ -104,8 +108,8 @@ contract Challenge {
// confirm the finalSystemHash asserts the state you claim (in $t0-$t7) and the machine is stopped
// 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
// you must load these proofs into MIPS before calling this
// we disagree at the end
// we disagree at the end
require(mips.ReadBytes32(finalSystemState, 0x30000800) == assertionRoot, "you are claiming a different state root in machine");
require(mips.
m().
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().
ReadMemory(finalSystemState, 0xC0000080) == 0xDEAD0000, "machine is not stopped in final state (PC == 0xDEAD0000)");
return newChallengeTrusted(startState, finalSystemState, stepCount);
return newChallengeTrusted(startState, finalSystemState, stepCount);
}
}
...
...
contracts/MIPS.sol
View file @
628f5b90
...
@@ -10,74 +10,23 @@ pragma solidity ^0.7.3;
...
@@ -10,74 +10,23 @@ pragma solidity ^0.7.3;
// If you are using the Preimage oracle, you call AddPreimage
// 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
// Then, you call Step. Step will revert if state is missing. If all state is present, it will return the next hash
contract MIPS {
interface IMIPSMemory {
// This state is global
function ReadMemory(bytes32 stateHash, uint32 addr) external view returns (uint32);
mapping(bytes32 => mapping (uint32 => uint64)) public state;
function ReadBytes32(bytes32 stateHash, uint32 addr) external view returns (bytes32);
mapping(bytes32 => bytes) public preimage;
function WriteMemory(bytes32 stateHash, uint32 addr, uint32 val) external pure returns (bytes32);
}
function AddPreimage(bytes calldata anything) public {
preimage[keccak256(anything)] = anything;
}
function AddMerkleState(bytes32 stateHash, uint32 addr, uint32 value, string calldata proof) public {
contract MIPS {
// TODO: check proof
IMIPSMemory constant public m = IMIPSMemory(0x1338);
state[stateHash][addr] = (1 << 32) | value;
}
uint32 constant public REG_OFFSET = 0xc0000000;
uint32 constant public REG_OFFSET = 0xc0000000;
uint32 constant public REG_PC = REG_OFFSET + 0x20*4;
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
// will revert if any required input state is missing
function Step(bytes32 stateHash) public view returns (bytes32) {
function Step(bytes32 stateHash) public view returns (bytes32) {
// instruction fetch
// instruction fetch
uint32 pc = ReadMemory(stateHash, REG_PC);
uint32 pc =
m.
ReadMemory(stateHash, REG_PC);
uint32 insn = ReadMemory(stateHash, pc);
uint32 insn =
m.
ReadMemory(stateHash, pc);
uint32 opcode = insn >> 26; // 6-bits
uint32 opcode = insn >> 26; // 6-bits
// decode
// decode
...
@@ -87,10 +36,10 @@ contract MIPS {
...
@@ -87,10 +36,10 @@ contract MIPS {
uint32 rt;
uint32 rt;
if (opcode != 2 && opcode != 3) { // J-type: j and jal have no register fetch
if (opcode != 2 && opcode != 3) { // J-type: j and jal have no register fetch
// R-type or I-type (stores rt)
// 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) {
if (opcode == 0) {
// R-type (stores rd)
// 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 {
...
@@ -100,7 +49,7 @@ contract MIPS {
if (opcode >= 0x20) {
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm]
// M[R[rs]+SignExtImm]
uint32 SignExtImm = insn&0xFFFF | (insn&0x8000 != 0 ? 0xFFFF0000 : 0);
uint32 SignExtImm = insn&0xFFFF | (insn&0x8000 != 0 ? 0xFFFF0000 : 0);
mem = ReadMemory(stateHash, (rs + SignExtImm) & 0xFFFFFFFC);
mem =
m.
ReadMemory(stateHash, (rs + SignExtImm) & 0xFFFFFFFC);
}
}
// execute
// 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 (
...
@@ -28,23 +28,30 @@ import (
)
)
// **** stub Tracer ****
// **** 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.
// 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.
// 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
// 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.
// 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
// Config are the configuration options for the Interpreter
type
Config
struct
{
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
package
main
import
(
import
(
"bytes"
"encoding/json"
"fmt"
"fmt"
"io/ioutil"
"log"
"math/big"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"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/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
)
)
type
StateDB
struct
{
type
StateDB
struct
{
Bytecode
[]
byte
}
}
func
(
s
*
StateDB
)
AddAddressToAccessList
(
addr
common
.
Address
)
{}
func
(
s
*
StateDB
)
AddAddressToAccessList
(
addr
common
.
Address
)
{}
...
@@ -27,7 +35,10 @@ func (b *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.
...
@@ -27,7 +35,10 @@ func (b *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.
return
nil
return
nil
}
}
func
(
s
*
StateDB
)
GetBalance
(
addr
common
.
Address
)
*
big
.
Int
{
return
common
.
Big0
}
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
)
GetCodeHash
(
addr
common
.
Address
)
common
.
Hash
{
return
common
.
Hash
{}
}
func
(
s
*
StateDB
)
GetCodeSize
(
addr
common
.
Address
)
int
{
return
0
}
func
(
s
*
StateDB
)
GetCodeSize
(
addr
common
.
Address
)
int
{
return
0
}
func
(
s
*
StateDB
)
GetCommittedState
(
addr
common
.
Address
,
hash
common
.
Hash
)
common
.
Hash
{
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
...
@@ -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
)
GetNonce
(
addr
common
.
Address
)
uint64
{
return
0
}
func
(
s
*
StateDB
)
GetRefund
()
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
)
HasSuicided
(
addr
common
.
Address
)
bool
{
return
false
}
func
(
s
*
StateDB
)
PrepareAccessList
(
sender
common
.
Address
,
dst
*
common
.
Address
,
precompiles
[]
common
.
Address
,
list
types
.
AccessList
)
{
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) {}
...
@@ -51,15 +65,74 @@ func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {}
func
(
s
*
StateDB
)
SubRefund
(
gas
uint64
)
{}
func
(
s
*
StateDB
)
SubRefund
(
gas
uint64
)
{}
func
(
s
*
StateDB
)
Suicide
(
addr
common
.
Address
)
bool
{
return
true
}
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
()
{
func
main
()
{
fmt
.
Println
(
"hello"
)
fmt
.
Println
(
"hello"
)
/*var parent types.Header
/*var parent types.Header
database := state.NewDatabase(parent)
database := state.NewDatabase(parent)
statedb, _ := state.New(parent.Root, database, nil)*/
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
{}
config
:=
vm
.
Config
{}
vm
:=
vm
.
NewEVM
(
vm
.
BlockContext
{},
vm
.
TxContext
{},
statedb
,
params
.
MainnetChainConfig
,
config
)
config
.
Debug
=
true
fmt
.
Println
(
vm
)
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