Commit 3d1052d0 authored by protolambda's avatar protolambda

mipsevm: refactor evm setup and contracts loading

parent 1e7439e5
package main package main
import ( import (
"bytes" "encoding/binary"
"encoding/json" "encoding/json"
"io/ioutil" "fmt"
"math/big" "math/big"
"time" "os"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"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/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
var ministart time.Time func LoadContracts() (*Contracts, error) {
mips, err := LoadContract("MIPS")
type jsoncontract struct { if err != nil {
Bytecode string `json:"bytecode"` return nil, err
DeployedBytecode string `json:"deployedBytecode"` }
mipsMem, err := LoadContract("MIPSMemory")
if err != nil {
return nil, err
}
challenge, err := LoadContract("Challenge")
if err != nil {
return nil, err
}
return &Contracts{
MIPS: mips,
MIPSMemory: mipsMem,
Challenge: challenge,
}, nil
} }
func GetBytecode(deployed bool) []byte { func LoadContract(name string) (*Contract, error) {
var jj jsoncontract // TODO change to forge build output
mipsjson, err := ioutil.ReadFile("../artifacts/contracts/MIPS.sol/MIPS.json") dat, err := os.ReadFile(fmt.Sprintf("../artifacts/contracts/%s.sol/%s.json", name, name))
check(err) if err != nil {
json.NewDecoder(bytes.NewReader(mipsjson)).Decode(&jj) return nil, fmt.Errorf("failed to read contract JSON definition of %q: %w", name, err)
if deployed { }
return common.Hex2Bytes(jj.DeployedBytecode[2:]) var out Contract
} else { if err := json.Unmarshal(dat, &out); err != nil {
return common.Hex2Bytes(jj.Bytecode[2:]) return nil, fmt.Errorf("failed to parse contract JSON definition of %q: %w", name, err)
} }
return &out, nil
} }
func GetInterpreter(ldebug int, realState bool, root string) (*vm.EVMInterpreter, *StateDB) { type Contract struct {
statedb := NewStateDB(ldebug, realState, root) DeployedBytecode struct {
Object hexutil.Bytes `json:"object"`
var header types.Header } `json:"deployedBytecode"`
header.Number = big.NewInt(13284469) // ignore abi,bytecode,etc.
header.Difficulty = common.Big0 }
bc := core.NewBlockChain(&header)
author := common.Address{}
blockContext := core.NewEVMBlockContext(&header, bc, &author)
txContext := vm.TxContext{}
config := vm.Config{}
evm := vm.NewEVM(blockContext, txContext, statedb, params.MainnetChainConfig, config) type Contracts struct {
MIPS *Contract
MIPSMemory *Contract
Challenge *Contract
}
interpreter := vm.NewEVMInterpreter(evm, config) type Addresses struct {
return interpreter, statedb MIPS common.Address
MIPSMemory common.Address
Challenge common.Address
} }
func RunWithRam(lram map[uint32](uint32), steps int, debug int, root string, lcallback func(int, map[uint32](uint32))) (uint64, error) { func NewEVMEnv(contracts *Contracts, addrs *Addresses) *vm.EVM {
interpreter, statedb := GetInterpreter(debug, false, root) chainCfg := params.MainnetChainConfig
statedb.Ram = lram bc := &testChain{}
header := bc.GetHeader(common.Hash{}, 100)
db := rawdb.NewMemoryDatabase()
statedb := state.NewDatabase(db)
state, err := state.New(types.EmptyRootHash, statedb, nil)
if err != nil {
panic(fmt.Errorf("failed to create memory state db: %w", err))
}
blockContext := core.NewEVMBlockContext(header, bc, nil)
vmCfg := vm.Config{}
env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg)
// pre-deploy the contracts
callback = lcallback env.StateDB.SetCode(addrs.MIPS, contracts.MIPS.DeployedBytecode.Object)
env.StateDB.SetCode(addrs.MIPSMemory, contracts.MIPSMemory.DeployedBytecode.Object)
env.StateDB.SetCode(addrs.Challenge, contracts.Challenge.DeployedBytecode.Object)
// TODO: any state to set, or immutables to replace, to link the contracts together?
return env
}
gas := 100000 * uint64(steps) type testChain struct {
}
// 0xdb7df598 func (d *testChain) Engine() consensus.Engine {
from := common.Address{} return ethash.NewFullFaker()
to := common.HexToAddress("0x1337") }
bytecode := GetBytecode(true)
statedb.Bytecodes[to] = bytecode
func (d *testChain) GetHeader(h common.Hash, n uint64) *types.Header {
parentHash := common.Hash{0: 0xff}
binary.BigEndian.PutUint64(parentHash[1:], n-1)
return &types.Header{
ParentHash: parentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: common.Hash{},
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
Bloom: types.Bloom{},
Difficulty: big.NewInt(0),
Number: new(big.Int).SetUint64(n),
GasLimit: 30_000_000,
GasUsed: 0,
Time: 1337,
Extra: nil,
MixDigest: common.Hash{},
Nonce: types.BlockNonce{},
BaseFee: big.NewInt(7),
WithdrawalsHash: &types.EmptyWithdrawalsHash,
}
}
func Calldata(st *State, accessList [][32]byte) []byte {
input := crypto.Keccak256Hash([]byte("Steps(bytes32,uint256)")).Bytes()[:4] input := crypto.Keccak256Hash([]byte("Steps(bytes32,uint256)")).Bytes()[:4]
input = append(input, common.BigToHash(common.Big0).Bytes()...) input = append(input, common.BigToHash(common.Big0).Bytes()...)
input = append(input, common.BigToHash(big.NewInt(int64(steps))).Bytes()...) input = append(input, common.BigToHash(big.NewInt(int64(st.Step))).Bytes()...)
ministart = time.Now()
contract := vm.NewContract(vm.AccountRef(from), vm.AccountRef(to), common.Big0, gas)
contract.SetCallCode(&to, crypto.Keccak256Hash(bytecode), bytecode)
_, err := interpreter.Run(contract, input, false)
return (gas - contract.Gas), err return input
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment