core/vm: apply suggestions, make ReturnStack an object

This commit is contained in:
Marius van der Wijden 2024-09-04 16:27:13 +02:00
parent 6549a87202
commit ddb9907a7a
2 changed files with 29 additions and 23 deletions

View file

@ -790,19 +790,19 @@ func opRjumpi(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
func opRjumpv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opRjumpv(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
var ( var (
code = scope.Contract.CodeAt(scope.CodeSection) code = scope.Contract.CodeAt(scope.CodeSection)
count = uint64(code[*pc+1]) + 1 maxIndex = uint64(code[*pc+1]) + 1
idx = scope.Stack.pop() idx = scope.Stack.pop()
) )
if idx, overflow := idx.Uint64WithOverflow(); overflow || idx >= count { if idx, overflow := idx.Uint64WithOverflow(); overflow || idx >= maxIndex {
// Index out-of-bounds, don't branch, just skip over immediate // Index out-of-bounds, don't branch, just skip over immediate
// argument. // argument.
*pc += 1 + count*2 *pc += 1 + maxIndex*2
return nil, nil return nil, nil
} }
offset := parseInt16(code[*pc+2+2*idx.Uint64():]) offset := parseInt16(code[*pc+2+2*idx.Uint64():])
// move pc past op and count byte (2), move past count number of 16bit offsets (count*2), add relative offset, subtract 1 to // move pc past op and count byte (2), move past count number of 16bit offsets (count*2), add relative offset, subtract 1 to
// account for interpreter loop. // account for interpreter loop.
*pc = uint64(int64(*pc+2+count*2) + int64(offset) - 1) *pc = uint64(int64(*pc+2+maxIndex*2) + int64(offset) - 1)
return nil, nil return nil, nil
} }
@ -816,7 +816,7 @@ func opCallf(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
if scope.Stack.len()+int(typ.MaxStackHeight)-int(typ.Input) > 1024 { if scope.Stack.len()+int(typ.MaxStackHeight)-int(typ.Input) > 1024 {
return nil, fmt.Errorf("stack overflow") return nil, fmt.Errorf("stack overflow")
} }
if len(scope.ReturnStack) > 1024 { if scope.ReturnStack.Len() > 1024 {
return nil, fmt.Errorf("return stack overflow") return nil, fmt.Errorf("return stack overflow")
} }
retCtx := &ReturnContext{ retCtx := &ReturnContext{
@ -826,23 +826,18 @@ func opCallf(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
} }
scope.ReturnStack = append(scope.ReturnStack, retCtx) scope.ReturnStack = append(scope.ReturnStack, retCtx)
scope.CodeSection = uint64(idx) scope.CodeSection = uint64(idx)
*pc = 0 *pc = uint64(math.MaxUint64)
*pc -= 1 // hacks xD (interpreter loop)
return nil, nil return nil, nil
} }
// opRetf implements the RETF opcode // opRetf implements the RETF opcode
func opRetf(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opRetf(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
var ( retCtx := scope.ReturnStack.Pop()
last = len(scope.ReturnStack) - 1
retCtx = scope.ReturnStack[last]
)
scope.ReturnStack = scope.ReturnStack[:last]
scope.CodeSection = retCtx.Section scope.CodeSection = retCtx.Section
*pc = retCtx.Pc - 1 *pc = retCtx.Pc - 1
// If returning from top frame, exit cleanly. // If returning from top frame, exit cleanly.
if len(scope.ReturnStack) == 0 { if scope.ReturnStack.Len() == 0 {
return nil, errStopToken return nil, errStopToken
} }
return nil, nil return nil, nil
@ -858,8 +853,7 @@ func opJumpf(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]by
return nil, fmt.Errorf("stack overflow") return nil, fmt.Errorf("stack overflow")
} }
scope.CodeSection = uint64(idx) scope.CodeSection = uint64(idx)
*pc = 0 *pc = uint64(math.MaxUint64)
*pc -= 1 // hacks xD (interpreter loop)
return nil, nil return nil, nil
} }
@ -947,11 +941,7 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
} }
c.DataSize = len(c.Data) c.DataSize = len(c.Data)
// Restore context // Restore context
var ( retCtx := scope.ReturnStack.Pop()
last = len(scope.ReturnStack) - 1
retCtx = scope.ReturnStack[last]
)
scope.ReturnStack = scope.ReturnStack[:last]
scope.CodeSection = retCtx.Section scope.CodeSection = retCtx.Section
*pc = retCtx.Pc - 1 // account for interpreter loop *pc = retCtx.Pc - 1 // account for interpreter loop
return c.MarshalBinary(), errStopToken return c.MarshalBinary(), errStopToken

View file

@ -44,10 +44,26 @@ type ScopeContext struct {
Contract *Contract Contract *Contract
CodeSection uint64 CodeSection uint64
ReturnStack []*ReturnContext ReturnStack ReturnStack
InitCodeMode bool InitCodeMode bool
} }
type ReturnStack []*ReturnContext
// Pop removes an element from the return stack
// Panics if the return stack is empty, which should
// never happen, since EOF code is verified for that.
func (ctx *ReturnStack) Pop() *ReturnContext {
item := (*ctx)[ctx.Len()-1]
*ctx = (*ctx)[:ctx.Len()-1]
return item
}
// Len returns the length of the return stack
func (ctx *ReturnStack) Len() int {
return len(*ctx)
}
type ReturnContext struct { type ReturnContext struct {
Section uint64 Section uint64
Pc uint64 Pc uint64