go-pulse/core/vm/vm.go

801 lines
18 KiB
Go
Raw Normal View History

2014-10-18 11:31:20 +00:00
package vm
2015-01-19 10:18:34 +00:00
import (
"fmt"
"math/big"
2015-03-16 10:27:38 +00:00
"github.com/ethereum/go-ethereum/common"
2015-03-23 15:59:09 +00:00
"github.com/ethereum/go-ethereum/core/state"
2015-03-23 20:48:31 +00:00
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
2015-01-19 10:18:34 +00:00
)
2014-10-15 15:12:26 +00:00
type Vm struct {
2015-01-19 10:18:34 +00:00
env Environment
err error
// For logging
debug bool
2015-01-19 10:18:34 +00:00
BreakPoints []int64
Stepping bool
Fn string
Recoverable bool
2015-03-28 19:03:25 +00:00
// Will be called before the vm returns
After func(*Context, error)
2015-01-19 10:18:34 +00:00
}
2015-01-20 14:49:12 +00:00
func New(env Environment) *Vm {
return &Vm{env: env, debug: Debug, Recoverable: true}
2015-01-19 10:18:34 +00:00
}
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
2015-01-19 10:18:34 +00:00
self.env.SetDepth(self.env.Depth() + 1)
2015-03-23 20:48:31 +00:00
defer self.env.SetDepth(self.env.Depth() - 1)
var (
caller = context.caller
code = context.Code
value = context.value
price = context.Price
)
2015-01-19 10:18:34 +00:00
2015-03-27 15:53:05 +00:00
// User defer pattern to check for an error and, based on the error being nil or not, use all gas and return.
2015-03-27 15:09:57 +00:00
defer func() {
2015-03-28 19:03:25 +00:00
if self.After != nil {
self.After(context, err)
}
2015-03-27 15:09:57 +00:00
if err != nil {
2015-03-27 15:09:57 +00:00
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
context.UseGas(context.Gas)
ret = context.Return(nil)
}
}()
2015-01-19 10:18:34 +00:00
2015-03-17 10:19:23 +00:00
if context.CodeAddr != nil {
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
return self.RunPrecompiled(p, callData, context)
}
2015-01-19 10:18:34 +00:00
}
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return context.Return(nil), nil
}
2015-01-19 10:18:34 +00:00
var (
op OpCode
codehash = crypto.Sha3Hash(code)
mem = NewMemory()
stack = newStack()
pc = uint64(0)
statedb = self.env.State()
jump = func(from uint64, to *big.Int) error {
if !context.jumpdests.has(codehash, code, to) {
nop := context.GetOp(to.Uint64())
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
2015-01-19 10:18:34 +00:00
}
pc = to.Uint64()
2015-01-19 10:18:34 +00:00
2015-03-27 15:09:57 +00:00
return nil
2015-01-19 10:18:34 +00:00
}
)
for {
// The base for all big integer arithmetic
base := new(big.Int)
// Get the memory location of pc
op = context.GetOp(pc)
self.log(pc, op, context.Gas, mem, stack, context)
2015-06-10 08:59:44 +00:00
2015-03-27 15:09:57 +00:00
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
if err != nil {
return nil, err
}
2015-01-19 10:18:34 +00:00
if !context.UseGas(gas) {
tmp := new(big.Int).Set(context.Gas)
context.UseGas(context.Gas)
return context.Return(nil), OOG(gas, tmp)
}
mem.Resize(newMemSize.Uint64())
switch op {
case ADD:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
base.Add(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case SUB:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
base.Sub(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case MUL:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
base.Mul(x, y)
2015-01-19 10:18:34 +00:00
U256(base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case DIV:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
if y.Cmp(common.Big0) != 0 {
2015-01-19 10:18:34 +00:00
base.Div(x, y)
}
U256(base)
2015-03-09 23:25:27 +00:00
// pop result back on the stack
stack.push(base)
2015-01-19 10:18:34 +00:00
case SDIV:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
2015-01-19 10:18:34 +00:00
} else {
n := new(big.Int)
2015-03-16 10:27:38 +00:00
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
2015-01-19 10:18:34 +00:00
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case MOD:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
2015-01-19 10:18:34 +00:00
} else {
base.Mod(x, y)
}
U256(base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case SMOD:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
2015-01-19 10:18:34 +00:00
} else {
n := new(big.Int)
2015-03-16 10:27:38 +00:00
if x.Cmp(common.Big0) < 0 {
2015-01-19 10:18:34 +00:00
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case EXP:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
base.Exp(x, y, Pow256)
2015-01-19 10:18:34 +00:00
U256(base)
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case SIGNEXTEND:
2015-03-12 18:41:56 +00:00
back := stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
2015-03-09 23:25:27 +00:00
num := stack.pop()
2015-03-16 10:27:38 +00:00
mask := new(big.Int).Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1)
if common.BitTest(num, int(bit)) {
2015-01-19 10:18:34 +00:00
num.Or(num, mask.Not(mask))
} else {
num.And(num, mask)
}
num = U256(num)
2015-03-09 23:25:27 +00:00
stack.push(num)
2015-01-19 10:18:34 +00:00
}
case NOT:
2015-03-12 17:22:35 +00:00
stack.push(U256(new(big.Int).Not(stack.pop())))
2015-01-19 10:18:34 +00:00
case LT:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
// x < y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) < 0 {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
case GT:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
// x > y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) > 0 {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
case SLT:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
// x < y
2015-03-09 23:25:27 +00:00
if x.Cmp(S256(y)) < 0 {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
case SGT:
2015-03-09 23:25:27 +00:00
x, y := S256(stack.pop()), S256(stack.pop())
2015-01-19 10:18:34 +00:00
// x > y
2015-03-09 23:25:27 +00:00
if x.Cmp(y) > 0 {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
case EQ:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
// x == y
if x.Cmp(y) == 0 {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
case ISZERO:
2015-03-09 23:25:27 +00:00
x := stack.pop()
2015-03-16 10:27:38 +00:00
if x.Cmp(common.BigFalse) > 0 {
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
}
case AND:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(base.And(x, y))
2015-01-19 10:18:34 +00:00
case OR:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(base.Or(x, y))
2015-01-19 10:18:34 +00:00
case XOR:
2015-03-09 23:25:27 +00:00
x, y := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(base.Xor(x, y))
2015-01-19 10:18:34 +00:00
case BYTE:
2015-03-09 23:25:27 +00:00
th, val := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
if th.Cmp(big.NewInt(32)) < 0 {
2015-03-16 10:27:38 +00:00
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
2015-01-19 10:18:34 +00:00
base.Set(byt)
} else {
2015-03-16 10:27:38 +00:00
base.Set(common.BigFalse)
2015-01-19 10:18:34 +00:00
}
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case ADDMOD:
2015-03-09 23:25:27 +00:00
x := stack.pop()
y := stack.pop()
z := stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-12 17:22:35 +00:00
if z.Cmp(Zero) > 0 {
add := new(big.Int).Add(x, y)
2015-01-19 10:18:34 +00:00
base.Mod(add, z)
2015-03-12 17:22:35 +00:00
base = U256(base)
2015-01-19 10:18:34 +00:00
}
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case MULMOD:
2015-03-09 23:25:27 +00:00
x := stack.pop()
y := stack.pop()
z := stack.pop()
2015-01-19 10:18:34 +00:00
if z.Cmp(Zero) > 0 {
mul := new(big.Int).Mul(x, y)
2015-01-19 10:18:34 +00:00
base.Mod(mul, z)
U256(base)
}
2015-03-09 23:25:27 +00:00
stack.push(base)
2015-01-19 10:18:34 +00:00
case SHA3:
2015-03-12 22:26:58 +00:00
offset, size := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
2015-03-16 10:27:38 +00:00
stack.push(common.BigD(data))
2015-01-19 10:18:34 +00:00
case ADDRESS:
2015-03-16 17:42:18 +00:00
stack.push(common.Bytes2Big(context.Address().Bytes()))
2015-01-19 10:18:34 +00:00
case BALANCE:
2015-03-16 17:42:18 +00:00
addr := common.BigToAddress(stack.pop())
2015-03-12 21:29:10 +00:00
balance := statedb.GetBalance(addr)
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
stack.push(balance)
2015-01-19 10:18:34 +00:00
case ORIGIN:
origin := self.env.Origin()
2015-03-16 17:42:18 +00:00
stack.push(origin.Big())
2015-01-19 10:18:34 +00:00
case CALLER:
caller := context.caller.Address()
2015-03-16 17:42:18 +00:00
stack.push(common.Bytes2Big(caller.Bytes()))
2015-01-19 10:18:34 +00:00
case CALLVALUE:
2015-03-09 23:25:27 +00:00
stack.push(value)
2015-01-19 10:18:34 +00:00
case CALLDATALOAD:
data := getData(callData, stack.pop(), common.Big32)
2015-01-19 10:18:34 +00:00
stack.push(common.Bytes2Big(data))
2015-01-19 10:18:34 +00:00
case CALLDATASIZE:
l := int64(len(callData))
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(l))
2015-01-19 10:18:34 +00:00
case CALLDATACOPY:
var (
2015-03-19 14:06:56 +00:00
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
2015-01-19 10:18:34 +00:00
)
2015-03-19 21:45:03 +00:00
data := getData(callData, cOff, l)
2015-01-19 10:18:34 +00:00
2015-03-19 14:06:56 +00:00
mem.Set(mOff.Uint64(), l.Uint64(), data)
2015-01-19 10:18:34 +00:00
case CODESIZE, EXTCODESIZE:
var code []byte
if op == EXTCODESIZE {
2015-03-16 17:42:18 +00:00
addr := common.BigToAddress(stack.pop())
2015-01-19 10:18:34 +00:00
code = statedb.GetCode(addr)
} else {
code = context.Code
}
l := big.NewInt(int64(len(code)))
2015-03-09 23:25:27 +00:00
stack.push(l)
2015-01-19 10:18:34 +00:00
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
2015-03-16 17:42:18 +00:00
addr := common.BigToAddress(stack.pop())
code = statedb.GetCode(addr)
2015-01-19 10:18:34 +00:00
} else {
code = context.Code
}
2015-03-19 14:06:56 +00:00
2015-01-19 10:18:34 +00:00
var (
2015-03-19 14:06:56 +00:00
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
2015-01-19 10:18:34 +00:00
)
2015-03-19 21:45:03 +00:00
codeCopy := getData(code, cOff, l)
2015-03-19 14:06:56 +00:00
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
2015-01-19 10:18:34 +00:00
case GASPRICE:
2015-03-09 23:25:27 +00:00
stack.push(context.Price)
2015-01-19 10:18:34 +00:00
case BLOCKHASH:
2015-03-09 23:25:27 +00:00
num := stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
2015-01-19 10:18:34 +00:00
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
2015-03-17 10:19:23 +00:00
stack.push(self.env.GetHash(num.Uint64()).Big())
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.Big0)
2015-01-19 10:18:34 +00:00
}
case COINBASE:
coinbase := self.env.Coinbase()
2015-03-17 10:19:23 +00:00
stack.push(coinbase.Big())
2015-01-19 10:18:34 +00:00
case TIMESTAMP:
time := self.env.Time()
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(time))
2015-01-19 10:18:34 +00:00
case NUMBER:
number := self.env.BlockNumber()
2015-03-09 23:25:27 +00:00
stack.push(U256(number))
2015-01-19 10:18:34 +00:00
case DIFFICULTY:
difficulty := self.env.Difficulty()
2015-03-09 23:25:27 +00:00
stack.push(difficulty)
2015-01-19 10:18:34 +00:00
case GASLIMIT:
2015-03-09 23:25:27 +00:00
stack.push(self.env.GasLimit())
2015-01-19 10:18:34 +00:00
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:
size := uint64(op - PUSH1 + 1)
byts := getData(code, new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
2015-03-09 23:25:27 +00:00
// push value to stack
stack.push(common.Bytes2Big(byts))
pc += size
2015-01-19 10:18:34 +00:00
case POP:
2015-03-09 23:25:27 +00:00
stack.pop()
2015-01-19 10:18:34 +00:00
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
2015-03-09 23:25:27 +00:00
stack.dup(n)
2015-01-19 10:18:34 +00:00
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
2015-03-09 23:25:27 +00:00
stack.swap(n)
2015-01-19 10:18:34 +00:00
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
2015-03-16 22:10:26 +00:00
topics := make([]common.Hash, n)
2015-03-09 23:25:27 +00:00
mStart, mSize := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
for i := 0; i < n; i++ {
topics[i] = common.BigToHash(stack.pop())
2015-01-19 10:18:34 +00:00
}
data := mem.Get(mStart.Int64(), mSize.Int64())
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
2015-01-19 10:18:34 +00:00
self.env.AddLog(log)
case MLOAD:
2015-03-09 23:25:27 +00:00
offset := stack.pop()
2015-03-16 10:27:38 +00:00
val := common.BigD(mem.Get(offset.Int64(), 32))
2015-03-09 23:25:27 +00:00
stack.push(val)
2015-01-19 10:18:34 +00:00
case MSTORE:
2015-03-09 23:25:27 +00:00
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
2015-03-16 10:27:38 +00:00
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
2015-01-19 10:18:34 +00:00
case MSTORE8:
2015-03-19 21:45:03 +00:00
off, val := stack.pop().Int64(), stack.pop().Int64()
2015-01-19 10:18:34 +00:00
2015-03-19 21:45:03 +00:00
mem.store[off] = byte(val & 0xff)
2015-01-19 10:18:34 +00:00
case SLOAD:
2015-03-16 17:42:18 +00:00
loc := common.BigToHash(stack.pop())
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
2015-03-09 23:25:27 +00:00
stack.push(val)
2015-01-19 10:18:34 +00:00
case SSTORE:
2015-03-16 17:42:18 +00:00
loc := common.BigToHash(stack.pop())
val := stack.pop()
statedb.SetState(context.Address(), loc, val)
2015-01-19 10:18:34 +00:00
case JUMP:
2015-03-27 15:09:57 +00:00
if err := jump(pc, stack.pop()); err != nil {
return nil, err
}
2015-01-19 10:18:34 +00:00
continue
case JUMPI:
2015-03-09 23:25:27 +00:00
pos, cond := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
if cond.Cmp(common.BigTrue) >= 0 {
2015-03-27 15:09:57 +00:00
if err := jump(pc, pos); err != nil {
return nil, err
}
2015-01-19 10:18:34 +00:00
continue
}
case JUMPDEST:
case PC:
stack.push(new(big.Int).SetUint64(pc))
2015-01-19 10:18:34 +00:00
case MSIZE:
2015-03-09 23:25:27 +00:00
stack.push(big.NewInt(int64(mem.Len())))
2015-01-19 10:18:34 +00:00
case GAS:
2015-03-09 23:25:27 +00:00
stack.push(context.Gas)
2015-02-04 15:39:02 +00:00
2015-01-19 10:18:34 +00:00
case CREATE:
var (
2015-03-09 23:25:27 +00:00
value = stack.pop()
offset, size = stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(context.Gas)
2015-03-16 17:42:18 +00:00
addr common.Address
2015-01-19 10:18:34 +00:00
)
context.UseGas(context.Gas)
2015-03-24 14:23:16 +00:00
ret, suberr, ref := self.env.Create(context, input, gas, price, value)
2015-01-19 10:18:34 +00:00
if suberr != nil {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
} else {
// gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, params.CreateDataGas)
2015-01-19 10:18:34 +00:00
if context.UseGas(dataGas) {
ref.SetCode(ret)
}
addr = ref.Address()
2015-03-16 17:42:18 +00:00
stack.push(addr.Big())
2015-01-19 10:18:34 +00:00
}
case CALL, CALLCODE:
2015-03-09 23:25:27 +00:00
gas := stack.pop()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
2015-02-19 10:09:46 +00:00
value = U256(value)
2015-03-09 23:25:27 +00:00
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
2015-01-19 10:18:34 +00:00
2015-03-16 17:42:18 +00:00
address := common.BigToAddress(addr)
2015-01-19 10:18:34 +00:00
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
2015-03-03 10:56:43 +00:00
if len(value.Bytes()) > 0 {
gas.Add(gas, params.CallStipend)
2015-03-03 10:56:43 +00:00
}
2015-01-19 10:18:34 +00:00
var (
ret []byte
err error
)
if op == CALLCODE {
ret, err = self.env.CallCode(context, address, args, gas, price, value)
2015-01-19 10:18:34 +00:00
} else {
ret, err = self.env.Call(context, address, args, gas, price, value)
2015-01-19 10:18:34 +00:00
}
if err != nil {
2015-03-16 10:27:38 +00:00
stack.push(common.BigFalse)
2015-01-19 10:18:34 +00:00
} else {
2015-03-16 10:27:38 +00:00
stack.push(common.BigTrue)
2015-01-19 10:18:34 +00:00
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
2015-01-19 10:18:34 +00:00
case RETURN:
2015-03-09 23:25:27 +00:00
offset, size := stack.pop(), stack.pop()
ret := mem.GetPtr(offset.Int64(), size.Int64())
2015-01-19 10:18:34 +00:00
return context.Return(ret), nil
case SUICIDE:
2015-03-16 17:42:18 +00:00
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
2015-01-19 10:18:34 +00:00
balance := statedb.GetBalance(context.Address())
receiver.AddBalance(balance)
2015-03-09 10:28:35 +00:00
2015-01-19 10:18:34 +00:00
statedb.Delete(context.Address())
fallthrough
case STOP: // Stop the context
return context.Return(nil), nil
default:
2015-03-27 15:09:57 +00:00
return nil, fmt.Errorf("Invalid opcode %x", op)
2015-01-19 10:18:34 +00:00
}
pc++
2015-01-19 10:18:34 +00:00
}
}
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *Stack) (*big.Int, *big.Int, error) {
2015-03-02 15:32:02 +00:00
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
)
2015-03-27 15:09:57 +00:00
err := baseCheck(op, stack, gas)
if err != nil {
return nil, nil, err
}
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
// stack Check, memory resize & gas phase
2015-01-19 10:18:34 +00:00
switch op {
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
2015-03-27 15:09:57 +00:00
err := stack.require(n)
if err != nil {
return nil, nil, err
}
2015-03-03 10:11:11 +00:00
gas.Set(GasFastestStep)
2015-01-19 10:18:34 +00:00
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
2015-03-27 15:09:57 +00:00
err := stack.require(n)
if err != nil {
return nil, nil, err
}
2015-03-03 10:11:11 +00:00
gas.Set(GasFastestStep)
2015-01-19 10:18:34 +00:00
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
2015-03-27 15:09:57 +00:00
err := stack.require(n + 2)
if err != nil {
return nil, nil, err
}
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
2015-03-02 15:32:02 +00:00
gas.Add(gas, params.LogGas)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), params.LogTopicGas))
gas.Add(gas, new(big.Int).Mul(mSize, params.LogDataGas))
2015-01-19 10:18:34 +00:00
newMemSize = calcMemSize(mStart, mSize)
case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
2015-01-19 10:18:34 +00:00
case SSTORE:
2015-03-27 15:09:57 +00:00
err := stack.require(2)
if err != nil {
return nil, nil, err
}
2015-01-19 10:18:34 +00:00
2015-03-02 15:32:02 +00:00
var g *big.Int
2015-03-09 23:25:27 +00:00
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
2015-03-16 17:42:18 +00:00
val := statedb.GetState(context.Address(), common.BigToHash(x))
2015-01-19 10:18:34 +00:00
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
g = params.SstoreSetGas
2015-01-19 10:18:34 +00:00
} else if len(val) > 0 && len(y.Bytes()) == 0 {
statedb.Refund(self.env.Origin(), params.SstoreRefundGas)
2015-01-19 10:18:34 +00:00
g = params.SstoreClearGas
2015-01-19 10:18:34 +00:00
} else {
// non 0 => non 0 (or 0 => 0)
g = params.SstoreClearGas
2015-01-19 10:18:34 +00:00
}
2015-03-02 15:32:02 +00:00
gas.Set(g)
2015-03-09 10:28:35 +00:00
case SUICIDE:
if !statedb.IsDeleted(context.Address()) {
statedb.Refund(self.env.Origin(), params.SuicideRefundGas)
2015-03-09 10:28:35 +00:00
}
2015-01-19 10:18:34 +00:00
case MLOAD:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(32))
2015-01-19 10:18:34 +00:00
case MSTORE8:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(1))
2015-03-02 16:55:45 +00:00
case MSTORE:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), u256(32))
2015-01-19 10:18:34 +00:00
case RETURN:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
2015-01-19 10:18:34 +00:00
case SHA3:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
2015-03-02 15:32:02 +00:00
case CALLDATACOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
2015-03-02 15:32:02 +00:00
case CODECOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, params.CopyGas))
2015-03-02 15:32:02 +00:00
case EXTCODECOPY:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
2015-03-02 15:32:02 +00:00
2015-03-09 23:25:27 +00:00
words := toWordSize(stack.data[stack.len()-4])
gas.Add(gas, words.Mul(words, params.CopyGas))
2015-03-03 12:29:52 +00:00
2015-03-02 15:32:02 +00:00
case CREATE:
2015-03-09 23:25:27 +00:00
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
2015-01-19 10:18:34 +00:00
case CALL, CALLCODE:
2015-03-09 23:25:27 +00:00
gas.Add(gas, stack.data[stack.len()-1])
2015-03-02 15:32:02 +00:00
if op == CALL {
2015-03-16 17:42:18 +00:00
if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
gas.Add(gas, params.CallNewAccountGas)
2015-03-02 15:32:02 +00:00
}
2015-03-03 12:29:52 +00:00
}
2015-03-02 15:32:02 +00:00
2015-03-09 23:25:27 +00:00
if len(stack.data[stack.len()-3].Bytes()) > 0 {
gas.Add(gas, params.CallValueTransferGas)
2015-03-02 15:32:02 +00:00
}
2015-01-19 10:18:34 +00:00
2015-03-09 23:25:27 +00:00
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
2015-01-19 10:18:34 +00:00
2015-03-16 10:27:38 +00:00
newMemSize = common.BigMax(x, y)
2015-01-19 10:18:34 +00:00
}
2015-03-16 10:27:38 +00:00
if newMemSize.Cmp(common.Big0) > 0 {
2015-03-03 10:56:43 +00:00
newMemSizeWords := toWordSize(newMemSize)
newMemSize.Mul(newMemSizeWords, u256(32))
2015-01-19 10:18:34 +00:00
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
2015-03-03 10:11:11 +00:00
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
2015-03-16 10:27:38 +00:00
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
linCoef := new(big.Int).Mul(oldSize, params.MemoryGas)
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
2015-03-03 10:11:11 +00:00
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
2015-03-16 10:27:38 +00:00
pow.Exp(newMemSizeWords, common.Big2, Zero)
linCoef = new(big.Int).Mul(newMemSizeWords, params.MemoryGas)
quadCoef = new(big.Int).Div(pow, params.QuadCoeffDiv)
2015-03-03 10:11:11 +00:00
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
fee := new(big.Int).Sub(newTotalFee, oldTotalFee)
gas.Add(gas, fee)
2015-01-19 10:18:34 +00:00
}
}
2015-01-19 10:18:34 +00:00
2015-03-27 15:09:57 +00:00
return newMemSize, gas, nil
2014-09-14 23:11:01 +00:00
}
2015-01-19 10:18:34 +00:00
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)
return context.Return(ret), nil
} else {
tmp := new(big.Int).Set(context.Gas)
2015-03-27 15:09:57 +00:00
return nil, OOG(gas, tmp)
2015-01-19 10:18:34 +00:00
}
}
func (self *Vm) log(pc uint64, op OpCode, gas *big.Int, memory *Memory, stack *Stack, context *Context) {
if Debug {
mem := make([]byte, len(memory.Data()))
copy(mem, memory.Data())
stck := make([]*big.Int, len(stack.Data()))
copy(stck, stack.Data())
object := context.self.(*state.StateObject)
storage := make(map[common.Hash][]byte)
object.EachStorage(func(k, v []byte) {
storage[common.BytesToHash(k)] = v
})
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), mem, stck, storage})
2015-01-19 10:18:34 +00:00
}
2014-09-19 11:19:19 +00:00
}
2014-10-14 11:37:26 +00:00
2015-01-19 10:18:34 +00:00
func (self *Vm) Env() Environment {
return self.env
}