Skip to content

Commit 8783059

Browse files
committed
core/vm: refactor + speed up eof validation
core/vm: some clarifications in the eof code core/vm: clarifications + minor speedup core/vm: clarifications + lint + minor speedup core/vm, core/asm: support eof in asm instruction iteration core/vm: comment out unused core/vm: remove gasfunctions
1 parent a3031cd commit 8783059

File tree

15 files changed

+207
-196
lines changed

15 files changed

+207
-196
lines changed

cmd/eofdump/eofparser.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ func parseAndValidate(s string, isInitCode bool) (*vm.Container, error) {
215215
}
216216

217217
func parse(b []byte, isInitCode bool) (*vm.Container, error) {
218-
219218
var c vm.Container
220219
if err := c.UnmarshalBinary(b, isInitCode); err != nil {
221220
return nil, err

cmd/eofdump/parse_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ func FuzzEofParsing(f *testing.F) {
5050
if err := c.UnmarshalBinary(data, true); err == nil {
5151
c.ValidateCode(&jt, true)
5252
if have := c.MarshalBinary(); !bytes.Equal(have, data) {
53-
f.Fatal("Unmarshal-> Marshal failure!")
53+
t.Fatal("Unmarshal-> Marshal failure!")
5454
}
5555
}
5656
if err := c.UnmarshalBinary(data, false); err == nil {
5757
c.ValidateCode(&jt, false)
5858
if have := c.MarshalBinary(); !bytes.Equal(have, data) {
59-
f.Fatal("Unmarshal-> Marshal failure!")
59+
t.Fatal("Unmarshal-> Marshal failure!")
6060
}
6161
}
6262
if !bytes.Equal(cpy, data) {
@@ -131,7 +131,6 @@ func testEofParse(t *testing.T, isInitCode bool, wantFile string) {
131131
}
132132
}
133133
line++
134-
135134
}
136135
corpus.Close()
137136
}

core/asm/asm.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ func (it *instructionIterator) Next() bool {
6565
}
6666

6767
it.op = vm.OpCode(it.code[it.pc])
68-
if it.op.IsPush() {
69-
a := uint64(it.op) - uint64(vm.PUSH0)
70-
u := it.pc + 1 + a
68+
69+
if a := vm.Immediates(it.op); a > 0 {
70+
u := it.pc + 1 + uint64(a)
7171
if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u {
72-
it.error = fmt.Errorf("incomplete push instruction at %v", it.pc)
72+
it.error = fmt.Errorf("incomplete instruction at %v", it.pc)
7373
return false
7474
}
7575
it.arg = it.code[it.pc+1 : u]

core/asm/asm_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ func TestInstructionIterator(t *testing.T) {
2929
code string
3030
wantErr string
3131
}{
32-
{2, "61000000", ""}, // valid code
33-
{0, "6100", "incomplete push instruction at 0"}, // invalid code
34-
{2, "5900", ""}, // push0
35-
{0, "", ""}, // empty
32+
{2, "61000000", ""}, // valid code
33+
{0, "6100", "incomplete instruction at 0"}, // invalid code
34+
{2, "5900", ""}, // push0
35+
{0, "", ""}, // empty
36+
{2, "d1aabb00", ""}, // DATALOADN(aabb),STOP
3637

3738
} {
3839
var (

core/vm/analysis_eof.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ func eofCodeBitmapInternal(code, bits bitvec) bitvec {
3636
pc++
3737

3838
switch {
39-
case op >= PUSH1 && op <= PUSH32:
39+
case op < PUSH1:
40+
continue
41+
case op <= PUSH32:
4042
numbits = uint16(op - PUSH1 + 1)
4143
case op == RJUMP || op == RJUMPI || op == CALLF || op == JUMPF || op == DATALOADN:
4244
numbits = 2

core/vm/eips.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,13 @@ func enable4762(jt *JumpTable) {
535535
}
536536

537537
// enableEOF applies the EOF changes.
538+
// OBS! For EOF, there are two changes:
539+
// 1. Two separate jumptables are required. One, EOF-jumptable, is used by
540+
// eof contracts. This one contains things like RJUMP.
541+
// 2. The regular non-eof jumptable also needs to be modified, specifically to
542+
// modify how EXTCODECOPY works under the hood.
543+
//
544+
// This method _only_ deals with case 1.
538545
func enableEOF(jt *JumpTable) {
539546
// Deprecate opcodes
540547
undefined := &operation{

core/vm/eof.go

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ func isEOFVersion1(code []byte) bool {
6666

6767
// Container is an EOF container object.
6868
type Container struct {
69-
types []*functionMetadata
70-
code [][]byte
71-
sections []*Container
72-
containerCode [][]byte
73-
data []byte
74-
dataSize int // might be more than len(data)
69+
types []*functionMetadata
70+
codeSections [][]byte
71+
subContainers []*Container
72+
subContainerCodes [][]byte
73+
data []byte
74+
dataSize int // might be more than len(data)
7575
}
7676

7777
// functionMetadata is an EOF function signature.
@@ -92,15 +92,15 @@ func (c *Container) MarshalBinary() []byte {
9292
b = append(b, kindTypes)
9393
b = binary.BigEndian.AppendUint16(b, uint16(len(c.types)*4))
9494
b = append(b, kindCode)
95-
b = binary.BigEndian.AppendUint16(b, uint16(len(c.code)))
96-
for _, code := range c.code {
97-
b = binary.BigEndian.AppendUint16(b, uint16(len(code)))
95+
b = binary.BigEndian.AppendUint16(b, uint16(len(c.codeSections)))
96+
for _, codeSection := range c.codeSections {
97+
b = binary.BigEndian.AppendUint16(b, uint16(len(codeSection)))
9898
}
9999
var encodedContainer [][]byte
100-
if len(c.sections) != 0 {
100+
if len(c.subContainers) != 0 {
101101
b = append(b, kindContainer)
102-
b = binary.BigEndian.AppendUint16(b, uint16(len(c.sections)))
103-
for _, section := range c.sections {
102+
b = binary.BigEndian.AppendUint16(b, uint16(len(c.subContainers)))
103+
for _, section := range c.subContainers {
104104
encoded := section.MarshalBinary()
105105
b = binary.BigEndian.AppendUint16(b, uint16(len(encoded)))
106106
encodedContainer = append(encodedContainer, encoded)
@@ -114,7 +114,7 @@ func (c *Container) MarshalBinary() []byte {
114114
for _, ty := range c.types {
115115
b = append(b, []byte{ty.inputs, ty.outputs, byte(ty.maxStackHeight >> 8), byte(ty.maxStackHeight & 0x00ff)}...)
116116
}
117-
for _, code := range c.code {
117+
for _, code := range c.codeSections {
118118
b = append(b, code...)
119119
}
120120
for _, section := range encodedContainer {
@@ -228,7 +228,7 @@ func (c *Container) unmarshalSubContainer(b []byte, isInitcode bool, topLevel bo
228228

229229
// Parse types section.
230230
idx := offsetTerminator + 1
231-
var types []*functionMetadata
231+
var types = make([]*functionMetadata, 0, typesSize/4)
232232
for i := 0; i < typesSize/4; i++ {
233233
sig := &functionMetadata{
234234
inputs: b[idx+i*4],
@@ -253,45 +253,44 @@ func (c *Container) unmarshalSubContainer(b []byte, isInitcode bool, topLevel bo
253253

254254
// Parse code sections.
255255
idx += typesSize
256-
code := make([][]byte, len(codeSizes))
256+
codeSections := make([][]byte, len(codeSizes))
257257
for i, size := range codeSizes {
258258
if size == 0 {
259259
return fmt.Errorf("%w for section %d: size must not be 0", ErrInvalidCodeSize, i)
260260
}
261-
code[i] = b[idx : idx+size]
261+
codeSections[i] = b[idx : idx+size]
262262
idx += size
263263
}
264-
c.code = code
265-
264+
c.codeSections = codeSections
266265
// Parse the optional container sizes.
267266
if len(containerSizes) != 0 {
268267
if len(containerSizes) > maxContainerSections {
269268
return fmt.Errorf("%w number of container section exceed: %v: have %v", ErrInvalidContainerSectionSize, maxContainerSections, len(containerSizes))
270269
}
271-
containerCode := make([][]byte, 0, len(containerSizes))
272-
container := make([]*Container, 0, len(containerSizes))
270+
subContainerCodes := make([][]byte, 0, len(containerSizes))
271+
subContainers := make([]*Container, 0, len(containerSizes))
273272
for i, size := range containerSizes {
274273
if size == 0 || idx+size > len(b) {
275274
return fmt.Errorf("%w for section %d: size must not be 0", ErrInvalidContainerSectionSize, i)
276275
}
277-
c := new(Container)
276+
subC := new(Container)
278277
end := min(idx+size, len(b))
279-
if err := c.unmarshalSubContainer(b[idx:end], isInitcode, false); err != nil {
278+
if err := subC.unmarshalSubContainer(b[idx:end], isInitcode, false); err != nil {
280279
if topLevel {
281280
return fmt.Errorf("%w in sub container %d", err, i)
282281
}
283282
return err
284283
}
285-
container = append(container, c)
286-
containerCode = append(containerCode, b[idx:end])
284+
subContainers = append(subContainers, subC)
285+
subContainerCodes = append(subContainerCodes, b[idx:end])
287286

288287
idx += size
289288
}
290-
c.sections = container
291-
c.containerCode = containerCode
289+
c.subContainers = subContainers
290+
c.subContainerCodes = subContainerCodes
292291
}
293292

294-
// Parse data section.
293+
//Parse data section.
295294
end := len(b)
296295
if !isInitcode {
297296
end = min(idx+dataSize, len(b))
@@ -327,7 +326,7 @@ func (c *Container) validateSubContainer(jt *JumpTable, refBy int) error {
327326
// should not mean 2 and 3 should be visited twice
328327
var (
329328
index = toVisit[0]
330-
code = c.code[index]
329+
code = c.codeSections[index]
331330
)
332331
if _, ok := visited[index]; !ok {
333332
res, err := validateCode(code, index, c, jt, refBy == refByEOFCreate)
@@ -359,10 +358,10 @@ func (c *Container) validateSubContainer(jt *JumpTable, refBy int) error {
359358
toVisit = toVisit[1:]
360359
}
361360
// Make sure every code section is visited at least once.
362-
if len(visited) != len(c.code) {
361+
if len(visited) != len(c.codeSections) {
363362
return ErrUnreachableCode
364363
}
365-
for idx, container := range c.sections {
364+
for idx, container := range c.subContainers {
366365
reference, ok := subContainerVisited[idx]
367366
if !ok {
368367
return ErrOrphanedSubcontainer
@@ -444,14 +443,14 @@ func (c *Container) String() string {
444443
result += fmt.Sprintf("KindType: %02x\n", kindTypes)
445444
result += fmt.Sprintf("TypesSize: %04x\n", len(c.types)*4)
446445
result += fmt.Sprintf("KindCode: %02x\n", kindCode)
447-
result += fmt.Sprintf("CodeSize: %04x\n", len(c.code))
448-
for i, code := range c.code {
446+
result += fmt.Sprintf("CodeSize: %04x\n", len(c.codeSections))
447+
for i, code := range c.codeSections {
449448
result += fmt.Sprintf("Code %v length: %04x\n", i, len(code))
450449
}
451-
if len(c.sections) != 0 {
450+
if len(c.subContainers) != 0 {
452451
result += fmt.Sprintf("KindContainer: %02x\n", kindContainer)
453-
result += fmt.Sprintf("ContainerSize: %04x\n", len(c.sections))
454-
for i, section := range c.sections {
452+
result += fmt.Sprintf("ContainerSize: %04x\n", len(c.subContainers))
453+
for i, section := range c.subContainers {
455454
result += fmt.Sprintf("Container %v length: %04x\n", i, len(section.MarshalBinary()))
456455
}
457456
}
@@ -464,10 +463,10 @@ func (c *Container) String() string {
464463
for i, typ := range c.types {
465464
result += fmt.Sprintf("Type %v: %v\n", i, hex.EncodeToString([]byte{typ.inputs, typ.outputs, byte(typ.maxStackHeight >> 8), byte(typ.maxStackHeight & 0x00ff)}))
466465
}
467-
for i, code := range c.code {
466+
for i, code := range c.codeSections {
468467
result += fmt.Sprintf("Code %v: %v\n", i, hex.EncodeToString(code))
469468
}
470-
for i, section := range c.sections {
469+
for i, section := range c.subContainers {
471470
result += fmt.Sprintf("Section %v: %v\n", i, hex.EncodeToString(section.MarshalBinary()))
472471
}
473472
result += fmt.Sprintf("Data: %v\n", hex.EncodeToString(c.data))

core/vm/eof_immediates.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,9 @@ func init() {
5555
terminals[REVERT] = true
5656
terminals[INVALID] = true
5757
}
58+
59+
// Immediates returns the number bytes of immediates (argument not from
60+
// stack but from code) a given opcode has.
61+
func Immediates(op OpCode) int {
62+
return int(immediates[op])
63+
}

core/vm/eof_instructions.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616

1717
package vm
1818

19-
// opExtCodeCopyEOF implements the EXTCODECOPY opcode for EOF-enabled forks.
20-
func opExtCodeCopyEOF(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
21-
panic("not implemented")
22-
}
23-
2419
// opRjump implements the RJUMP opcode.
2520
func opRjump(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
2621
panic("not implemented")

core/vm/eof_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ func TestEOFMarshaling(t *testing.T) {
3232
}{
3333
{
3434
want: Container{
35-
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
36-
code: [][]byte{common.Hex2Bytes("604200")},
37-
data: []byte{0x01, 0x02, 0x03},
38-
dataSize: 3,
35+
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
36+
codeSections: [][]byte{common.Hex2Bytes("604200")},
37+
data: []byte{0x01, 0x02, 0x03},
38+
dataSize: 3,
3939
},
4040
},
4141
{
4242
want: Container{
43-
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
44-
code: [][]byte{common.Hex2Bytes("604200")},
45-
data: []byte{0x01, 0x02, 0x03},
46-
dataSize: 3,
43+
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
44+
codeSections: [][]byte{common.Hex2Bytes("604200")},
45+
data: []byte{0x01, 0x02, 0x03},
46+
dataSize: 3,
4747
},
4848
},
4949
{
@@ -53,7 +53,7 @@ func TestEOFMarshaling(t *testing.T) {
5353
{inputs: 2, outputs: 3, maxStackHeight: 4},
5454
{inputs: 1, outputs: 1, maxStackHeight: 1},
5555
},
56-
code: [][]byte{
56+
codeSections: [][]byte{
5757
common.Hex2Bytes("604200"),
5858
common.Hex2Bytes("6042604200"),
5959
common.Hex2Bytes("00"),
@@ -82,11 +82,11 @@ func TestEOFSubcontainer(t *testing.T) {
8282
t.Fatal(err)
8383
}
8484
container := Container{
85-
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
86-
code: [][]byte{common.Hex2Bytes("604200")},
87-
sections: []*Container{subcontainer},
88-
data: []byte{0x01, 0x02, 0x03},
89-
dataSize: 3,
85+
types: []*functionMetadata{{inputs: 0, outputs: 0x80, maxStackHeight: 1}},
86+
codeSections: [][]byte{common.Hex2Bytes("604200")},
87+
subContainers: []*Container{subcontainer},
88+
data: []byte{0x01, 0x02, 0x03},
89+
dataSize: 3,
9090
}
9191
var (
9292
b = container.MarshalBinary()

0 commit comments

Comments
 (0)