github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/core/vm/instructions.go (about) 1 // Copyright 2015 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 "math/big" 21 22 "github.com/ethereumproject/go-ethereum/common" 23 "github.com/ethereumproject/go-ethereum/crypto" 24 ) 25 26 var callStipend = big.NewInt(2300) // Free gas given at beginning of call. 27 28 type instrFn func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) 29 30 type instruction struct { 31 op OpCode 32 pc uint64 33 fn instrFn 34 data *big.Int 35 36 gas *big.Int 37 spop int 38 spush int 39 40 returns bool 41 } 42 43 func (instr instruction) halts() bool { 44 return instr.returns 45 } 46 47 func (instr instruction) Op() OpCode { 48 return instr.op 49 } 50 51 func opAdd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 52 x, y := stack.pop(), stack.pop() 53 stack.push(U256(x.Add(x, y))) 54 } 55 56 func opSub(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 57 x, y := stack.pop(), stack.pop() 58 stack.push(U256(x.Sub(x, y))) 59 } 60 61 func opMul(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 62 x, y := stack.pop(), stack.pop() 63 stack.push(U256(x.Mul(x, y))) 64 } 65 66 func opDiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 67 x, y := stack.pop(), stack.pop() 68 if y.Sign() != 0 { 69 stack.push(U256(x.Div(x, y))) 70 } else { 71 stack.push(new(big.Int)) 72 } 73 } 74 75 func opSdiv(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 76 x, y := S256(stack.pop()), S256(stack.pop()) 77 if y.Sign() == 0 { 78 stack.push(new(big.Int)) 79 return 80 } else { 81 n := new(big.Int) 82 if new(big.Int).Mul(x, y).Sign() < 0 { 83 n.SetInt64(-1) 84 } else { 85 n.SetInt64(1) 86 } 87 88 res := x.Div(x.Abs(x), y.Abs(y)) 89 res.Mul(res, n) 90 91 stack.push(U256(res)) 92 } 93 } 94 95 func opMod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 96 x, y := stack.pop(), stack.pop() 97 if y.Sign() == 0 { 98 stack.push(new(big.Int)) 99 } else { 100 stack.push(U256(x.Mod(x, y))) 101 } 102 } 103 104 func opSmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 105 x, y := S256(stack.pop()), S256(stack.pop()) 106 107 if y.Sign() == 0 { 108 stack.push(new(big.Int)) 109 } else { 110 n := new(big.Int) 111 if x.Sign() < 0 { 112 n.SetInt64(-1) 113 } else { 114 n.SetInt64(1) 115 } 116 117 res := x.Mod(x.Abs(x), y.Abs(y)) 118 res.Mul(res, n) 119 120 stack.push(U256(res)) 121 } 122 } 123 124 func opExp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 125 x, y := stack.pop(), stack.pop() 126 stack.push(U256(x.Exp(x, y, Pow256))) 127 } 128 129 func opSignExtend(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 130 back := stack.pop() 131 if back.Cmp(big.NewInt(31)) < 0 { 132 bit := uint(back.Uint64()*8 + 7) 133 num := stack.pop() 134 mask := back.Lsh(common.Big1, bit) 135 mask.Sub(mask, common.Big1) 136 if common.BitTest(num, int(bit)) { 137 num.Or(num, mask.Not(mask)) 138 } else { 139 num.And(num, mask) 140 } 141 142 stack.push(U256(num)) 143 } 144 } 145 146 func opNot(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 147 x := stack.pop() 148 stack.push(U256(x.Not(x))) 149 } 150 151 func opLt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 152 x, y := stack.pop(), stack.pop() 153 if x.Cmp(y) < 0 { 154 stack.push(big.NewInt(1)) 155 } else { 156 stack.push(new(big.Int)) 157 } 158 } 159 160 func opGt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 161 x, y := stack.pop(), stack.pop() 162 if x.Cmp(y) > 0 { 163 stack.push(big.NewInt(1)) 164 } else { 165 stack.push(new(big.Int)) 166 } 167 } 168 169 func opSlt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 170 x, y := S256(stack.pop()), S256(stack.pop()) 171 if x.Cmp(S256(y)) < 0 { 172 stack.push(big.NewInt(1)) 173 } else { 174 stack.push(new(big.Int)) 175 } 176 } 177 178 func opSgt(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 179 x, y := S256(stack.pop()), S256(stack.pop()) 180 if x.Cmp(y) > 0 { 181 stack.push(big.NewInt(1)) 182 } else { 183 stack.push(new(big.Int)) 184 } 185 } 186 187 func opEq(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 188 x, y := stack.pop(), stack.pop() 189 if x.Cmp(y) == 0 { 190 stack.push(big.NewInt(1)) 191 } else { 192 stack.push(new(big.Int)) 193 } 194 } 195 196 func opIszero(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 197 x := stack.pop() 198 if x.Sign() != 0 { 199 stack.push(new(big.Int)) 200 } else { 201 stack.push(big.NewInt(1)) 202 } 203 } 204 205 func opAnd(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 206 x, y := stack.pop(), stack.pop() 207 stack.push(x.And(x, y)) 208 } 209 func opOr(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 210 x, y := stack.pop(), stack.pop() 211 stack.push(x.Or(x, y)) 212 } 213 func opXor(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 214 x, y := stack.pop(), stack.pop() 215 stack.push(x.Xor(x, y)) 216 } 217 func opByte(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 218 th, val := stack.pop(), stack.pop() 219 if th.Cmp(big.NewInt(32)) < 0 { 220 byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) 221 stack.push(byte) 222 } else { 223 stack.push(new(big.Int)) 224 } 225 } 226 func opAddmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 227 x, y, z := stack.pop(), stack.pop(), stack.pop() 228 if z.Sign() > 0 { 229 add := x.Add(x, y) 230 add.Mod(add, z) 231 stack.push(U256(add)) 232 } else { 233 stack.push(new(big.Int)) 234 } 235 } 236 func opMulmod(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 237 x, y, z := stack.pop(), stack.pop(), stack.pop() 238 if z.Sign() > 0 { 239 mul := x.Mul(x, y) 240 mul.Mod(mul, z) 241 stack.push(U256(mul)) 242 } else { 243 stack.push(new(big.Int)) 244 } 245 } 246 247 func opSha3(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 248 offset, size := stack.pop(), stack.pop() 249 hash := crypto.Keccak256(memory.Get(offset.Int64(), size.Int64())) 250 251 stack.push(new(big.Int).SetBytes(hash)) 252 } 253 254 func opAddress(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 255 stack.push(new(big.Int).SetBytes(contract.Address().Bytes())) 256 } 257 258 func opBalance(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 259 addr := common.BigToAddress(stack.pop()) 260 balance := env.Db().GetBalance(addr) 261 262 stack.push(new(big.Int).Set(balance)) 263 } 264 265 func opOrigin(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 266 stack.push(env.Origin().Big()) 267 } 268 269 func opCaller(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 270 stack.push(contract.Caller().Big()) 271 } 272 273 func opCallValue(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 274 stack.push(new(big.Int).Set(contract.value)) 275 } 276 277 func opCalldataLoad(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 278 stack.push(new(big.Int).SetBytes(getData(contract.Input, stack.pop(), common.Big32))) 279 } 280 281 func opCalldataSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 282 stack.push(big.NewInt(int64(len(contract.Input)))) 283 } 284 285 func opCalldataCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 286 var ( 287 mOff = stack.pop() 288 cOff = stack.pop() 289 l = stack.pop() 290 ) 291 memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l)) 292 } 293 294 func opExtCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 295 addr := common.BigToAddress(stack.pop()) 296 l := big.NewInt(int64(env.Db().GetCodeSize(addr))) 297 stack.push(l) 298 } 299 300 func opCodeSize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 301 l := big.NewInt(int64(len(contract.Code))) 302 stack.push(l) 303 } 304 305 func opCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 306 var ( 307 mOff = stack.pop() 308 cOff = stack.pop() 309 l = stack.pop() 310 ) 311 codeCopy := getData(contract.Code, cOff, l) 312 313 memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) 314 } 315 316 func opExtCodeCopy(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 317 var ( 318 addr = common.BigToAddress(stack.pop()) 319 mOff = stack.pop() 320 cOff = stack.pop() 321 l = stack.pop() 322 ) 323 codeCopy := getData(env.Db().GetCode(addr), cOff, l) 324 325 memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) 326 } 327 328 func opGasprice(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 329 stack.push(new(big.Int).Set(contract.Price)) 330 } 331 332 func opBlockhash(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 333 num := stack.pop() 334 335 n := new(big.Int).Sub(env.BlockNumber(), common.Big257) 336 if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber()) < 0 { 337 stack.push(env.GetHash(num.Uint64()).Big()) 338 } else { 339 stack.push(new(big.Int)) 340 } 341 } 342 343 func opCoinbase(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 344 stack.push(env.Coinbase().Big()) 345 } 346 347 func opTimestamp(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 348 stack.push(U256(new(big.Int).Set(env.Time()))) 349 } 350 351 func opNumber(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 352 stack.push(U256(new(big.Int).Set(env.BlockNumber()))) 353 } 354 355 func opDifficulty(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 356 stack.push(U256(new(big.Int).Set(env.Difficulty()))) 357 } 358 359 func opGasLimit(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 360 stack.push(U256(new(big.Int).Set(env.GasLimit()))) 361 } 362 363 func opPop(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 364 stack.pop() 365 } 366 367 func opMload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 368 offset := stack.pop() 369 val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32)) 370 stack.push(val) 371 } 372 373 func opMstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 374 // pop value of the stack 375 mStart, val := stack.pop(), stack.pop() 376 memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256)) 377 } 378 379 func opMstore8(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 380 off, val := stack.pop().Int64(), stack.pop().Int64() 381 memory.store[off] = byte(val & 0xff) 382 } 383 384 func opSload(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 385 loc := common.BigToHash(stack.pop()) 386 val := env.Db().GetState(contract.Address(), loc).Big() 387 stack.push(val) 388 } 389 390 func opSstore(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 391 loc := common.BigToHash(stack.pop()) 392 val := stack.pop() 393 env.Db().SetState(contract.Address(), loc, common.BigToHash(val)) 394 } 395 396 func opJumpdest(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 397 } 398 399 func opPc(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 400 stack.push(new(big.Int).Set(instr.data)) 401 } 402 403 func opMsize(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 404 stack.push(big.NewInt(int64(memory.Len()))) 405 } 406 407 func opGas(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 408 stack.push(new(big.Int).Set(contract.Gas)) 409 } 410 411 func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 412 var ( 413 value = stack.pop() 414 offset, size = stack.pop(), stack.pop() 415 input = memory.Get(offset.Int64(), size.Int64()) 416 gas = new(big.Int).Set(contract.Gas) 417 ) 418 if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil { 419 gas.Div(gas, n64) 420 gas = gas.Sub(contract.Gas, gas) 421 } 422 423 contract.UseGas(gas) 424 _, addr, suberr := env.Create(contract, input, gas, contract.Price, value) 425 // Push item on the stack based on the returned error. If the ruleset is 426 // homestead we must check for CodeStoreOutOfGasError (homestead only 427 // rule) and treat as an error, if the ruleset is frontier we must 428 // ignore this error and pretend the operation was successful. 429 if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError { 430 stack.push(new(big.Int)) 431 } else if suberr != nil && suberr != CodeStoreOutOfGasError { 432 stack.push(new(big.Int)) 433 } else { 434 stack.push(addr.Big()) 435 } 436 } 437 438 func opCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 439 gas := stack.pop() 440 // pop gas and value of the stack. 441 addr, value := stack.pop(), stack.pop() 442 value = U256(value) 443 // pop input size and offset 444 inOffset, inSize := stack.pop(), stack.pop() 445 // pop return size and offset 446 retOffset, retSize := stack.pop(), stack.pop() 447 448 address := common.BigToAddress(addr) 449 450 // Get the arguments from the memory 451 args := memory.Get(inOffset.Int64(), inSize.Int64()) 452 453 if len(value.Bytes()) > 0 { 454 gas.Add(gas, callStipend) 455 } 456 457 ret, err := env.Call(contract, address, args, gas, contract.Price, value) 458 459 if err != nil { 460 stack.push(new(big.Int)) 461 462 } else { 463 stack.push(big.NewInt(1)) 464 465 memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) 466 } 467 } 468 469 func opCallCode(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 470 gas := stack.pop() 471 // pop gas and value of the stack. 472 addr, value := stack.pop(), stack.pop() 473 value = U256(value) 474 // pop input size and offset 475 inOffset, inSize := stack.pop(), stack.pop() 476 // pop return size and offset 477 retOffset, retSize := stack.pop(), stack.pop() 478 479 address := common.BigToAddress(addr) 480 481 // Get the arguments from the memory 482 args := memory.Get(inOffset.Int64(), inSize.Int64()) 483 484 if len(value.Bytes()) > 0 { 485 gas.Add(gas, callStipend) 486 } 487 488 ret, err := env.CallCode(contract, address, args, gas, contract.Price, value) 489 490 if err != nil { 491 stack.push(new(big.Int)) 492 493 } else { 494 stack.push(big.NewInt(1)) 495 496 memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) 497 } 498 } 499 500 func opDelegateCall(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 501 gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() 502 503 toAddr := common.BigToAddress(to) 504 args := memory.Get(inOffset.Int64(), inSize.Int64()) 505 ret, err := env.DelegateCall(contract, toAddr, args, gas, contract.Price) 506 if err != nil { 507 stack.push(new(big.Int)) 508 } else { 509 stack.push(big.NewInt(1)) 510 memory.Set(outOffset.Uint64(), outSize.Uint64(), ret) 511 } 512 } 513 514 func opSuicide(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 515 balance := env.Db().GetBalance(contract.Address()) 516 env.Db().AddBalance(common.BigToAddress(stack.pop()), balance) 517 518 env.Db().Suicide(contract.Address()) 519 } 520 521 // following functions are used by the instruction jump table 522 523 // make log instruction function 524 func makeLog(size int) instrFn { 525 return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 526 topics := make([]common.Hash, size) 527 mStart, mSize := stack.pop(), stack.pop() 528 for i := 0; i < size; i++ { 529 topics[i] = common.BigToHash(stack.pop()) 530 } 531 532 d := memory.Get(mStart.Int64(), mSize.Int64()) 533 log := NewLog(contract.Address(), topics, d, env.BlockNumber().Uint64()) 534 env.AddLog(log) 535 } 536 } 537 538 // make push instruction function 539 func makePush(size uint64, bsize *big.Int) instrFn { 540 return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 541 bytes := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize) 542 stack.push(new(big.Int).SetBytes(bytes)) 543 *pc += size 544 } 545 } 546 547 // make push instruction function 548 func makeDup(size int64) instrFn { 549 return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 550 stack.dup(int(size)) 551 } 552 } 553 554 // make swap instruction function 555 func makeSwap(size int64) instrFn { 556 // switch n + 1 otherwise n would be swapped with n 557 size += 1 558 return func(instr instruction, pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) { 559 stack.swap(int(size)) 560 } 561 }