takenobu-hs/ethereum-evm-illustrated

Illustration of "Stack" elements not accurate

bitrocks opened this issue · 6 comments

I read your work, it's really great illustration of the EVM.

However, it's the call depth limited to 1024 other than the stack size. https://github.com/ethereum/wiki/wiki/Design-Rationale#virtual-machine.

So slide 49,50 are not accurate.

Thank you, I was confused about that too.

However, with yellow paper's specification and geth's implementation, the size of the data stack is also limited to 1024.

Perhaps the description of Design-Rationale#virtual-machine ('Not having a stack size limit') seems to be not accurate.

The yellowpaper and geth code are as follows:


yellowpaper : https://ethereum.github.io/yellowpaper/paper.pdf

9.1 Basic
The stack has a maximum size of 1024.
9.4.2. Exceptional Halting.
(136)
‖μs‖ - δw + αw > 1024

Geth implementation:

https://github.com/ethereum/go-ethereum/blob/master/core/vm/stack.go#L32

func newstack() *Stack {
	return &Stack{data: make([]*big.Int, 0, 1024)}
}

https://github.com/ethereum/go-ethereum/blob/master/core/vm/stack.go#L40

func (st *Stack) push(d *big.Int) {
        // NOTE push limit (1024) is checked in baseCheck
        //stackItem := new(big.Int).Set(d)
        //st.data = append(st.data, stackItem)
        st.data = append(st.data, d)
}

Cheers

Inspired by you, I checked the git history of the file

https://github.com/ethereum/go-ethereum/blob/master/core/vm/stack.go

it surprises me that the 1024 limit is recently updated:

Besides, the append function can auto extend if the capacity is insufficient:

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
//	slice = append(slice, elem1, elem2)
//	slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
//	slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type

It seems still unsettled.

It is interesting. I also explored a little.
GO lang's append is extended automatically, but EVM of Geth checks the stack size as follows:

https://github.com/ethereum/go-ethereum/blob/master/params/protocol_params.go#L56

	StackLimit uint64 = 1024 // Maximum size of VM stack allowed.

https://github.com/ethereum/go-ethereum/blob/master/core/vm/stack_table.go#L31

func makeStackFunc(pop, push int) stackValidationFunc {
	return func(stack *Stack) error {
		if err := stack.require(pop); err != nil {
			return err
		}

		if stack.len()+push-pop > int(params.StackLimit) {
			return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit)
		}
		return nil
	}
}

I tried to find the so-called "baseCheck" part but failed. The evidence convinces me now. It's the design rationale outdated. The git history of the stack_table.go still shows the dev-team didn't add the limitation until 2017-1-5. But that's another story.

Thanks a lot :-)

hupengbuaa, thanks. I submitted issue to ethereum/wiki.

ethereum/wiki#559

Closed this.

see ethereum/wiki#559