Skip to content

Commit 13d3e1d

Browse files
committed
(feat): add cli command for simulation
1 parent 35eb75d commit 13d3e1d

File tree

4 files changed

+208
-62
lines changed

4 files changed

+208
-62
lines changed

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.22.4
55
require (
66
github.com/ethereum/go-ethereum v1.14.7
77
github.com/holiman/uint256 v1.3.0
8+
github.com/urfave/cli/v2 v2.25.7
89
)
910

1011
require (
@@ -23,6 +24,7 @@ require (
2324
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
2425
github.com/consensys/bavard v0.1.13 // indirect
2526
github.com/consensys/gnark-crypto v0.12.1 // indirect
27+
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
2628
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect
2729
github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
2830
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
@@ -49,11 +51,13 @@ require (
4951
github.com/prometheus/procfs v0.7.3 // indirect
5052
github.com/rivo/uniseg v0.2.0 // indirect
5153
github.com/rogpeppe/go-internal v1.9.0 // indirect
54+
github.com/russross/blackfriday/v2 v2.1.0 // indirect
5255
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
5356
github.com/supranational/blst v0.3.11 // indirect
5457
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
5558
github.com/tklauser/go-sysconf v0.3.12 // indirect
5659
github.com/tklauser/numcpus v0.6.1 // indirect
60+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
5761
golang.org/x/crypto v0.22.0 // indirect
5862
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
5963
golang.org/x/sync v0.7.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj
8585
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
8686
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
8787
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
88+
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
89+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
8890
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I=
8991
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
9092
github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI=
@@ -291,6 +293,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
291293
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
292294
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
293295
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
296+
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
297+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
294298
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
295299
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
296300
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -311,6 +315,10 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA
311315
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
312316
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
313317
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
318+
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
319+
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
320+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
321+
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
314322
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
315323
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
316324
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

main.go

Lines changed: 61 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,78 @@
11
package main
22

33
import (
4-
"goevm/evm"
4+
"fmt"
5+
"goevm/simulation"
56
"os"
6-
"unsafe"
77

8-
"github.com/ethereum/go-ethereum/common"
98
"github.com/ethereum/go-ethereum/log"
10-
"github.com/holiman/uint256"
9+
"github.com/urfave/cli/v2"
1110
)
1211

13-
func main() {
14-
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
15-
16-
// Create a temporary address for simulation
17-
sender := common.HexToAddress("0x350fbDe850998AAC40f0b9364b4ACeA665a3d08c")
18-
19-
// Create a new tracer
20-
tracer := evm.NewTracer()
12+
var (
13+
StorageFlag = &cli.StringFlag{
14+
Name: "storage",
15+
Usage: "Type of storage to use for simulation (simple/remote)",
16+
Value: "simple",
17+
}
18+
Datadir = &cli.StringFlag{
19+
Name: "datadir",
20+
Usage: "Path to use for opening remote geth database",
21+
Value: "",
22+
}
23+
ContractAddressFlag = &cli.StringFlag{
24+
Name: "contract-address",
25+
Usage: "Contract address to be used for remote simulation",
26+
Value: "",
27+
}
28+
simulateCommand = &cli.Command{
29+
Name: "simulate",
30+
Usage: "Simulate EVM opcodes",
31+
Action: runSimulator,
32+
Flags: []cli.Flag{
33+
StorageFlag,
34+
Datadir,
35+
ContractAddressFlag,
36+
},
37+
}
38+
)
2139

22-
// Create a new storage using tracer
23-
storage := evm.NewSimpleStorage(tracer)
24-
defer storage.Close()
40+
func initSimulator() *cli.App {
41+
app := cli.NewApp()
42+
app.Name = "evm-simulator"
43+
app.Usage = "Simulate EVM opcodes"
44+
app.Commands = []*cli.Command{simulateCommand}
45+
return app
46+
}
2547

26-
// Create a new account and set some balance
27-
storage.CreateAccount(sender)
28-
storage.SetBalance(sender, uint256.NewInt(10000))
48+
func main() {
49+
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
2950

30-
// Arithmetic/Comparision/Logical operations
31-
var opcodes []evm.OpCode = []evm.OpCode{
32-
evm.PUSH1, 0x5, // Pushes 5 to stack [0x5]
33-
evm.PUSH1, 0x6, // Pushes 6 to stack [0x5, 0x6]
34-
evm.ADD, // Adds the top two elements of the stack [0xb]
35-
evm.PUSH1, 0x2, // Pushes 2 to stack [0xb, 0x2]
36-
evm.MUL, // Multiplies the top two elements of the stack [0x16]
37-
evm.PUSH1, 0x5, // Push key to stack [0x16, 0x5]
38-
evm.GT, // Greater than [0x0]
39-
evm.PUSH1, 0x1, // Push key to stack [0x0, 0x1]
40-
evm.OR, // Bitwise OR [0x1]
51+
simulator := initSimulator()
52+
if err := simulator.Run(os.Args); err != nil {
53+
fmt.Fprintln(os.Stderr, err)
54+
os.Exit(1)
4155
}
56+
}
4257

43-
// Environment operations
44-
opcodes = append(opcodes, []evm.OpCode{
45-
evm.ADDRESS, // Pushes the address to stack [0x1, address]
46-
evm.BALANCE, // Pushes the balance to stack [0x1, balance(0x0)]
47-
evm.POP, // Pops the top element of the stack [0x1]
48-
}...)
49-
50-
// Memory and storage operations
51-
withWrite := []evm.OpCode{
52-
// Stack: [0x1] (value)
53-
evm.PUSH1, 0x0, // Pushes 0 to stack [0x1, 0x0] (offset)
54-
evm.MSTORE, // Store value at offset in memory (total length = 32)
55-
evm.PUSH1, 0x2, // Pushes 2 to stack [0x2] (value)
56-
evm.PUSH1, 0x20, // Pushes 32 to stack [0x2, 0x20] (offset)
57-
evm.MSTORE, // Store second value at offset in memory (total length = 64)
58-
evm.PUSH1, 0x64, // Pushes 100 to stack [0x64] (value)
59-
evm.PUSH1, 0x20, // Pushes 32 to stack [0x64, 0x20] (to load value from memory)
60-
evm.MLOAD, // Load value from memory at offset [0x64, 0x2] (value)
61-
evm.SSTORE, // Store value at key in storage (key = 0x2, value = 0x64)
62-
evm.PUSH1, 0x2, // Pushes 2 to stack [0x2] (key)
63-
evm.SLOAD, // Load value from storage at key
64-
evm.STOP,
58+
func runSimulator(c *cli.Context) error {
59+
storageType := c.String("storage")
60+
if storageType == "simple" {
61+
simulation.RunSimpleSimulation()
62+
return nil
6563
}
6664

67-
opcodes = append(opcodes, withWrite...)
68-
code := *(*[]byte)(unsafe.Pointer(&opcodes))
69-
70-
// Initialise EVM instance
71-
opts := evm.NewExecutionOpts(common.Address{}, sender, 1, []byte{}, code, 10000)
72-
evm := evm.NewEVM(storage, opts, tracer)
73-
74-
log.Info("Initialized new evm instance, starting simulation", "len", len(code))
75-
76-
evm.Run()
65+
if storageType == "remote" {
66+
contractAddress := c.String("contract-address")
67+
path := c.String("datadir")
68+
if contractAddress == "" || path == "" {
69+
log.Error("Contract address and datadir are required for remote simulation")
70+
return nil
71+
}
72+
simulation.RunRemoteSimulation(path, contractAddress)
73+
return nil
74+
}
7775

78-
log.Info("Done execution")
76+
log.Error("Invalid simulation type, exiting")
77+
return nil
7978
}

simulation/main.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package simulation
2+
3+
import (
4+
"goevm/evm"
5+
"unsafe"
6+
7+
"github.com/ethereum/go-ethereum/common"
8+
"github.com/ethereum/go-ethereum/log"
9+
"github.com/holiman/uint256"
10+
)
11+
12+
func RunSimpleSimulation() {
13+
// Create a temporary address for simulation
14+
sender := common.HexToAddress("0x350fbDe850998AAC40f0b9364b4ACeA665a3d08c")
15+
16+
// Create a new tracer
17+
tracer := evm.NewTracer()
18+
19+
// Create a new storage using tracer
20+
storage := evm.NewSimpleStorage(tracer)
21+
defer storage.Close()
22+
23+
// Create a new account and set some balance
24+
storage.CreateAccount(sender)
25+
storage.SetBalance(sender, uint256.NewInt(10000))
26+
27+
// Arithmetic/Comparision/Logical operations
28+
var opcodes []evm.OpCode = []evm.OpCode{
29+
evm.PUSH1, 0x5, // Pushes 5 to stack [0x5]
30+
evm.PUSH1, 0x6, // Pushes 6 to stack [0x5, 0x6]
31+
evm.ADD, // Adds the top two elements of the stack [0xb]
32+
evm.PUSH1, 0x2, // Pushes 2 to stack [0xb, 0x2]
33+
evm.MUL, // Multiplies the top two elements of the stack [0x16]
34+
evm.PUSH1, 0x5, // Push key to stack [0x16, 0x5]
35+
evm.GT, // Greater than [0x0]
36+
evm.PUSH1, 0x1, // Push key to stack [0x0, 0x1]
37+
evm.OR, // Bitwise OR [0x1]
38+
}
39+
40+
// Environment operations
41+
opcodes = append(opcodes, []evm.OpCode{
42+
evm.ADDRESS, // Pushes the address to stack [0x1, address]
43+
evm.BALANCE, // Pushes the balance to stack [0x1, balance(0x0)]
44+
evm.POP, // Pops the top element of the stack [0x1]
45+
}...)
46+
47+
// Memory and storage operations
48+
withWrite := []evm.OpCode{
49+
// Stack: [0x1] (value)
50+
evm.PUSH1, 0x0, // Pushes 0 to stack [0x1, 0x0] (offset)
51+
evm.MSTORE, // Store value at offset in memory (total length = 32)
52+
evm.PUSH1, 0x2, // Pushes 2 to stack [0x2] (value)
53+
evm.PUSH1, 0x20, // Pushes 32 to stack [0x2, 0x20] (offset)
54+
evm.MSTORE, // Store second value at offset in memory (total length = 64)
55+
evm.PUSH1, 0x64, // Pushes 100 to stack [0x64] (value)
56+
evm.PUSH1, 0x20, // Pushes 32 to stack [0x64, 0x20] (to load value from memory)
57+
evm.MLOAD, // Load value from memory at offset [0x64, 0x2] (value)
58+
evm.SSTORE, // Store value at key in storage (key = 0x2, value = 0x64)
59+
evm.PUSH1, 0x2, // Pushes 2 to stack [0x2] (key)
60+
evm.SLOAD, // Load value from storage at key
61+
evm.STOP,
62+
}
63+
64+
opcodes = append(opcodes, withWrite...)
65+
code := *(*[]byte)(unsafe.Pointer(&opcodes))
66+
67+
// Initialise EVM instance
68+
opts := evm.NewExecutionOpts(common.Address{}, sender, 1, []byte{}, code, 10000)
69+
evm := evm.NewEVM(storage, opts, tracer)
70+
71+
log.Info("Initialized new evm instance, starting simple simulation", "len", len(code))
72+
73+
evm.Run()
74+
75+
log.Info("Done execution, exiting")
76+
}
77+
78+
func RunRemoteSimulation(path string, contractAddress string) {
79+
// Create a temporary address for simulation
80+
sender := common.HexToAddress("0x350fbDe850998AAC40f0b9364b4ACeA665a3d08c")
81+
82+
// Initialise the contract address
83+
contract := common.HexToAddress(contractAddress)
84+
85+
// Create a new tracer
86+
tracer := evm.NewTracer()
87+
88+
// Create a new storage using tracer
89+
storage := evm.NewRemoteStorage(path, tracer)
90+
defer storage.Close()
91+
92+
// Arithmetic/Comparision/Logical operations
93+
var opcodes []evm.OpCode = []evm.OpCode{
94+
evm.PUSH1, 0x5, // Pushes 5 to stack [0x5]
95+
evm.PUSH1, 0x6, // Pushes 6 to stack [0x5, 0x6]
96+
evm.ADD, // Adds the top two elements of the stack [0xb]
97+
evm.PUSH1, 0x2, // Pushes 2 to stack [0xb, 0x2]
98+
evm.MUL, // Multiplies the top two elements of the stack [0x16]
99+
evm.PUSH1, 0x5, // Push key to stack [0x16, 0x5]
100+
evm.GT, // Greater than [0x0]
101+
evm.PUSH1, 0x1, // Push key to stack [0x0, 0x1]
102+
evm.OR, // Bitwise OR [0x1]
103+
}
104+
105+
// Environment operations
106+
opcodes = append(opcodes, []evm.OpCode{
107+
evm.ADDRESS, // Pushes the address to stack [0x1, address]
108+
evm.BALANCE, // Pushes the balance to stack [0x1, balance(0x0)]
109+
evm.POP, // Pops the top element of the stack [0x1]
110+
}...)
111+
112+
// Memory and storage operations
113+
opcodes = append(opcodes, []evm.OpCode{
114+
// Stack: [0x1] (value)
115+
evm.PUSH1, 0x0, // Pushes 0 to stack [0x1, 0x0] (offset)
116+
evm.MSTORE, // Store value at offset in memory (total length = 32)
117+
evm.PUSH1, 0x2, // Pushes 2 to stack [0x2] (value)
118+
evm.PUSH1, 0x20, // Pushes 32 to stack [0x2, 0x20] (offset)
119+
evm.MSTORE, // Store second value at offset in memory (total length = 64)
120+
evm.PUSH1, 0x0, // Pushes 0 to stack [0x0] (key) (val1 in our test contract)
121+
evm.SLOAD, // Load value from storage at key
122+
evm.PUSH1, 0x1, // Pushes 2 to stack [0x1] (key) (val2 in our test contract)
123+
evm.SLOAD, // Load value from storage at key
124+
evm.STOP, // STOP
125+
}...)
126+
127+
// Initialise EVM instance
128+
code := *(*[]byte)(unsafe.Pointer(&opcodes))
129+
opts := evm.NewExecutionOpts(contract, sender, 1, []byte{}, code, 10000)
130+
evm := evm.NewEVM(storage, opts, tracer)
131+
132+
log.Info("Initialized new evm instance, starting remote simulation", "len", len(code))
133+
evm.Run()
134+
log.Info("Done execution, exiting")
135+
}

0 commit comments

Comments
 (0)