github.com/datachainlab/burrow@v0.25.0/execution/evm/stack.go (about)

     1  // Copyright 2017 Monax Industries Limited
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package evm
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/hyperledger/burrow/crypto"
    21  
    22  	"math/big"
    23  
    24  	"math"
    25  
    26  	. "github.com/hyperledger/burrow/binary"
    27  	"github.com/hyperledger/burrow/execution/errors"
    28  )
    29  
    30  // Not goroutine safe
    31  type Stack struct {
    32  	slice       []Word256
    33  	maxCapacity uint64
    34  	ptr         int
    35  
    36  	gas     *uint64
    37  	errSink errors.Sink
    38  }
    39  
    40  func NewStack(initialCapacity uint64, maxCapacity uint64, gas *uint64, errSink errors.Sink) *Stack {
    41  	return &Stack{
    42  		slice:       make([]Word256, initialCapacity),
    43  		ptr:         0,
    44  		maxCapacity: maxCapacity,
    45  		gas:         gas,
    46  		errSink:     errSink,
    47  	}
    48  }
    49  
    50  func (st *Stack) useGas(gasToUse uint64) {
    51  	if *st.gas > gasToUse {
    52  		*st.gas -= gasToUse
    53  	} else {
    54  		st.pushErr(errors.ErrorCodeInsufficientGas)
    55  	}
    56  }
    57  
    58  func (st *Stack) pushErr(err errors.CodedError) {
    59  	st.errSink.PushError(err)
    60  }
    61  
    62  func (st *Stack) Push(d Word256) {
    63  	st.useGas(GasStackOp)
    64  	err := st.ensureCapacity(uint64(st.ptr) + 1)
    65  	if err != nil {
    66  		st.pushErr(errors.ErrorCodeDataStackOverflow)
    67  		return
    68  	}
    69  	st.slice[st.ptr] = d
    70  	st.ptr++
    71  }
    72  
    73  // currently only called after sha3.Sha3
    74  func (st *Stack) PushBytes(bz []byte) {
    75  	if len(bz) != 32 {
    76  		panic("Invalid bytes size: expected 32")
    77  	}
    78  	st.Push(LeftPadWord256(bz))
    79  }
    80  
    81  func (st *Stack) PushAddress(address crypto.Address) {
    82  	st.Push(address.Word256())
    83  }
    84  
    85  func (st *Stack) Push64(i int64) {
    86  	st.Push(Int64ToWord256(i))
    87  }
    88  
    89  func (st *Stack) PushU64(i uint64) {
    90  	st.Push(Uint64ToWord256(i))
    91  }
    92  
    93  // Pushes the bigInt as a Word256 encoding negative values in 32-byte twos complement and returns the encoded result
    94  func (st *Stack) PushBigInt(bigInt *big.Int) Word256 {
    95  	word := LeftPadWord256(U256(bigInt).Bytes())
    96  	st.Push(word)
    97  	return word
    98  }
    99  
   100  // Pops
   101  
   102  func (st *Stack) Pop() Word256 {
   103  	st.useGas(GasStackOp)
   104  	if st.ptr == 0 {
   105  		st.pushErr(errors.ErrorCodeDataStackUnderflow)
   106  		return Zero256
   107  	}
   108  	st.ptr--
   109  	return st.slice[st.ptr]
   110  }
   111  
   112  func (st *Stack) PopBytes() []byte {
   113  	return st.Pop().Bytes()
   114  }
   115  
   116  func (st *Stack) PopAddress() crypto.Address {
   117  	return crypto.AddressFromWord256(st.Pop())
   118  }
   119  
   120  func (st *Stack) Pop64() int64 {
   121  	d := st.Pop()
   122  	if Is64BitOverflow(d) {
   123  		st.pushErr(errors.ErrorCodef(errors.ErrorCodeCallStackOverflow, "int64 overflow from word: %v", d))
   124  		return 0
   125  	}
   126  	return Int64FromWord256(d)
   127  }
   128  
   129  func (st *Stack) PopU64() uint64 {
   130  	d := st.Pop()
   131  	if Is64BitOverflow(d) {
   132  		st.pushErr(errors.ErrorCodef(errors.ErrorCodeCallStackOverflow, "int64 overflow from word: %v", d))
   133  		return 0
   134  	}
   135  	return Uint64FromWord256(d)
   136  }
   137  
   138  func (st *Stack) PopBigIntSigned() *big.Int {
   139  	return S256(st.PopBigInt())
   140  }
   141  
   142  func (st *Stack) PopBigInt() *big.Int {
   143  	d := st.Pop()
   144  	return new(big.Int).SetBytes(d[:])
   145  }
   146  
   147  func (st *Stack) Len() int {
   148  	return st.ptr
   149  }
   150  
   151  func (st *Stack) Swap(n int) {
   152  	st.useGas(GasStackOp)
   153  	if st.ptr < n {
   154  		st.pushErr(errors.ErrorCodeDataStackUnderflow)
   155  		return
   156  	}
   157  	st.slice[st.ptr-n], st.slice[st.ptr-1] = st.slice[st.ptr-1], st.slice[st.ptr-n]
   158  }
   159  
   160  func (st *Stack) Dup(n int) {
   161  	st.useGas(GasStackOp)
   162  	if st.ptr < n {
   163  		st.pushErr(errors.ErrorCodeDataStackUnderflow)
   164  		return
   165  	}
   166  	st.Push(st.slice[st.ptr-n])
   167  }
   168  
   169  // Not an opcode, costs no gas.
   170  func (st *Stack) Peek() Word256 {
   171  	if st.ptr == 0 {
   172  		st.pushErr(errors.ErrorCodeDataStackUnderflow)
   173  		return Zero256
   174  	}
   175  	return st.slice[st.ptr-1]
   176  }
   177  
   178  func (st *Stack) Print(n int) {
   179  	fmt.Println("### stack ###")
   180  	if st.ptr > 0 {
   181  		nn := n
   182  		if st.ptr < n {
   183  			nn = st.ptr
   184  		}
   185  		for j, i := 0, st.ptr-1; i > st.ptr-1-nn; i-- {
   186  			fmt.Printf("%-3d  %X\n", j, st.slice[i])
   187  			j += 1
   188  		}
   189  	} else {
   190  		fmt.Println("-- empty --")
   191  	}
   192  	fmt.Println("#############")
   193  }
   194  
   195  func Is64BitOverflow(word Word256) bool {
   196  	for i := 0; i < len(word)-8; i++ {
   197  		if word[i] != 0 {
   198  			return true
   199  		}
   200  	}
   201  	return false
   202  }
   203  
   204  // Ensures the current stack can hold a new element. Will only grow the
   205  // backing array (will not shrink).
   206  func (st *Stack) ensureCapacity(newCapacity uint64) error {
   207  	// Maximum length of a slice that allocates memory is the same as the native int max size
   208  	// We could rethink this limit, but we don't want different validators to disagree on
   209  	// transaction validity so we pick the lowest common denominator
   210  	if newCapacity > math.MaxInt32 {
   211  		// If we ever did want more than an int32 of space then we would need to
   212  		// maintain multiple pages of memory
   213  		return fmt.Errorf("cannot address memory beyond a maximum index "+
   214  			"with int32 width (%v bytes)", math.MaxInt32)
   215  	}
   216  	newCapacityInt := int(newCapacity)
   217  	// We're already big enough so return
   218  	if newCapacityInt <= len(st.slice) {
   219  		return nil
   220  	}
   221  	if st.maxCapacity > 0 && newCapacity > st.maxCapacity {
   222  		return fmt.Errorf("cannot grow memory because it would exceed the "+
   223  			"current maximum limit of %v bytes", st.maxCapacity)
   224  	}
   225  	// Ensure the backing array of slice is big enough
   226  	// Grow the memory one word at time using the pre-allocated zeroWords to avoid
   227  	// unnecessary allocations. Use append to make use of any spare capacity in
   228  	// the slice's backing array.
   229  	for newCapacityInt > cap(st.slice) {
   230  		// We'll trust Go exponentially grow our arrays (at first).
   231  		st.slice = append(st.slice, Zero256)
   232  	}
   233  	// Now we've ensured the backing array of the slice is big enough we can
   234  	// just re-slice (even if len(mem.slice) < newCapacity)
   235  	st.slice = st.slice[:newCapacity]
   236  	return nil
   237  }