github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/vm/vm.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vm 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 "time" 24 25 "github.com/ethereumproject/go-ethereum/common" 26 "github.com/ethereumproject/go-ethereum/crypto" 27 "github.com/ethereumproject/go-ethereum/logger" 28 "github.com/ethereumproject/go-ethereum/logger/glog" 29 ) 30 31 var ( 32 OutOfGasError = errors.New("Out of gas") 33 CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas") 34 ) 35 36 // VirtualMachine is an EVM interface 37 type VirtualMachine interface { 38 Run(*Contract, []byte) ([]byte, error) 39 } 40 41 // EVM is used to run Ethereum based contracts and will utilise the 42 // passed environment to query external sources for state information. 43 // The EVM will run the byte code VM or JIT VM based on the passed 44 // configuration. 45 type EVM struct { 46 env Environment 47 jumpTable vmJumpTable 48 gasTable GasTable 49 } 50 51 // New returns a new instance of the EVM. 52 func New(env Environment) *EVM { 53 return &EVM{ 54 env: env, 55 jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()), 56 gasTable: *env.RuleSet().GasTable(env.BlockNumber()), 57 } 58 } 59 60 // Run loops and evaluates the contract's code with the given input data 61 func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { 62 evm.env.SetDepth(evm.env.Depth() + 1) 63 defer evm.env.SetDepth(evm.env.Depth() - 1) 64 65 if contract.CodeAddr != nil { 66 if p := Precompiled[contract.CodeAddr.Str()]; p != nil { 67 return evm.RunPrecompiled(p, input, contract) 68 } 69 } 70 71 // Don't bother with the execution if there's no code. 72 if len(contract.Code) == 0 { 73 return nil, nil 74 } 75 76 codehash := contract.CodeHash // codehash is used when doing jump dest caching 77 if codehash == (common.Hash{}) { 78 codehash = crypto.Keccak256Hash(contract.Code) 79 } 80 81 var ( 82 caller = contract.caller 83 code = contract.Code 84 instrCount = 0 85 86 op OpCode // current opcode 87 mem = NewMemory() // bound memory 88 stack = newstack() // local stack 89 statedb = evm.env.Db() // current state 90 // For optimisation reason we're using uint64 as the program counter. 91 // It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible. 92 pc = uint64(0) // program counter 93 94 // jump evaluates and checks whether the given jump destination is a valid one 95 // if valid move the `pc` otherwise return an error. 96 jump = func(from uint64, to *big.Int) error { 97 if !contract.jumpdests.has(codehash, code, to) { 98 nop := contract.GetOp(to.Uint64()) 99 return fmt.Errorf("invalid jump destination (%v) %v", nop, to) 100 } 101 102 pc = to.Uint64() 103 104 return nil 105 } 106 107 newMemSize *big.Int 108 cost *big.Int 109 ) 110 contract.Input = input 111 112 if glog.V(logger.Debug) { 113 glog.Infof("running byte VM %x\n", codehash[:4]) 114 tstart := time.Now() 115 defer func() { 116 glog.Infof("byte VM %x done. time: %v instrc: %v\n", codehash[:4], time.Since(tstart), instrCount) 117 }() 118 } 119 120 for ; ; instrCount++ { 121 // Get the memory location of pc 122 op = contract.GetOp(pc) 123 // calculate the new memory size and gas price for the current executing opcode 124 newMemSize, cost, err = calculateGasAndSize(&evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack) 125 if err != nil { 126 return nil, err 127 } 128 129 // Use the calculated gas. When insufficient gas is present, use all gas and return an 130 // Out Of Gas error 131 if !contract.UseGas(cost) { 132 return nil, OutOfGasError 133 } 134 135 // Resize the memory calculated previously 136 mem.Resize(newMemSize.Uint64()) 137 138 if opPtr := evm.jumpTable[op]; opPtr.valid { 139 if opPtr.fn != nil { 140 opPtr.fn(instruction{}, &pc, evm.env, contract, mem, stack) 141 } else { 142 switch op { 143 case PC: 144 opPc(instruction{data: new(big.Int).SetUint64(pc)}, &pc, evm.env, contract, mem, stack) 145 case JUMP: 146 if err := jump(pc, stack.pop()); err != nil { 147 return nil, err 148 } 149 150 continue 151 case JUMPI: 152 pos, cond := stack.pop(), stack.pop() 153 154 if cond.Sign() != 0 { 155 if err := jump(pc, pos); err != nil { 156 return nil, err 157 } 158 159 continue 160 } 161 case RETURN: 162 offset, size := stack.pop(), stack.pop() 163 ret := mem.GetPtr(offset.Int64(), size.Int64()) 164 165 return ret, nil 166 case SUICIDE: 167 opSuicide(instruction{}, nil, evm.env, contract, mem, stack) 168 169 fallthrough 170 case STOP: // Stop the contract 171 return nil, nil 172 } 173 } 174 } else { 175 return nil, fmt.Errorf("Invalid opcode %x", op) 176 } 177 178 pc++ 179 180 } 181 } 182 183 // calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for 184 // the operation. This does not reduce gas or resizes the memory. 185 func calculateGasAndSize(gasTable *GasTable, env Environment, contract *Contract, caller ContractRef, op OpCode, statedb Database, mem *Memory, stack *stack) (*big.Int, *big.Int, error) { 186 var ( 187 gas = new(big.Int) 188 newMemSize *big.Int = new(big.Int) 189 ) 190 err := baseCheck(op, stack, gas) 191 if err != nil { 192 return nil, nil, err 193 } 194 195 // stack Check, memory resize & gas phase 196 switch op { 197 case SUICIDE: 198 // if suicide is not nil: homestead gas fork 199 if gasTable.CreateBySuicide != nil { 200 gas.Set(gasTable.Suicide) 201 if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) { 202 gas.Add(gas, gasTable.CreateBySuicide) 203 } 204 } 205 206 if !statedb.HasSuicided(contract.Address()) { 207 statedb.AddRefund(big.NewInt(24000)) 208 } 209 case EXTCODESIZE: 210 gas.Set(gasTable.ExtcodeSize) 211 case BALANCE: 212 gas.Set(gasTable.Balance) 213 case SLOAD: 214 gas.Set(gasTable.SLoad) 215 case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: 216 n := int(op - SWAP1 + 2) 217 err := stack.require(n) 218 if err != nil { 219 return nil, nil, err 220 } 221 gas.Set(GasFastestStep) 222 case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: 223 n := int(op - DUP1 + 1) 224 err := stack.require(n) 225 if err != nil { 226 return nil, nil, err 227 } 228 gas.Set(GasFastestStep) 229 case LOG0, LOG1, LOG2, LOG3, LOG4: 230 n := int(op - LOG0) 231 err := stack.require(n + 2) 232 if err != nil { 233 return nil, nil, err 234 } 235 236 mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1] 237 238 // log gas 239 gas.Add(gas, big.NewInt(375)) 240 // log topic gass 241 gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), big.NewInt(375))) 242 // log data gass 243 gas.Add(gas, new(big.Int).Mul(mSize, big.NewInt(8))) 244 245 newMemSize = calcMemSize(mStart, mSize) 246 247 quadMemGas(mem, newMemSize, gas) 248 case EXP: 249 expByteLen := int64(len(stack.data[stack.len()-2].Bytes())) 250 gas.Add(gas, new(big.Int).Mul(big.NewInt(expByteLen), gasTable.ExpByte)) 251 case SSTORE: 252 err := stack.require(2) 253 if err != nil { 254 return nil, nil, err 255 } 256 257 var g *big.Int 258 y, x := stack.data[stack.len()-2], stack.data[stack.len()-1] 259 val := statedb.GetState(contract.Address(), common.BigToHash(x)) 260 261 // This checks for 3 scenario's and calculates gas accordingly 262 // 1. From a zero-value address to a non-zero value (NEW VALUE) 263 // 2. From a non-zero value address to a zero-value address (DELETE) 264 // 3. From a non-zero to a non-zero (CHANGE) 265 if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { 266 // 0 => non 0 267 g = big.NewInt(20000) // Once per SLOAD operation. 268 } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { 269 statedb.AddRefund(big.NewInt(15000)) 270 g = big.NewInt(5000) 271 } else { 272 // non 0 => non 0 (or 0 => 0) 273 g = big.NewInt(5000) 274 } 275 gas.Set(g) 276 277 case MLOAD: 278 newMemSize = calcMemSize(stack.peek(), u256(32)) 279 quadMemGas(mem, newMemSize, gas) 280 case MSTORE8: 281 newMemSize = calcMemSize(stack.peek(), u256(1)) 282 quadMemGas(mem, newMemSize, gas) 283 case MSTORE: 284 newMemSize = calcMemSize(stack.peek(), u256(32)) 285 quadMemGas(mem, newMemSize, gas) 286 case RETURN: 287 newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) 288 quadMemGas(mem, newMemSize, gas) 289 case SHA3: 290 newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2]) 291 292 words := toWordSize(stack.data[stack.len()-2]) 293 gas.Add(gas, words.Mul(words, big.NewInt(6))) 294 295 quadMemGas(mem, newMemSize, gas) 296 case CALLDATACOPY: 297 newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) 298 299 words := toWordSize(stack.data[stack.len()-3]) 300 gas.Add(gas, words.Mul(words, big.NewInt(3))) 301 302 quadMemGas(mem, newMemSize, gas) 303 case CODECOPY: 304 newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3]) 305 306 words := toWordSize(stack.data[stack.len()-3]) 307 gas.Add(gas, words.Mul(words, big.NewInt(3))) 308 309 quadMemGas(mem, newMemSize, gas) 310 case EXTCODECOPY: 311 gas.Set(gasTable.ExtcodeCopy) 312 313 newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4]) 314 315 words := toWordSize(stack.data[stack.len()-4]) 316 gas.Add(gas, words.Mul(words, big.NewInt(3))) 317 318 quadMemGas(mem, newMemSize, gas) 319 case CREATE: 320 newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3]) 321 322 quadMemGas(mem, newMemSize, gas) 323 case CALL, CALLCODE: 324 gas.Set(gasTable.Calls) 325 326 if op == CALL { 327 if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) { 328 gas.Add(gas, big.NewInt(25000)) 329 } 330 } 331 if len(stack.data[stack.len()-3].Bytes()) > 0 { 332 gas.Add(gas, big.NewInt(9000)) 333 } 334 x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7]) 335 y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5]) 336 337 newMemSize = common.BigMax(x, y) 338 339 quadMemGas(mem, newMemSize, gas) 340 341 cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1]) 342 // Replace the stack item with the new gas calculation. This means that 343 // either the original item is left on the stack or the item is replaced by: 344 // (availableGas - gas) * 63 / 64 345 // We replace the stack item so that it's available when the opCall instruction is 346 // called. This information is otherwise lost due to the dependency on *current* 347 // available gas. 348 stack.data[stack.len()-1] = cg 349 gas.Add(gas, cg) 350 351 case DELEGATECALL: 352 gas.Set(gasTable.Calls) 353 354 x := calcMemSize(stack.data[stack.len()-5], stack.data[stack.len()-6]) 355 y := calcMemSize(stack.data[stack.len()-3], stack.data[stack.len()-4]) 356 357 newMemSize = common.BigMax(x, y) 358 359 quadMemGas(mem, newMemSize, gas) 360 361 cg := callGas(gasTable, contract.Gas, gas, stack.data[stack.len()-1]) 362 // Replace the stack item with the new gas calculation. This means that 363 // either the original item is left on the stack or the item is replaced by: 364 // (availableGas - gas) * 63 / 64 365 // We replace the stack item so that it's available when the opCall instruction is 366 // called. 367 stack.data[stack.len()-1] = cg 368 gas.Add(gas, cg) 369 370 } 371 372 return newMemSize, gas, nil 373 } 374 375 // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go 376 func (evm *EVM) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Contract) (ret []byte, err error) { 377 gas := p.Gas(len(input)) 378 if contract.UseGas(gas) { 379 ret = p.Call(input) 380 381 return ret, nil 382 } else { 383 return nil, OutOfGasError 384 } 385 }