Skip to content
This repository was archived by the owner on Jun 6, 2025. It is now read-only.

Commit ec0f76f

Browse files
committed
WrapperCodeGenerator: add script for generating wrappers
- ExportInstructionSet: export instruction set based on input version to json - ImportInstructionSet: import instruction set from json - OpCodeWrapperGenerator: generate wrappers for an instruction set
1 parent 5d400f1 commit ec0f76f

File tree

1 file changed

+219
-0
lines changed

1 file changed

+219
-0
lines changed

WrapperCodeGenerator/main.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"text/template"
7+
8+
"github.com/ethereum/go-ethereum/core/vm"
9+
"github.com/ethereum/go-ethereum/params"
10+
)
11+
12+
type InstructionSetJSON struct {
13+
Version string `json:"version"`
14+
InstructionSet []vm.OperationAttribute `json:"instruction_set"`
15+
}
16+
func ExportInstructionSet(version string) {
17+
// Get the instruction set
18+
var rules params.Rules
19+
switch {
20+
case version == "Homestead":
21+
rules = params.Rules{
22+
IsHomestead: true,
23+
}
24+
case version == "TangerineWhistle":
25+
rules = params.Rules{
26+
IsEIP150: true,
27+
}
28+
case version == "SpuriousDragon":
29+
rules = params.Rules{
30+
IsEIP158: true,
31+
}
32+
case version == "Byzantium":
33+
rules = params.Rules{
34+
IsByzantium: true,
35+
}
36+
case version == "Constantinople":
37+
rules = params.Rules{
38+
IsConstantinople: true,
39+
}
40+
case version == "Istanbul":
41+
rules = params.Rules{
42+
IsIstanbul: true,
43+
}
44+
case version == "Berlin":
45+
rules = params.Rules{
46+
IsBerlin: true,
47+
}
48+
case version == "London":
49+
rules = params.Rules{
50+
IsLondon: true,
51+
}
52+
default:
53+
// frontier by default
54+
rules = params.Rules{
55+
56+
}
57+
}
58+
instructionSet := vm.ExportInstructionSet(rules)
59+
60+
// Export the instruction set to json
61+
file, err := os.Create("instruction_set.json")
62+
if err != nil {
63+
panic(err)
64+
}
65+
defer file.Close()
66+
67+
encoder := json.NewEncoder(file)
68+
encoder.SetIndent("", " ")
69+
err = encoder.Encode(
70+
InstructionSetJSON{
71+
Version: version,
72+
InstructionSet: instructionSet,
73+
},
74+
)
75+
if err != nil {
76+
panic(err)
77+
}
78+
}
79+
80+
func ImportInstructionSet() InstructionSetJSON {
81+
// Import the instruction set from json
82+
file, err := os.Open("instruction_set.json")
83+
if err != nil {
84+
panic(err)
85+
}
86+
defer file.Close()
87+
88+
decoder := json.NewDecoder(file)
89+
var instructionSetJSON InstructionSetJSON
90+
err = decoder.Decode(&instructionSetJSON)
91+
if err != nil {
92+
panic(err)
93+
}
94+
return instructionSetJSON
95+
}
96+
97+
func OpCodeWrapperGenerator() {
98+
// Get instruction set
99+
instructionSetJSON := ImportInstructionSet()
100+
101+
// Define the template
102+
tmpl := template.Must(template.New("opcode").Parse(`
103+
package vm
104+
105+
import "github.com/ethereum/go-ethereum/common/math"
106+
{{$parent := .}}
107+
{{range .InstructionSet}}
108+
func {{.Name}}Wrapper{{$parent.Version}}(operation *operation, pc *uint64, in *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
109+
{{- if .Supported}}
110+
{{- if or .MemorySize .DynamicCost}}
111+
mem := callContext.Memory
112+
{{- end}}
113+
stack := callContext.Stack
114+
contract := callContext.Contract
115+
var err error
116+
var res []byte
117+
118+
in.evm.Context.Counter++
119+
120+
if sLen := stack.len(); sLen < {{.MinStack}} {
121+
return nil, &ErrStackUnderflow{stackLen: sLen, required: {{.MinStack}}}
122+
} else if sLen > {{.MaxStack}} {
123+
return nil, &ErrStackOverflow{stackLen: sLen, limit: {{.MaxStack}}}
124+
}
125+
{{- if or .Writes (eq .Name "opCall")}}
126+
if in.readOnly && in.evm.chainRules.IsByzantium {
127+
{{- if .Writes}}
128+
return nil, ErrWriteProtection
129+
{{- else if (eq .Name "opCall")}}
130+
if stack.Back(2).Sign() != 0 {
131+
return nil, ErrWriteProtection
132+
}
133+
{{- end}}
134+
}
135+
{{- end}}
136+
{{- if not .DynamicCost}}
137+
if !contract.UseGas({{.ConstantGas}}) {
138+
return nil, ErrOutOfGas
139+
}
140+
{{- end}}
141+
{{- if or .MemorySize .DynamicCost}}
142+
var memorySize uint64
143+
{{- end}}
144+
{{- if .MemorySize}}
145+
memSize, overflow := operation.memorySize(stack)
146+
if overflow {
147+
return nil, ErrGasUintOverflow
148+
}
149+
if memorySize, overflow = math.SafeMul(toWordSize(memSize), 32); overflow {
150+
return nil, ErrGasUintOverflow
151+
}
152+
{{- end}}
153+
{{- if .DynamicCost}}
154+
var dynamicCost uint64
155+
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
156+
if err != nil || !contract.UseGas({{.ConstantGas}} + dynamicCost) {
157+
return nil, ErrOutOfGas
158+
}
159+
{{- end}}
160+
{{- if or .MemorySize .DynamicCost}}
161+
if memorySize > 0 {
162+
mem.Resize(memorySize)
163+
}
164+
{{- end}}
165+
res, err = operation.execute(pc, in, callContext)
166+
{{- if .Returns}}
167+
in.returnData = res
168+
{{- end}}
169+
if err != nil {
170+
return nil, err
171+
}
172+
{{- if .Reverts}}
173+
return res, ErrExecutionReverted
174+
{{- end}}
175+
{{- if and (not .Jumps) (not .Reverts)}}
176+
*pc++
177+
{{- end}}
178+
{{- if not .Reverts}}
179+
return res, nil
180+
{{- end}}
181+
{{- else}}
182+
return nil, nil
183+
{{- end}}
184+
}
185+
{{end}}
186+
var stringToWrapper{{$parent.Version}} = map[string]executionWrapperFunc{
187+
{{- range .InstructionSet}}
188+
"{{.Name}}": {{.Name}}Wrapper{{$parent.Version}},{{end}}
189+
}
190+
`))
191+
192+
// Create the source file
193+
file, err := os.Create("instruction_wrapper_" + instructionSetJSON.Version + ".go")
194+
if err != nil {
195+
panic(err)
196+
}
197+
defer file.Close()
198+
199+
// Execute the template and write to the source file
200+
err = tmpl.Execute(file, instructionSetJSON)
201+
if err != nil {
202+
panic(err)
203+
}
204+
}
205+
206+
func main() {
207+
if len(os.Args) > 1 {
208+
version := os.Args[1]
209+
ExportInstructionSet(version)
210+
OpCodeWrapperGenerator()
211+
} else {
212+
// export all by default
213+
versions := []string{"Homestead", "TangerineWhistle", "SpuriousDragon", "Byzantium", "Constantinople", "Istanbul", "Berlin", "London", "Frontier"}
214+
for _, version := range versions {
215+
ExportInstructionSet(version)
216+
OpCodeWrapperGenerator()
217+
}
218+
}
219+
}

0 commit comments

Comments
 (0)