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