Official Go implementation of the Ethereum protocol
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-ethereum/vm/vm.go

908 lines
21 KiB

10 years ago
package vm
10 years ago
import (
"fmt"
"math/big"
10 years ago
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
)
type Vm struct {
10 years ago
env Environment
logTy byte
logStr string
err error
// For logging
debug bool
10 years ago
BreakPoints []int64
Stepping bool
Fn string
Recoverable bool
}
10 years ago
func New(env Environment) *Vm {
10 years ago
lt := LogTyPretty
return &Vm{debug: Debug, env: env, logTy: lt, Recoverable: true}
10 years ago
}
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)
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address()[:4], context.Address(), len(code), context.Gas, callData).Endl()
10 years ago
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()
10 years ago
stack = newStack()
10 years ago
pc uint64 = 0
step = 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 {
// The base for all big integer arithmetic
base := new(big.Int)
step++
// Get the memory location of pc
op = context.GetOp(pc)
10 years ago
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
10 years ago
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:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v + %v", y, x)
10 years ago
base.Add(x, y)
10 years ago
U256(base)
self.Printf(" = %v", base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case SUB:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v - %v", y, x)
10 years ago
base.Sub(x, y)
10 years ago
U256(base)
self.Printf(" = %v", base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case MUL:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v * %v", y, x)
10 years ago
base.Mul(x, y)
10 years ago
U256(base)
self.Printf(" = %v", base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case DIV:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v / %v", x, y)
if y.Cmp(ethutil.Big0) != 0 {
base.Div(x, y)
}
U256(base)
self.Printf(" = %v", base)
10 years ago
// pop result back on the stack
stack.push(base)
10 years ago
case SDIV:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
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)
10 years ago
stack.push(base)
10 years ago
case MOD:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
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)
10 years ago
stack.push(base)
10 years ago
case SMOD:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
10 years ago
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)
10 years ago
stack.push(base)
10 years ago
case EXP:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
10 years ago
self.Printf(" %v ** %v", x, y)
10 years ago
10 years ago
base.Exp(x, y, Pow256)
10 years ago
U256(base)
self.Printf(" = %v", base)
10 years ago
stack.push(base)
10 years ago
case SIGNEXTEND:
10 years ago
back := stack.pop().Uint64()
10 years ago
if back < 31 {
bit := uint(back*8 + 7)
10 years ago
num := stack.pop()
10 years ago
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)
10 years ago
stack.push(num)
10 years ago
}
case NOT:
10 years ago
base.Sub(Pow256, stack.pop()).Sub(base, ethutil.Big1)
10 years ago
// Not needed
10 years ago
base = U256(base)
10 years ago
10 years ago
stack.push(base)
10 years ago
case LT:
10 years ago
x, y := stack.pop(), stack.pop()
self.Printf(" %v < %v", x, y)
10 years ago
// x < y
10 years ago
if x.Cmp(y) < 0 {
stack.push(ethutil.BigTrue)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
}
case GT:
10 years ago
x, y := stack.pop(), stack.pop()
self.Printf(" %v > %v", x, y)
10 years ago
// x > y
10 years ago
if x.Cmp(y) > 0 {
stack.push(ethutil.BigTrue)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
}
case SLT:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v < %v", x, y)
10 years ago
// x < y
10 years ago
if x.Cmp(S256(y)) < 0 {
stack.push(ethutil.BigTrue)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
}
case SGT:
10 years ago
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v > %v", x, y)
10 years ago
// x > y
10 years ago
if x.Cmp(y) > 0 {
stack.push(ethutil.BigTrue)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
}
case EQ:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v == %v", y, x)
// x == y
if x.Cmp(y) == 0 {
10 years ago
stack.push(ethutil.BigTrue)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
}
case ISZERO:
10 years ago
x := stack.pop()
10 years ago
if x.Cmp(ethutil.BigFalse) > 0 {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
} else {
10 years ago
stack.push(ethutil.BigTrue)
10 years ago
}
// 0x10 range
case AND:
10 years ago
x, y := stack.pop(), stack.pop()
10 years ago
self.Printf(" %v & %v", y, x)
10 years ago
stack.push(base.And(x, y))
10 years ago
case OR:
10 years ago
x, y := stack.pop(), stack.pop()
self.Printf(" %v | %v", x, y)
10 years ago
10 years ago
stack.push(base.Or(x, y))
10 years ago
case XOR:
10 years ago
x, y := stack.pop(), stack.pop()
self.Printf(" %v ^ %v", x, y)
10 years ago
10 years ago
stack.push(base.Xor(x, y))
10 years ago
case BYTE:
10 years ago
th, val := stack.pop(), stack.pop()
10 years ago
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())
10 years ago
stack.push(base)
10 years ago
case ADDMOD:
10 years ago
x := stack.pop()
y := stack.pop()
z := stack.pop()
10 years ago
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)
10 years ago
stack.push(base)
10 years ago
case MULMOD:
10 years ago
x := stack.pop()
y := stack.pop()
z := stack.pop()
10 years ago
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)
10 years ago
stack.push(base)
10 years ago
// 0x20 range
case SHA3:
10 years ago
size, offset := stack.pop(), stack.pop()
10 years ago
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
10 years ago
stack.push(ethutil.BigD(data))
10 years ago
self.Printf(" => (%v) %x", size, data)
10 years ago
// 0x30 range
case ADDRESS:
10 years ago
stack.push(ethutil.BigD(context.Address()))
10 years ago
self.Printf(" => %x", context.Address())
case BALANCE:
10 years ago
addr := stack.pop().Bytes()
var balance *big.Int
if statedb.GetStateObject(addr) != nil {
balance = statedb.GetBalance(addr)
} else {
balance = base
}
10 years ago
10 years ago
stack.push(balance)
10 years ago
self.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
origin := self.env.Origin()
10 years ago
stack.push(ethutil.BigD(origin))
10 years ago
self.Printf(" => %x", origin)
case CALLER:
caller := context.caller.Address()
10 years ago
stack.push(ethutil.BigD(caller))
10 years ago
self.Printf(" => %x", caller)
case CALLVALUE:
10 years ago
stack.push(value)
10 years ago
self.Printf(" => %v", value)
case CALLDATALOAD:
var (
10 years ago
offset = stack.pop()
10 years ago
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)
10 years ago
stack.push(ethutil.BigD(data))
10 years ago
case CALLDATASIZE:
l := int64(len(callData))
10 years ago
stack.push(big.NewInt(l))
10 years ago
self.Printf(" => %d", l)
case CALLDATACOPY:
var (
size = uint64(len(callData))
10 years ago
mOff = stack.pop().Uint64()
cOff = stack.pop().Uint64()
l = stack.pop().Uint64()
10 years ago
)
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 {
10 years ago
addr := stack.pop().Bytes()
10 years ago
code = statedb.GetCode(addr)
} else {
code = context.Code
}
l := big.NewInt(int64(len(code)))
10 years ago
stack.push(l)
10 years ago
self.Printf(" => %d", l)
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
10 years ago
code = statedb.GetCode(stack.pop().Bytes())
10 years ago
} else {
code = context.Code
}
context := NewContext(nil, nil, code, ethutil.Big0, ethutil.Big0)
var (
10 years ago
mOff = stack.pop().Uint64()
cOff = stack.pop().Uint64()
l = stack.pop().Uint64()
10 years ago
)
codeCopy := context.GetCode(cOff, l)
mem.Set(mOff, l, codeCopy)
self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
case GASPRICE:
10 years ago
stack.push(context.Price)
10 years ago
10 years ago
self.Printf(" => %x", context.Price)
10 years ago
// 0x40 range
case BLOCKHASH:
10 years ago
num := stack.pop()
10 years ago
n := new(big.Int).Sub(self.env.BlockNumber(), ethutil.Big257)
10 years ago
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
10 years ago
stack.push(ethutil.BigD(self.env.GetHash(num.Uint64())))
10 years ago
} else {
10 years ago
stack.push(ethutil.Big0)
10 years ago
}
10 years ago
self.Printf(" => 0x%x", stack.peek().Bytes())
10 years ago
case COINBASE:
coinbase := self.env.Coinbase()
10 years ago
stack.push(ethutil.BigD(coinbase))
10 years ago
self.Printf(" => 0x%x", coinbase)
case TIMESTAMP:
time := self.env.Time()
10 years ago
stack.push(big.NewInt(time))
10 years ago
self.Printf(" => 0x%x", time)
case NUMBER:
number := self.env.BlockNumber()
10 years ago
stack.push(U256(number))
10 years ago
self.Printf(" => 0x%x", number.Bytes())
case DIFFICULTY:
difficulty := self.env.Difficulty()
10 years ago
stack.push(difficulty)
10 years ago
self.Printf(" => 0x%x", difficulty.Bytes())
case GASLIMIT:
self.Printf(" => %v", self.env.GasLimit())
10 years ago
stack.push(self.env.GasLimit())
10 years ago
// 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)
10 years ago
// push value to stack
stack.push(ethutil.BigD(byts))
10 years ago
pc += a
step += int(op) - int(PUSH1) + 1
self.Printf(" => 0x%x", byts)
case POP:
10 years ago
stack.pop()
10 years ago
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
10 years ago
stack.dup(n)
10 years ago
10 years ago
self.Printf(" => [%d] 0x%x", n, stack.peek().Bytes())
10 years ago
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
10 years ago
stack.swap(n)
10 years ago
10 years ago
self.Printf(" => [%d]", n)
10 years ago
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics := make([][]byte, n)
10 years ago
mStart, mSize := stack.pop(), stack.pop()
10 years ago
for i := 0; i < n; i++ {
10 years ago
topics[i] = ethutil.LeftPadBytes(stack.pop().Bytes(), 32)
10 years ago
}
data := mem.Get(mStart.Int64(), mSize.Int64())
log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
10 years ago
self.env.AddLog(log)
self.Printf(" => %v", log)
case MLOAD:
10 years ago
offset := stack.pop()
10 years ago
val := ethutil.BigD(mem.Get(offset.Int64(), 32))
10 years ago
stack.push(val)
10 years ago
self.Printf(" => 0x%x", val.Bytes())
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
10 years ago
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
10 years ago
mem.Set(mStart.Uint64(), 32, ethutil.BigToBytes(val, 256))
self.Printf(" => 0x%x", val)
case MSTORE8:
10 years ago
off, val := stack.pop(), stack.pop()
10 years ago
mem.store[off.Int64()] = byte(val.Int64() & 0xff)
self.Printf(" => [%v] 0x%x", off, val)
case SLOAD:
10 years ago
loc := stack.pop()
10 years ago
val := ethutil.BigD(statedb.GetState(context.Address(), loc.Bytes()))
10 years ago
stack.push(val)
10 years ago
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case SSTORE:
10 years ago
loc, val := stack.pop(), stack.pop()
10 years ago
statedb.SetState(context.Address(), loc.Bytes(), val)
self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case JUMP:
10 years ago
jump(pc, stack.pop())
10 years ago
continue
case JUMPI:
10 years ago
pos, cond := stack.pop(), stack.pop()
10 years ago
if cond.Cmp(ethutil.BigTrue) >= 0 {
jump(pc, pos)
continue
}
self.Printf(" ~> false")
10 years ago
case JUMPDEST:
case PC:
10 years ago
stack.push(big.NewInt(int64(pc)))
10 years ago
case MSIZE:
10 years ago
stack.push(big.NewInt(int64(mem.Len())))
10 years ago
case GAS:
10 years ago
stack.push(context.Gas)
10 years ago
self.Printf(" => %x", context.Gas)
10 years ago
// 0x60 range
case CREATE:
var (
10 years ago
value = stack.pop()
offset, size = stack.pop(), stack.pop()
10 years ago
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(context.Gas)
addr []byte
)
10 years ago
self.Endl()
10 years ago
context.UseGas(context.Gas)
ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value)
if suberr != nil {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
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()
10 years ago
stack.push(ethutil.BigD(addr))
10 years ago
}
case CALL, CALLCODE:
10 years ago
gas := stack.pop()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
10 years ago
value = U256(value)
10 years ago
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
10 years ago
address := ethutil.Address(addr.Bytes())
self.Printf(" => %x", address).Endl()
10 years ago
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
if len(value.Bytes()) > 0 {
gas.Add(gas, GasStipend)
}
10 years ago
var (
ret []byte
err error
)
if op == CALLCODE {
ret, err = self.env.CallCode(context, address, args, gas, price, value)
10 years ago
} else {
ret, err = self.env.Call(context, address, args, gas, price, value)
10 years ago
}
if err != nil {
10 years ago
stack.push(ethutil.BigFalse)
10 years ago
self.Printf("%v").Endl()
10 years ago
} else {
10 years ago
stack.push(ethutil.BigTrue)
10 years ago
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
self.Printf("resume %x (%v)", context.Address(), context.Gas)
case RETURN:
10 years ago
offset, size := stack.pop(), stack.pop()
10 years ago
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:
10 years ago
receiver := statedb.GetOrNewStateObject(stack.pop().Bytes())
10 years ago
balance := statedb.GetBalance(context.Address())
self.Printf(" => (%x) %v", receiver.Address()[:4], balance)
receiver.AddBalance(balance)
10 years ago
statedb.Delete(context.Address())
fallthrough
case STOP: // Stop the context
self.Endl()
return context.Return(nil), nil
default:
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
10 years ago
panic(fmt.Errorf("Invalid opcode %x", op))
}
pc++
self.Endl()
}
}
10 years ago
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)
10 years ago
10 years ago
// stack Check, memory resize & gas phase
10 years ago
switch op {
10 years ago
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)
10 years ago
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)
10 years ago
gas.Set(GasFastestStep)
10 years ago
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)
10 years ago
gas.Set(GasFastestStep)
10 years ago
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
stack.require(n + 2)
10 years ago
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
gas.Add(gas, GasLogBase)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
10 years ago
gas.Add(gas, new(big.Int).Mul(mSize, GasLogByte))
10 years ago
newMemSize = calcMemSize(mStart, mSize)
case EXP:
10 years ago
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
10 years ago
case SSTORE:
stack.require(2)
var g *big.Int
10 years ago
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
10 years ago
val := statedb.GetState(context.Address(), x.Bytes())
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
g = GasStorageAdd
10 years ago
} else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(self.env.Origin(), RefundStorage)
10 years ago
g = GasStorageMod
10 years ago
} else {
// non 0 => non 0 (or 0 => 0)
g = GasStorageMod
10 years ago
}
gas.Set(g)
case SUICIDE:
if !statedb.IsDeleted(context.Address()) {
statedb.Refund(self.env.Origin(), RefundSuicide)
}
10 years ago
case MLOAD:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(32))
10 years ago
case MSTORE8:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(1))
10 years ago
case MSTORE:
10 years ago
newMemSize = calcMemSize(stack.peek(), u256(32))
10 years ago
case RETURN:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
10 years ago
case SHA3:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, GasSha3Word))
case CALLDATACOPY:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case CODECOPY:
10 years ago
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
10 years ago
10 years ago
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case EXTCODECOPY:
10 years ago
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
10 years ago
words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, GasCopyWord))
case CREATE:
10 years ago
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
10 years ago
case CALL, CALLCODE:
10 years ago
gas.Add(gas, stack.data[stack.len()-1])
if op == CALL {
10 years ago
if self.env.State().GetStateObject(stack.data[stack.len()-2].Bytes()) == nil {
gas.Add(gas, GasCallNewAccount)
}
}
10 years ago
if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, GasCallValueTransfer)
}
10 years ago
10 years ago
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
10 years ago
newMemSize = ethutil.BigMax(x, y)
}
if newMemSize.Cmp(ethutil.Big0) > 0 {
newMemSizeWords := toWordSize(newMemSize)
newMemSize.Mul(newMemSizeWords, u256(32))
10 years ago
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
10 years ago
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
pow := new(big.Int).Exp(oldSize, ethutil.Big2, Zero)
10 years ago
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)
10 years ago
quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee))
10 years ago
}
}
10 years ago
return newMemSize, gas
10 years ago
}
10 years ago
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())
}
}
10 years ago
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
10 years ago
}
return self
}
10 years ago
func (self *Vm) Endl() VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
vmlogger.Infoln(self.logStr)
self.logStr = ""
}
10 years ago
}
return self
10 years ago
}
10 years ago
func (self *Vm) Env() Environment {
return self.env
}