Skip to content

Commit

Permalink
tos
Browse files Browse the repository at this point in the history
  • Loading branch information
sunny2022da committed Feb 1, 2024
1 parent f90a16a commit 94f150c
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 56 deletions.
2 changes: 1 addition & 1 deletion core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin

func (c *Contract) validJumpdest(dest *uint256.Int) bool {
udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// PC cannot go beyond Len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if overflow || udest >= uint64(len(c.Code)) {
return false
Expand Down
8 changes: 4 additions & 4 deletions core/vm/gas_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,8 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
}

func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)

// expByteLen := uint64((stack.data[stack.Len()-2].BitLen() + 7) / 8)
expByteLen := uint64((stack.Back(1).BitLen() + 7) / 8)
var (
gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas
overflow bool
Expand All @@ -349,8 +349,8 @@ func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem
}

func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)

// expByteLen := uint64((stack.data[stack.Len()-2].BitLen() + 7) / 8)
expByteLen := uint64((stack.Back(1).BitLen() + 7) / 8)
var (
gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas
overflow bool
Expand Down
4 changes: 2 additions & 2 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = scope.Contract.Gas
)

// Apply EIP150
gas -= gas / 64
scope.Contract.UseGas(gas)
Expand Down Expand Up @@ -813,14 +814,12 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))

return ret, errStopToken
}

func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.pop()
ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64()))

interpreter.returnData = ret
return ret, ErrExecutionReverted
}
Expand Down Expand Up @@ -860,6 +859,7 @@ func makeLog(size int) executionFunc {
return nil, ErrWriteProtection
}
topics := make([]common.Hash, size)

stack := scope.Stack
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
Expand Down
14 changes: 7 additions & 7 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
stack.push(x)
stack.push(y)
opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
if stack.Len() != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", name, stack.Len())
}
actual := stack.pop()

Expand Down Expand Up @@ -604,14 +604,14 @@ func TestOpTstore(t *testing.T) {
stack.push(new(uint256.Int))
opTstore(&pc, evmInterpreter, &scopeContext)
// there should be no elements on the stack after TSTORE
if stack.len() != 0 {
if stack.Len() != 0 {
t.Fatal("stack wrong size")
}
// push the location to the stack
stack.push(new(uint256.Int))
opTload(&pc, evmInterpreter, &scopeContext)
// there should be one element on the stack after TLOAD
if stack.len() != 1 {
if stack.Len() != 1 {
t.Fatal("stack wrong size")
}
val := stack.peek()
Expand Down Expand Up @@ -700,7 +700,7 @@ func TestCreate2Addreses(t *testing.T) {
/*
stack := newstack()
// salt, but we don't need that for this test
stack.push(big.NewInt(int64(len(code)))) //size
stack.push(big.NewInt(int64(Len(code)))) //size
stack.push(big.NewInt(0)) // memstart
stack.push(big.NewInt(0)) // value
gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0)
Expand Down Expand Up @@ -732,8 +732,8 @@ func TestRandom(t *testing.T) {
evmInterpreter = env.interpreter
)
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
if len(stack.data) != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
if stack.Len() != 1 {
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, stack.Len())
}
actual := stack.pop()
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes()))
Expand Down
2 changes: 1 addition & 1 deletion core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
operation := in.table[op]
cost = operation.constantGas // For tracing
// Validate stack
if sLen := stack.len(); sLen < operation.minStack {
if sLen := stack.Len(); sLen < operation.minStack {
return nil, &ErrStackUnderflow{stackLen: sLen, required: operation.minStack}
} else if sLen > operation.maxStack {
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
Expand Down
150 changes: 139 additions & 11 deletions core/vm/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package vm

import (
"fmt"
"sync"

"github.com/holiman/uint256"
Expand All @@ -32,51 +33,178 @@ var stackPool = sync.Pool{
// expected to be changed and modified. stack does not take care of adding newly
// initialised objects.
type Stack struct {
data []uint256.Int
Tos1 uint256.Int // Todo-dav: make this private
Tos2 uint256.Int // Todo-dav: make this private
Tos1InUse bool // Todo-dav: make this private
Tos2InUse bool // Todo-dav: make this private
data []uint256.Int
}

func newstack() *Stack {
return stackPool.Get().(*Stack)
stack := stackPool.Get().(*Stack)
stack.Tos1InUse = false
stack.Tos2InUse = false
return stack
}

func returnStack(s *Stack) {
s.data = s.data[:0]
stackPool.Put(s)
s.Tos1InUse = false
s.Tos2InUse = false
}

// Data returns the underlying uint256.Int array.
func (st *Stack) Data() []uint256.Int {
return st.data
}

// tos2->tos1->st.data[Len-1]-> ...

// push push to tos
func (st *Stack) push(d *uint256.Int) {
if !st.Tos1InUse {
st.Tos1 = *d
st.Tos1InUse = true
} else {
if st.Tos2InUse {
// push tos2 to st.data
st.data = append(st.data, st.Tos1)
st.Tos1 = st.Tos2
st.Tos2 = *d
} else {
// push to tos2
st.Tos2 = *d
st.Tos2InUse = true
}
}
// NOTE push limit (1024) is checked in baseCheck
st.data = append(st.data, *d)
// st.data = append(st.data, *d)
}

// pop the top most elem in stack or cache
func (st *Stack) pop() (ret uint256.Int) {
ret = st.data[len(st.data)-1]
st.data = st.data[:len(st.data)-1]
if st.Tos2InUse {
ret = st.Tos2
st.Tos2InUse = false
} else {
// check tos1
if st.Tos1InUse {
ret = st.Tos1
st.Tos1InUse = false
} else if len(st.data) > 0 {
ret = st.data[len(st.data)-1]
st.data = st.data[:len(st.data)-1]
}
}
return
}

func (st *Stack) len() int {
return len(st.data)
func (st *Stack) Len() int {
length := len(st.data)
if st.Tos1InUse {
length++
}
if st.Tos2InUse {
length++
}
return length
}

func (st *Stack) swap(n int) {
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n]
// n is >=2
// it is not possible that tos1 in use and tos2 not in use when n >=2
if st.Tos2InUse {
// todo-dav: debug only, delete me
if !st.Tos1InUse {
fmt.Errorf("FATAL: stack underflow! swap: %v\n", n)
panic(n)
}
// if n == 2, swap tos1 and tos2
if n == 2 {
st.Tos2, st.Tos1 = st.Tos1, st.Tos2
return
} else {
// n > 2, swap tos2 and st.data.
st.Tos2, st.data[len(st.data)-n+2] = st.data[len(st.data)-n+2], st.Tos2
}
} else if st.Tos1InUse {
// tos2 not in use. tos1 is the top most. swap with st.data
st.Tos1, st.data[len(st.data)-n+1] = st.data[len(st.data)-n+1], st.Tos1
} else {
// st.data[st.Len()-1] is the top of stack
st.data[len(st.data)-n], st.data[len(st.data)-1] = st.data[len(st.data)-1], st.data[len(st.data)-n]
}
// st.data[st.Len()-n], st.data[st.Len()-1] = st.data[st.Len()-1], st.data[st.Len()-n]
}

func (st *Stack) dup(n int) {
st.push(&st.data[st.len()-n])
if !st.Tos2InUse {
if !st.Tos1InUse {
// tos is st.data
st.Tos1 = st.data[len(st.data)-n]
st.Tos1InUse = true
} else {
// tos is Tos1
if n == 1 {
st.Tos2 = st.Tos1
st.Tos2InUse = true
} else {
st.Tos2 = st.data[len(st.data)-n+1]
st.Tos2InUse = true
}
}
} else {
// tos is Tos2
if !st.Tos1InUse {
// this is not possible
fmt.Printf("FATAL: stack underflow!! dup %v\n", n)
panic(st.Len())
} else {
// all tos in use, need push to st.data
var tmp uint256.Int
if n == 1 {
tmp = st.Tos2
} else if n == 2 {
tmp = st.Tos1
} else {
tmp = st.data[len(st.data)-n+2]
}
// push Tos2.
st.data = append(st.data, st.Tos1)
st.Tos1 = st.Tos2
st.Tos2 = tmp
}
}
}

func (st *Stack) peek() *uint256.Int {
return &st.data[st.len()-1]
if st.Tos2InUse {
return &st.Tos2
}
if st.Tos1InUse {
return &st.Tos1
}
return &st.data[len(st.data)-1]
}

// Back returns the n'th item in stack
func (st *Stack) Back(n int) *uint256.Int {
return &st.data[st.len()-n-1]
if st.Tos2InUse {
if n == 0 {
return &st.Tos2
}
if n == 1 {
return &st.Tos1
}
return &st.data[len(st.data)-n+1]
} else {
if st.Tos1InUse {
if n == 0 {
return &st.Tos1
}
return &st.data[len(st.data)-n]
}
}
return &st.data[len(st.data)-n-1]
}
6 changes: 3 additions & 3 deletions eth/tracers/js/goja.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,14 +638,14 @@ func (s *stackObj) Peek(idx int) goja.Value {

// peek returns the nth-from-the-top element of the stack.
func (s *stackObj) peek(idx int) (*big.Int, error) {
if len(s.stack.Data()) <= idx || idx < 0 {
return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx)
if s.stack.Len() <= idx || idx < 0 {
return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", s.stack.Len(), idx)
}
return s.stack.Back(idx).ToBig(), nil
}

func (s *stackObj) Length() int {
return len(s.stack.Data())
return s.stack.Len()
}

func (s *stackObj) setupObject() *goja.Object {
Expand Down
10 changes: 5 additions & 5 deletions eth/tracers/logger/access_list_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,20 @@ func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to com
// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist.
func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
stack := scope.Stack
stackData := stack.Data()
stackLen := len(stackData)
// stackData := stack.Data()
stackLen := stack.Len()
if (op == vm.SLOAD || op == vm.SSTORE) && stackLen >= 1 {
slot := common.Hash(stackData[stackLen-1].Bytes32())
slot := common.Hash(stack.Back(0).Bytes32())
a.list.addSlot(scope.Contract.Address(), slot)
}
if (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT) && stackLen >= 1 {
addr := common.Address(stackData[stackLen-1].Bytes20())
addr := common.Address(stack.Back(0).Bytes20())
if _, ok := a.excl[addr]; !ok {
a.list.addAddress(addr)
}
}
if (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE) && stackLen >= 5 {
addr := common.Address(stackData[stackLen-2].Bytes20())
addr := common.Address(stack.Back(1).Bytes20())
if _, ok := a.excl[addr]; !ok {
a.list.addAddress(addr)
}
Expand Down
Loading

0 comments on commit 94f150c

Please sign in to comment.