| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016 |
- 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 Vm struct {
- env Environment
- logTy byte
- logStr string
- err error
- // For logging
- debug bool
- Dbg Debugger
- BreakPoints []int64
- Stepping bool
- Fn string
- Recoverable bool
- }
- func New(env Environment) *Vm {
- lt := LogTyPretty
- // lt = LogTyDiff
- return &Vm{debug: true, env: env, logTy: lt, Recoverable: true}
- }
- func (self *Vm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
- self.env.SetDepth(self.env.Depth() + 1)
- 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())
- if self.Dbg != nil {
- //self.Dbg.Step(self, op, mem, stack, context)
- }
- 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(" => (%v) %x", size, 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(" => %x", context.Price)
- // 0x40 range
- case BLOCKHASH:
- num := stack.Pop()
- n := 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(U256(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.BlockNumber().Uint64()}
- 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)
- 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
- }
- self.Printf(" ~> false")
- 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)
- self.Printf(" => %x", 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
- )
- self.Endl()
- 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)
- }
- addr = ref.Address()
- stack.Push(ethutil.BigD(addr))
- }
- // Debug hook
- if self.Dbg != nil {
- self.Dbg.SetCode(context.Code)
- }
- case CALL, CALLCODE:
- gas := stack.Pop()
- // Pop gas and value of the stack.
- value, addr := stack.Popn()
- value = U256(value)
- // Pop input size and offset
- inSize, inOffset := stack.Popn()
- // Pop return size and offset
- retSize, retOffset := stack.Popn()
- address := ethutil.Address(addr.Bytes())
- self.Printf(" => %x", address).Endl()
- // Get the arguments from the memory
- args := mem.Get(inOffset.Int64(), inSize.Int64())
- if len(value.Bytes()) > 0 {
- gas.Add(gas, GasStipend)
- }
- var (
- ret []byte
- err error
- )
- if op == CALLCODE {
- ret, err = self.env.CallCode(context, address, args, gas, price, value)
- } else {
- ret, err = self.env.Call(context, address, args, gas, price, value)
- }
- if err != nil {
- stack.Push(ethutil.BigFalse)
- vmlogger.Debugln(err)
- } else {
- stack.Push(ethutil.BigTrue)
- 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.AddBalance(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
- }
- }
- }
- }
- }
- }
- type req struct {
- stack int
- gas *big.Int
- }
- var _baseCheck = map[OpCode]req{
- // Req Stack Gas price
- ADD: {2, GasFastestStep},
- LT: {2, GasFastestStep},
- GT: {2, GasFastestStep},
- SLT: {2, GasFastestStep},
- SGT: {2, GasFastestStep},
- EQ: {2, GasFastestStep},
- ISZERO: {1, GasFastestStep},
- SUB: {2, GasFastestStep},
- AND: {2, GasFastestStep},
- OR: {2, GasFastestStep},
- XOR: {2, GasFastestStep},
- NOT: {1, GasFastestStep},
- BYTE: {2, GasFastestStep},
- CALLDATALOAD: {1, GasFastestStep},
- CALLDATACOPY: {3, GasFastestStep},
- MLOAD: {1, GasFastestStep},
- MSTORE: {2, GasFastestStep},
- MSTORE8: {2, GasFastestStep},
- CODECOPY: {3, GasFastestStep},
- MUL: {2, GasFastStep},
- DIV: {2, GasFastStep},
- SDIV: {2, GasFastStep},
- MOD: {2, GasFastStep},
- SMOD: {2, GasFastStep},
- SIGNEXTEND: {2, GasFastStep},
- ADDMOD: {3, GasMidStep},
- MULMOD: {3, GasMidStep},
- JUMP: {1, GasMidStep},
- JUMPI: {2, GasSlowStep},
- EXP: {2, GasSlowStep},
- ADDRESS: {0, GasQuickStep},
- ORIGIN: {0, GasQuickStep},
- CALLER: {0, GasQuickStep},
- CALLVALUE: {0, GasQuickStep},
- CODESIZE: {0, GasQuickStep},
- GASPRICE: {0, GasQuickStep},
- COINBASE: {0, GasQuickStep},
- TIMESTAMP: {0, GasQuickStep},
- NUMBER: {0, GasQuickStep},
- CALLDATASIZE: {0, GasQuickStep},
- DIFFICULTY: {0, GasQuickStep},
- GASLIMIT: {0, GasQuickStep},
- POP: {0, GasQuickStep},
- PC: {0, GasQuickStep},
- MSIZE: {0, GasQuickStep},
- GAS: {0, GasQuickStep},
- BLOCKHASH: {1, GasExtStep},
- BALANCE: {0, GasExtStep},
- EXTCODESIZE: {1, GasExtStep},
- EXTCODECOPY: {4, GasExtStep},
- SLOAD: {1, GasStorageGet},
- SSTORE: {2, Zero},
- SHA3: {1, GasSha3Base},
- CREATE: {3, GasCreate},
- CALL: {7, GasCall},
- CALLCODE: {7, GasCall},
- JUMPDEST: {0, GasJumpDest},
- SUICIDE: {1, Zero},
- RETURN: {2, Zero},
- }
- func baseCheck(op OpCode, stack *Stack, gas *big.Int) {
- if r, ok := _baseCheck[op]; ok {
- stack.require(r.stack)
- gas.Add(gas, r.gas)
- }
- }
- func toWordSize(size *big.Int) *big.Int {
- tmp := new(big.Int)
- tmp.Add(size, u256(31))
- tmp.Div(tmp, u256(32))
- return tmp
- }
- func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int) {
- var (
- gas = new(big.Int)
- newMemSize *big.Int = new(big.Int)
- )
- baseCheck(op, stack, gas)
- // Stack Check, memory resize & gas phase
- switch op {
- 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:
- gas.Set(GasFastestStep)
- 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)
- gas.Set(GasFastestStep)
- 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)
- gas.Set(GasFastestStep)
- case LOG0, LOG1, LOG2, LOG3, LOG4:
- n := int(op - LOG0)
- stack.require(n + 2)
- mSize, mStart := stack.Peekn()
- gas.Add(gas, GasLogBase)
- gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
- gas.Add(gas, new(big.Int).Mul(mSize, GasLogByte))
- newMemSize = calcMemSize(mStart, mSize)
- case EXP:
- gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.Len()-2].Bytes()))), GasExpByte))
- case SSTORE:
- stack.require(2)
- var g *big.Int
- y, x := stack.Peekn()
- val := statedb.GetState(context.Address(), x.Bytes())
- if len(val) == 0 && len(y.Bytes()) > 0 {
- // 0 => non 0
- g = GasStorageAdd
- } else if len(val) > 0 && len(y.Bytes()) == 0 {
- statedb.Refund(self.env.Origin(), RefundStorage)
- g = GasStorageMod
- } else {
- // non 0 => non 0 (or 0 => 0)
- g = GasStorageMod
- }
- gas.Set(g)
- case MLOAD:
- newMemSize = calcMemSize(stack.Peek(), u256(32))
- case MSTORE8:
- newMemSize = calcMemSize(stack.Peek(), u256(1))
- case MSTORE:
- newMemSize = calcMemSize(stack.Peek(), u256(32))
- case RETURN:
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
- case SHA3:
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-2])
- words := toWordSize(stack.data[stack.Len()-2])
- gas.Add(gas, words.Mul(words, GasSha3Word))
- case CALLDATACOPY:
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- words := toWordSize(stack.data[stack.Len()-3])
- gas.Add(gas, words.Mul(words, GasCopyWord))
- case CODECOPY:
- newMemSize = calcMemSize(stack.Peek(), stack.data[stack.Len()-3])
- words := toWordSize(stack.data[stack.Len()-3])
- gas.Add(gas, words.Mul(words, GasCopyWord))
- case EXTCODECOPY:
- newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-4])
- words := toWordSize(stack.data[stack.Len()-4])
- gas.Add(gas, words.Mul(words, GasCopyWord))
- case CREATE:
- newMemSize = calcMemSize(stack.data[stack.Len()-2], stack.data[stack.Len()-3])
- case CALL, CALLCODE:
- gas.Add(gas, stack.data[stack.Len()-1])
- if op == CALL {
- if self.env.State().GetStateObject(stack.data[stack.Len()-2].Bytes()) == nil {
- gas.Add(gas, GasCallNewAccount)
- }
- }
- if len(stack.data[stack.Len()-3].Bytes()) > 0 {
- gas.Add(gas, GasCallValueTransfer)
- }
- 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)
- }
- if newMemSize.Cmp(ethutil.Big0) > 0 {
- newMemSizeWords := toWordSize(newMemSize)
- newMemSize.Mul(newMemSizeWords, u256(32))
- if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
- oldSize := toWordSize(big.NewInt(int64(mem.Len())))
- pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero)
- linCoef := new(big.Int).Mul(oldSize, GasMemWord)
- quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom)
- oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
- pow.Exp(newMemSizeWords, ethutil.Big2, Zero)
- linCoef = new(big.Int).Mul(newMemSizeWords, GasMemWord)
- quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
- newTotalFee := new(big.Int).Add(linCoef, quadCoef)
- gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee))
- }
- }
- return newMemSize, gas
- }
- func (self *Vm) 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 *Vm) Printf(format string, v ...interface{}) VirtualMachine {
- if self.debug {
- if self.logTy == LogTyPretty {
- self.logStr += fmt.Sprintf(format, v...)
- }
- }
- return self
- }
- func (self *Vm) Endl() VirtualMachine {
- if self.debug {
- if self.logTy == LogTyPretty {
- vmlogger.Debugln(self.logStr)
- self.logStr = ""
- }
- }
- return self
- }
- func (self *Vm) Env() Environment {
- return self.env
- }
|