| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961 |
- package vm
- import (
- "fmt"
- "math/big"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/state"
- )
- type DebugVm struct {
- env Environment
- logTy byte
- logStr string
- err error
- // Debugging
- Dbg Debugger
- BreakPoints []int64
- Stepping bool
- Fn string
- Recoverable bool
- }
- func NewDebugVm(env Environment) *DebugVm {
- lt := LogTyPretty
- if ethutil.Config.Diff {
- lt = LogTyDiff
- }
- return &DebugVm{env: env, logTy: lt, Recoverable: true}
- }
- func (self *DebugVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
- self.env.SetDepth(self.env.Depth() + 1)
- msg := self.env.State().Manifest().AddMessage(&state.Message{
- To: me.Address(), From: caller.Address(),
- Input: callData,
- Origin: self.env.Origin(),
- Timestamp: self.env.Time(), Coinbase: self.env.Coinbase(), Number: self.env.BlockNumber(),
- Value: value,
- })
- context := NewContext(caller, me, code, gas, price)
- vmlogger.Debugf("(%d) (%x) %x (code=%d) gas: %v (d) %x\n", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData)
- if self.Recoverable {
- // Recover from any require exception
- defer func() {
- if r := recover(); r != nil {
- self.Printf(" %v", r).Endl()
- context.UseGas(context.Gas)
- ret = context.Return(nil)
- err = fmt.Errorf("%v", r)
- }
- }()
- }
- if p := Precompiled[string(me.Address())]; p != nil {
- return self.RunPrecompiled(p, callData, context)
- }
- var (
- op OpCode
- destinations = analyseJumpDests(context.Code)
- mem = NewMemory()
- stack = NewStack()
- pc uint64 = 0
- step = 0
- prevStep = 0
- statedb = self.env.State()
- jump = func(from uint64, to *big.Int) {
- p := to.Uint64()
- nop := context.GetOp(p)
- if !destinations.Has(p) {
- panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p))
- }
- self.Printf(" ~> %v", to)
- pc = to.Uint64()
- self.Endl()
- }
- )
- // Don't bother with the execution if there's no code.
- if len(code) == 0 {
- return context.Return(nil), nil
- }
- for {
- prevStep = step
- // The base for all big integer arithmetic
- base := new(big.Int)
- step++
- // Get the memory location of pc
- op = context.GetOp(pc)
- self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.Len())
- newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
- self.Printf("(g) %-3v (%v)", gas, context.Gas)
- if !context.UseGas(gas) {
- self.Endl()
- tmp := new(big.Int).Set(context.Gas)
- context.UseGas(context.Gas)
- return context.Return(nil), OOG(gas, tmp)
- }
- mem.Resize(newMemSize.Uint64())
- switch op {
- // 0x20 range
- case ADD:
- x, y := stack.Popn()
- self.Printf(" %v + %v", y, x)
- base.Add(y, x)
- U256(base)
- self.Printf(" = %v", base)
- // Pop result back on the stack
- stack.Push(base)
- case SUB:
- x, y := stack.Popn()
- self.Printf(" %v - %v", y, x)
- base.Sub(y, x)
- U256(base)
- self.Printf(" = %v", base)
- // Pop result back on the stack
- stack.Push(base)
- case MUL:
- x, y := stack.Popn()
- self.Printf(" %v * %v", y, x)
- base.Mul(y, x)
- U256(base)
- self.Printf(" = %v", base)
- // Pop result back on the stack
- stack.Push(base)
- case DIV:
- x, y := stack.Pop(), stack.Pop()
- self.Printf(" %v / %v", x, y)
- if y.Cmp(ethutil.Big0) != 0 {
- base.Div(x, y)
- }
- U256(base)
- self.Printf(" = %v", base)
- // Pop result back on the stack
- stack.Push(base)
- case SDIV:
- x, y := S256(stack.Pop()), S256(stack.Pop())
- self.Printf(" %v / %v", x, y)
- if y.Cmp(ethutil.Big0) == 0 {
- base.Set(ethutil.Big0)
- } else {
- n := new(big.Int)
- if new(big.Int).Mul(x, y).Cmp(ethutil.Big0) < 0 {
- n.SetInt64(-1)
- } else {
- n.SetInt64(1)
- }
- base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
- U256(base)
- }
- self.Printf(" = %v", base)
- stack.Push(base)
- case MOD:
- x, y := stack.Pop(), stack.Pop()
- self.Printf(" %v %% %v", x, y)
- if y.Cmp(ethutil.Big0) == 0 {
- base.Set(ethutil.Big0)
- } else {
- base.Mod(x, y)
- }
- U256(base)
- self.Printf(" = %v", base)
- stack.Push(base)
- case SMOD:
- x, y := S256(stack.Pop()), S256(stack.Pop())
- self.Printf(" %v %% %v", x, y)
- if y.Cmp(ethutil.Big0) == 0 {
- base.Set(ethutil.Big0)
- } else {
- n := new(big.Int)
- if x.Cmp(ethutil.Big0) < 0 {
- n.SetInt64(-1)
- } else {
- n.SetInt64(1)
- }
- base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
- U256(base)
- }
- self.Printf(" = %v", base)
- stack.Push(base)
- case EXP:
- x, y := stack.Popn()
- self.Printf(" %v ** %v", y, x)
- base.Exp(y, x, Pow256)
- U256(base)
- self.Printf(" = %v", base)
- stack.Push(base)
- case SIGNEXTEND:
- back := stack.Pop().Uint64()
- if back < 31 {
- bit := uint(back*8 + 7)
- num := stack.Pop()
- mask := new(big.Int).Lsh(ethutil.Big1, bit)
- mask.Sub(mask, ethutil.Big1)
- if ethutil.BitTest(num, int(bit)) {
- num.Or(num, mask.Not(mask))
- } else {
- num.And(num, mask)
- }
- num = U256(num)
- self.Printf(" = %v", num)
- stack.Push(num)
- }
- case NOT:
- base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1)
- // Not needed
- //base = U256(base)
- stack.Push(base)
- case LT:
- x, y := stack.Popn()
- self.Printf(" %v < %v", y, x)
- // x < y
- if y.Cmp(x) < 0 {
- stack.Push(ethutil.BigTrue)
- } else {
- stack.Push(ethutil.BigFalse)
- }
- case GT:
- x, y := stack.Popn()
- self.Printf(" %v > %v", y, x)
- // x > y
- if y.Cmp(x) > 0 {
- stack.Push(ethutil.BigTrue)
- } else {
- stack.Push(ethutil.BigFalse)
- }
- case SLT:
- y, x := S256(stack.Pop()), S256(stack.Pop())
- self.Printf(" %v < %v", y, x)
- // x < y
- if y.Cmp(S256(x)) < 0 {
- stack.Push(ethutil.BigTrue)
- } else {
- stack.Push(ethutil.BigFalse)
- }
- case SGT:
- y, x := S256(stack.Pop()), S256(stack.Pop())
- self.Printf(" %v > %v", y, x)
- // x > y
- if y.Cmp(x) > 0 {
- stack.Push(ethutil.BigTrue)
- } else {
- stack.Push(ethutil.BigFalse)
- }
- case EQ:
- x, y := stack.Popn()
- self.Printf(" %v == %v", y, x)
- // x == y
- if x.Cmp(y) == 0 {
- stack.Push(ethutil.BigTrue)
- } else {
- stack.Push(ethutil.BigFalse)
- }
- case ISZERO:
- x := stack.Pop()
- if x.Cmp(ethutil.BigFalse) > 0 {
- stack.Push(ethutil.BigFalse)
- } else {
- stack.Push(ethutil.BigTrue)
- }
- // 0x10 range
- case AND:
- x, y := stack.Popn()
- self.Printf(" %v & %v", y, x)
- stack.Push(base.And(y, x))
- case OR:
- x, y := stack.Popn()
- self.Printf(" %v | %v", y, x)
- stack.Push(base.Or(y, x))
- case XOR:
- x, y := stack.Popn()
- self.Printf(" %v ^ %v", y, x)
- stack.Push(base.Xor(y, x))
- case BYTE:
- val, th := stack.Popn()
- if th.Cmp(big.NewInt(32)) < 0 {
- byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
- base.Set(byt)
- } else {
- base.Set(ethutil.BigFalse)
- }
- self.Printf(" => 0x%x", base.Bytes())
- stack.Push(base)
- case ADDMOD:
- x := stack.Pop()
- y := stack.Pop()
- z := stack.Pop()
- add := new(big.Int).Add(x, y)
- if len(z.Bytes()) > 0 { // NOT 0x0
- base.Mod(add, z)
- U256(base)
- }
- self.Printf(" %v + %v %% %v = %v", x, y, z, base)
- stack.Push(base)
- case MULMOD:
- x := stack.Pop()
- y := stack.Pop()
- z := stack.Pop()
- mul := new(big.Int).Mul(x, y)
- if len(z.Bytes()) > 0 { // NOT 0x0
- base.Mod(mul, z)
- U256(base)
- }
- self.Printf(" %v + %v %% %v = %v", x, y, z, base)
- stack.Push(base)
- // 0x20 range
- case SHA3:
- size, offset := stack.Popn()
- data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
- stack.Push(ethutil.BigD(data))
- self.Printf(" => %x", data)
- // 0x30 range
- case ADDRESS:
- stack.Push(ethutil.BigD(context.Address()))
- self.Printf(" => %x", context.Address())
- case BALANCE:
- addr := stack.Pop().Bytes()
- balance := statedb.GetBalance(addr)
- stack.Push(balance)
- self.Printf(" => %v (%x)", balance, addr)
- case ORIGIN:
- origin := self.env.Origin()
- stack.Push(ethutil.BigD(origin))
- self.Printf(" => %x", origin)
- case CALLER:
- caller := context.caller.Address()
- stack.Push(ethutil.BigD(caller))
- self.Printf(" => %x", caller)
- case CALLVALUE:
- stack.Push(value)
- self.Printf(" => %v", value)
- case CALLDATALOAD:
- var (
- offset = stack.Pop()
- data = make([]byte, 32)
- lenData = big.NewInt(int64(len(callData)))
- )
- if lenData.Cmp(offset) >= 0 {
- length := new(big.Int).Add(offset, ethutil.Big32)
- length = ethutil.BigMin(length, lenData)
- copy(data, callData[offset.Int64():length.Int64()])
- }
- self.Printf(" => 0x%x", data)
- stack.Push(ethutil.BigD(data))
- case CALLDATASIZE:
- l := int64(len(callData))
- stack.Push(big.NewInt(l))
- self.Printf(" => %d", l)
- case CALLDATACOPY:
- var (
- size = uint64(len(callData))
- mOff = stack.Pop().Uint64()
- cOff = stack.Pop().Uint64()
- l = stack.Pop().Uint64()
- )
- if cOff > size {
- cOff = 0
- l = 0
- } else if cOff+l > size {
- l = 0
- }
- code := callData[cOff : cOff+l]
- mem.Set(mOff, l, code)
- self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, callData[cOff:cOff+l])
- case CODESIZE, EXTCODESIZE:
- var code []byte
- if op == EXTCODESIZE {
- addr := stack.Pop().Bytes()
- code = statedb.GetCode(addr)
- } else {
- code = context.Code
- }
- l := big.NewInt(int64(len(code)))
- stack.Push(l)
- self.Printf(" => %d", l)
- case CODECOPY, EXTCODECOPY:
- var code []byte
- if op == EXTCODECOPY {
- code = statedb.GetCode(stack.Pop().Bytes())
- } else {
- code = context.Code
- }
- context := NewContext(nil, nil, code, ethutil.Big0, ethutil.Big0)
- var (
- mOff = stack.Pop().Uint64()
- cOff = stack.Pop().Uint64()
- l = stack.Pop().Uint64()
- )
- codeCopy := context.GetCode(cOff, l)
- mem.Set(mOff, l, codeCopy)
- self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
- case GASPRICE:
- stack.Push(context.Price)
- self.Printf(" => %v", context.Price)
- // 0x40 range
- case BLOCKHASH:
- num := stack.Pop()
- n := U256(new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big257))
- if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
- stack.Push(ethutil.BigD(self.env.GetHash(num.Uint64())))
- } else {
- stack.Push(ethutil.Big0)
- }
- self.Printf(" => 0x%x", stack.Peek().Bytes())
- case COINBASE:
- coinbase := self.env.Coinbase()
- stack.Push(ethutil.BigD(coinbase))
- self.Printf(" => 0x%x", coinbase)
- case TIMESTAMP:
- time := self.env.Time()
- stack.Push(big.NewInt(time))
- self.Printf(" => 0x%x", time)
- case NUMBER:
- number := self.env.BlockNumber()
- stack.Push(number)
- self.Printf(" => 0x%x", number.Bytes())
- case DIFFICULTY:
- difficulty := self.env.Difficulty()
- stack.Push(difficulty)
- self.Printf(" => 0x%x", difficulty.Bytes())
- case GASLIMIT:
- self.Printf(" => %v", self.env.GasLimit())
- stack.Push(self.env.GasLimit())
- // 0x50 range
- case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
- a := uint64(op - PUSH1 + 1)
- byts := context.GetRangeValue(pc+1, a)
- // Push value to stack
- stack.Push(ethutil.BigD(byts))
- pc += a
- step += int(op) - int(PUSH1) + 1
- self.Printf(" => 0x%x", byts)
- case POP:
- stack.Pop()
- case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
- n := int(op - DUP1 + 1)
- stack.Dupn(n)
- self.Printf(" => [%d] 0x%x", n, stack.Peek().Bytes())
- case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
- n := int(op - SWAP1 + 2)
- x, y := stack.Swapn(n)
- self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes())
- case LOG0, LOG1, LOG2, LOG3, LOG4:
- n := int(op - LOG0)
- topics := make([][]byte, n)
- mSize, mStart := stack.Popn()
- for i := 0; i < n; i++ {
- topics[i] = ethutil.LeftPadBytes(stack.Pop().Bytes(), 32)
- }
- data := mem.Get(mStart.Int64(), mSize.Int64())
- log := &Log{context.Address(), topics, data}
- self.env.AddLog(log)
- self.Printf(" => %v", log)
- case MLOAD:
- offset := stack.Pop()
- val := ethutil.BigD(mem.Get(offset.Int64(), 32))
- stack.Push(val)
- self.Printf(" => 0x%x", val.Bytes())
- case MSTORE: // Store the value at stack top-1 in to memory at location stack top
- // Pop value of the stack
- val, mStart := stack.Popn()
- mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256))
- self.Printf(" => 0x%x", val)
- case MSTORE8:
- off := stack.Pop()
- val := stack.Pop()
- mem.store[off.Int64()] = byte(val.Int64() & 0xff)
- self.Printf(" => [%v] 0x%x", off, val)
- case SLOAD:
- loc := stack.Pop()
- val := ethutil.BigD(statedb.GetState(context.Address(), loc.Bytes()))
- stack.Push(val)
- self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
- case SSTORE:
- val, loc := stack.Popn()
- statedb.SetState(context.Address(), loc.Bytes(), val)
- msg.AddStorageChange(loc.Bytes())
- self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
- case JUMP:
- jump(pc, stack.Pop())
- continue
- case JUMPI:
- cond, pos := stack.Popn()
- if cond.Cmp(ethutil.BigTrue) >= 0 {
- jump(pc, pos)
- continue
- }
- case JUMPDEST:
- case PC:
- stack.Push(big.NewInt(int64(pc)))
- case MSIZE:
- stack.Push(big.NewInt(int64(mem.Len())))
- case GAS:
- stack.Push(context.Gas)
- // 0x60 range
- case CREATE:
- var (
- value = stack.Pop()
- size, offset = stack.Popn()
- input = mem.Get(offset.Int64(), size.Int64())
- gas = new(big.Int).Set(context.Gas)
- addr []byte
- )
- context.UseGas(context.Gas)
- ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value)
- if suberr != nil {
- stack.Push(ethutil.BigFalse)
- self.Printf(" (*) 0x0 %v", suberr)
- } else {
- // gas < len(ret) * CreateDataGas == NO_CODE
- dataGas := big.NewInt(int64(len(ret)))
- dataGas.Mul(dataGas, GasCreateByte)
- if context.UseGas(dataGas) {
- ref.SetCode(ret)
- msg.Output = ret
- }
- addr = ref.Address()
- stack.Push(ethutil.BigD(addr))
- self.Printf(" (*) %x", addr)
- }
- // Debug hook
- if self.Dbg != nil {
- self.Dbg.SetCode(context.Code)
- }
- case CALL, CALLCODE:
- self.Endl()
- gas := stack.Pop()
- // Pop gas and value of the stack.
- value, addr := stack.Popn()
- // Pop input size and offset
- inSize, inOffset := stack.Popn()
- // Pop return size and offset
- retSize, retOffset := stack.Popn()
- // Get the arguments from the memory
- args := mem.Get(inOffset.Int64(), inSize.Int64())
- var (
- ret []byte
- err error
- )
- if op == CALLCODE {
- ret, err = self.env.CallCode(context, addr.Bytes(), args, gas, price, value)
- } else {
- ret, err = self.env.Call(context, addr.Bytes(), args, gas, price, value)
- }
- if err != nil {
- stack.Push(ethutil.BigFalse)
- vmlogger.Debugln(err)
- } else {
- stack.Push(ethutil.BigTrue)
- msg.Output = ret
- mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
- }
- self.Printf("resume %x (%v)", context.Address(), context.Gas)
- // Debug hook
- if self.Dbg != nil {
- self.Dbg.SetCode(context.Code)
- }
- case RETURN:
- size, offset := stack.Popn()
- ret := mem.Get(offset.Int64(), size.Int64())
- self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
- return context.Return(ret), nil
- case SUICIDE:
- receiver := statedb.GetOrNewStateObject(stack.Pop().Bytes())
- balance := statedb.GetBalance(context.Address())
- self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
- receiver.AddAmount(balance)
- statedb.Delete(context.Address())
- fallthrough
- case STOP: // Stop the context
- self.Endl()
- return context.Return(nil), nil
- default:
- vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op)
- panic(fmt.Errorf("Invalid opcode %x", op))
- }
- pc++
- self.Endl()
- if self.Dbg != nil {
- for _, instrNo := range self.Dbg.BreakPoints() {
- if pc == uint64(instrNo) {
- self.Stepping = true
- if !self.Dbg.BreakHook(prevStep, op, mem, stack, statedb.GetStateObject(context.Address())) {
- return nil, nil
- }
- } else if self.Stepping {
- if !self.Dbg.StepHook(prevStep, op, mem, stack, statedb.GetStateObject(context.Address())) {
- return nil, nil
- }
- }
- }
- }
- }
- }
- func (self *DebugVm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
- gas := new(big.Int)
- addStepGasUsage := func(amount *big.Int) {
- if amount.Cmp(ethutil.Big0) >= 0 {
- gas.Add(gas, amount)
- }
- }
- addStepGasUsage(GasStep)
- var newMemSize *big.Int = ethutil.Big0
- var additionalGas *big.Int = new(big.Int)
- // Stack Check, memory resize & gas phase
- switch op {
- // Stack checks only
- case ISZERO, CALLDATALOAD, POP, JUMP, NOT: // 1
- stack.require(1)
- case JUMPI, ADD, SUB, DIV, SDIV, MOD, SMOD, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SIGNEXTEND: // 2
- stack.require(2)
- case ADDMOD, MULMOD: // 3
- stack.require(3)
- case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
- n := int(op - SWAP1 + 2)
- stack.require(n)
- case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
- n := int(op - DUP1 + 1)
- stack.require(n)
- case LOG0, LOG1, LOG2, LOG3, LOG4:
- n := int(op - LOG0)
- stack.require(n + 2)
- gas.Set(GasLog)
- addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog))
- mSize, mStart := stack.Peekn()
- addStepGasUsage(mSize)
- newMemSize = calcMemSize(mStart, mSize)
- case EXP:
- stack.require(2)
- gas.Set(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()) + 1)))
- // Gas only
- case STOP:
- gas.Set(ethutil.Big0)
- case SUICIDE:
- stack.require(1)
- gas.Set(ethutil.Big0)
- case SLOAD:
- stack.require(1)
- gas.Set(GasSLoad)
- // Memory resize & Gas
- case SSTORE:
- stack.require(2)
- var mult *big.Int
- y, x := stack.Peekn()
- val := statedb.GetState(context.Address(), x.Bytes())
- if len(val) == 0 && len(y.Bytes()) > 0 {
- // 0 => non 0
- mult = ethutil.Big3
- } else if len(val) > 0 && len(y.Bytes()) == 0 {
- statedb.Refund(caller.Address(), GasSStoreRefund)
- mult = ethutil.Big0
- } else {
- // non 0 => non 0 (or 0 => 0)
- mult = ethutil.Big1
- }
- gas.Set(new(big.Int).Mul(mult, GasSStore))
- case BALANCE:
- stack.require(1)
- gas.Set(GasBalance)
- case MSTORE:
- stack.require(2)
- newMemSize = calcMemSize(stack.Peek(), u256(32))
- case MLOAD:
- stack.require(1)
- newMemSize = calcMemSize(stack.Peek(), u256(32))
- case MSTORE8:
- stack.require(2)
- newMemSize = calcMemSize(stack.Peek(), u256(1))
- case RETURN:
- stack.require(2)
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
- case SHA3:
- stack.require(2)
- gas.Set(GasSha)
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
- additionalGas.Set(stack.data[stack.Len()-2])
- case CALLDATACOPY:
- stack.require(2)
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- additionalGas.Set(stack.data[stack.Len()-3])
- case CODECOPY:
- stack.require(3)
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- additionalGas.Set(stack.data[stack.Len()-3])
- case EXTCODECOPY:
- stack.require(4)
- newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
- additionalGas.Set(stack.data[stack.Len()-4])
- case CALL, CALLCODE:
- stack.require(7)
- gas.Set(GasCall)
- addStepGasUsage(stack.data[stack.Len()-1])
- x := calcMemSize(stack.data[stack.Len()-6], stack.data[stack.Len()-7])
- y := calcMemSize(stack.data[stack.Len()-4], stack.data[stack.Len()-5])
- newMemSize = ethutil.BigMax(x, y)
- case CREATE:
- stack.require(3)
- gas.Set(GasCreate)
- newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
- }
- switch op {
- case CALLDATACOPY, CODECOPY, EXTCODECOPY:
- additionalGas.Add(additionalGas, u256(31))
- additionalGas.Div(additionalGas, u256(32))
- addStepGasUsage(additionalGas)
- case SHA3:
- additionalGas.Add(additionalGas, u256(31))
- additionalGas.Div(additionalGas, u256(32))
- additionalGas.Mul(additionalGas, GasSha3Byte)
- addStepGasUsage(additionalGas)
- }
- if newMemSize.Cmp(ethutil.Big0) > 0 {
- newMemSize.Add(newMemSize, u256(31))
- newMemSize.Div(newMemSize, u256(32))
- newMemSize.Mul(newMemSize, u256(32))
- if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
- memGasUsage := new(big.Int).Sub(newMemSize, u256(int64(mem.Len())))
- memGasUsage.Mul(GasMemory, memGasUsage)
- memGasUsage.Div(memGasUsage, u256(32))
- addStepGasUsage(memGasUsage)
- }
- }
- return newMemSize, gas
- }
- func (self *DebugVm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
- gas := p.Gas(len(callData))
- if context.UseGas(gas) {
- ret = p.Call(callData)
- self.Printf("NATIVE_FUNC => %x", ret)
- self.Endl()
- return context.Return(ret), nil
- } else {
- self.Printf("NATIVE_FUNC => failed").Endl()
- tmp := new(big.Int).Set(context.Gas)
- panic(OOG(gas, tmp).Error())
- }
- }
- func (self *DebugVm) Printf(format string, v ...interface{}) VirtualMachine {
- if self.logTy == LogTyPretty {
- self.logStr += fmt.Sprintf(format, v...)
- }
- return self
- }
- func (self *DebugVm) Endl() VirtualMachine {
- if self.logTy == LogTyPretty {
- vmlogger.Debugln(self.logStr)
- self.logStr = ""
- }
- return self
- }
- func (self *DebugVm) Env() Environment {
- return self.env
- }
|