2014-10-18 14:31:20 +03:00
|
|
|
package vm
|
2014-07-22 12:54:48 +03:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
2014-07-22 12:54:48 +03:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2015-03-23 17:59:09 +02:00
|
|
|
"github.com/ethereum/go-ethereum/core/state"
|
2015-03-23 22:48:31 +02:00
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2015-04-02 06:17:15 +03:00
|
|
|
"github.com/ethereum/go-ethereum/params"
|
2015-01-19 12:18:34 +02:00
|
|
|
)
|
2014-10-15 18:12:26 +03:00
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// Vm implements VirtualMachine
|
2014-07-22 12:54:48 +03:00
|
|
|
type Vm struct {
|
2015-01-19 12:18:34 +02:00
|
|
|
env Environment
|
|
|
|
|
|
|
|
err error
|
2015-02-28 21:14:01 +02:00
|
|
|
// For logging
|
|
|
|
debug bool
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
BreakPoints []int64
|
|
|
|
Stepping bool
|
|
|
|
Fn string
|
|
|
|
|
|
|
|
Recoverable bool
|
2015-03-28 21:03:25 +02:00
|
|
|
|
|
|
|
// Will be called before the vm returns
|
|
|
|
After func(*Context, error)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// New returns a new Virtual Machine
|
2015-01-20 16:49:12 +02:00
|
|
|
func New(env Environment) *Vm {
|
2015-06-10 13:23:49 +03:00
|
|
|
return &Vm{env: env, debug: Debug, Recoverable: true}
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// Run loops and evaluates the contract's code with the given input data
|
|
|
|
func (self *Vm) Run(context *Context, input []byte) (ret []byte, err error) {
|
2015-01-19 12:18:34 +02:00
|
|
|
self.env.SetDepth(self.env.Depth() + 1)
|
2015-03-23 22:48:31 +02:00
|
|
|
defer self.env.SetDepth(self.env.Depth() - 1)
|
|
|
|
|
2015-03-13 14:44:15 +02:00
|
|
|
var (
|
|
|
|
caller = context.caller
|
|
|
|
code = context.Code
|
|
|
|
value = context.value
|
|
|
|
price = context.Price
|
|
|
|
)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-27 17:53:05 +02: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 17:09:57 +02:00
|
|
|
defer func() {
|
2015-03-28 21:03:25 +02:00
|
|
|
if self.After != nil {
|
|
|
|
self.After(context, err)
|
|
|
|
}
|
|
|
|
|
2015-03-27 17:09:57 +02:00
|
|
|
if err != nil {
|
2015-06-10 13:23:49 +03:00
|
|
|
|
2015-03-27 17:09:57 +02: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 12:18:34 +02:00
|
|
|
|
2015-03-17 12:19:23 +02:00
|
|
|
if context.CodeAddr != nil {
|
|
|
|
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
|
2015-06-10 18:40:13 +03:00
|
|
|
return self.RunPrecompiled(p, input, context)
|
2015-03-17 12:19:23 +02:00
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-05-29 15:58:57 +03:00
|
|
|
// Don't bother with the execution if there's no code.
|
|
|
|
if len(code) == 0 {
|
|
|
|
return context.Return(nil), nil
|
|
|
|
}
|
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
var (
|
2015-06-10 18:40:13 +03:00
|
|
|
op OpCode // current opcode
|
|
|
|
codehash = crypto.Sha3Hash(code) // codehash is used when doing jump dest caching
|
|
|
|
mem = NewMemory() // bound memory
|
2015-06-10 18:45:21 +03:00
|
|
|
stack = newstack() // local stack
|
2015-06-10 18:40:13 +03:00
|
|
|
pc = uint64(0) // program counter
|
|
|
|
statedb = self.env.State() // current state
|
|
|
|
|
|
|
|
// jump evaluates and checks whether the given jump destination is a valid one
|
|
|
|
// if valid move the `pc` otherwise return an error.
|
2015-06-10 11:44:46 +03:00
|
|
|
jump = func(from uint64, to *big.Int) error {
|
2015-05-29 15:40:45 +03:00
|
|
|
if !context.jumpdests.has(codehash, code, to) {
|
2015-06-10 11:44:46 +03:00
|
|
|
nop := context.GetOp(to.Uint64())
|
2015-03-28 21:30:16 +02:00
|
|
|
return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-06-10 11:44:46 +03:00
|
|
|
pc = to.Uint64()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-27 17:09:57 +02:00
|
|
|
return nil
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
for {
|
|
|
|
// The base for all big integer arithmetic
|
|
|
|
base := new(big.Int)
|
|
|
|
|
|
|
|
// Get the memory location of pc
|
|
|
|
op = context.GetOp(pc)
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// calculate the new memory size and gas price for the current executing opcode
|
2015-03-27 17:09:57 +02:00
|
|
|
newMemSize, gas, err := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-06-10 20:56:40 +03:00
|
|
|
self.log(pc, op, context.Gas, gas, mem, stack, context)
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// Use the calculated gas. When insufficient gas is present, use all gas and return an
|
|
|
|
// Out Of Gas error
|
2015-01-19 12:18:34 +02:00
|
|
|
if !context.UseGas(gas) {
|
|
|
|
tmp := new(big.Int).Set(context.Gas)
|
|
|
|
|
|
|
|
context.UseGas(context.Gas)
|
|
|
|
|
|
|
|
return context.Return(nil), OOG(gas, tmp)
|
|
|
|
}
|
2015-06-10 18:40:13 +03:00
|
|
|
// Resize the memory calculated previously
|
2015-01-19 12:18:34 +02:00
|
|
|
mem.Resize(newMemSize.Uint64())
|
|
|
|
|
|
|
|
switch op {
|
|
|
|
case ADD:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
base.Add(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
// pop result back on the stack
|
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case SUB:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
base.Sub(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
// pop result back on the stack
|
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case MUL:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
base.Mul(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
// pop result back on the stack
|
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case DIV:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if y.Cmp(common.Big0) != 0 {
|
2015-01-19 12:18:34 +02:00
|
|
|
base.Div(x, y)
|
|
|
|
}
|
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
// pop result back on the stack
|
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case SDIV:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := S256(stack.pop()), S256(stack.pop())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if y.Cmp(common.Big0) == 0 {
|
|
|
|
base.Set(common.Big0)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
|
|
|
n := new(big.Int)
|
2015-03-16 12:27:38 +02:00
|
|
|
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
2015-01-19 12:18:34 +02:00
|
|
|
n.SetInt64(-1)
|
|
|
|
} else {
|
|
|
|
n.SetInt64(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
|
|
|
|
|
|
|
|
U256(base)
|
|
|
|
}
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case MOD:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if y.Cmp(common.Big0) == 0 {
|
|
|
|
base.Set(common.Big0)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
|
|
|
base.Mod(x, y)
|
|
|
|
}
|
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case SMOD:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := S256(stack.pop()), S256(stack.pop())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if y.Cmp(common.Big0) == 0 {
|
|
|
|
base.Set(common.Big0)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
|
|
|
n := new(big.Int)
|
2015-03-16 12:27:38 +02:00
|
|
|
if x.Cmp(common.Big0) < 0 {
|
2015-01-19 12:18:34 +02:00
|
|
|
n.SetInt64(-1)
|
|
|
|
} else {
|
|
|
|
n.SetInt64(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
|
|
|
|
|
|
|
|
U256(base)
|
|
|
|
}
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case EXP:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
base.Exp(x, y, Pow256)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
U256(base)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case SIGNEXTEND:
|
2015-03-12 20:41:56 +02:00
|
|
|
back := stack.pop()
|
|
|
|
if back.Cmp(big.NewInt(31)) < 0 {
|
|
|
|
bit := uint(back.Uint64()*8 + 7)
|
2015-03-10 01:25:27 +02:00
|
|
|
num := stack.pop()
|
2015-03-16 12:27:38 +02:00
|
|
|
mask := new(big.Int).Lsh(common.Big1, bit)
|
|
|
|
mask.Sub(mask, common.Big1)
|
|
|
|
if common.BitTest(num, int(bit)) {
|
2015-01-19 12:18:34 +02:00
|
|
|
num.Or(num, mask.Not(mask))
|
|
|
|
} else {
|
|
|
|
num.And(num, mask)
|
|
|
|
}
|
|
|
|
|
|
|
|
num = U256(num)
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(num)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
case NOT:
|
2015-03-12 19:22:35 +02:00
|
|
|
stack.push(U256(new(big.Int).Not(stack.pop())))
|
2015-01-19 12:18:34 +02:00
|
|
|
case LT:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-06-10 13:23:49 +03:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
// x < y
|
2015-03-10 01:25:27 +02:00
|
|
|
if x.Cmp(y) < 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
case GT:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
// x > y
|
2015-03-10 01:25:27 +02:00
|
|
|
if x.Cmp(y) > 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case SLT:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := S256(stack.pop()), S256(stack.pop())
|
2015-06-10 13:23:49 +03:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
// x < y
|
2015-03-10 01:25:27 +02:00
|
|
|
if x.Cmp(S256(y)) < 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
case SGT:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := S256(stack.pop()), S256(stack.pop())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
// x > y
|
2015-03-10 01:25:27 +02:00
|
|
|
if x.Cmp(y) > 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case EQ:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
// x == y
|
|
|
|
if x.Cmp(y) == 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
case ISZERO:
|
2015-03-10 01:25:27 +02:00
|
|
|
x := stack.pop()
|
2015-03-16 12:27:38 +02:00
|
|
|
if x.Cmp(common.BigFalse) > 0 {
|
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case AND:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base.And(x, y))
|
2015-01-19 12:18:34 +02:00
|
|
|
case OR:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base.Or(x, y))
|
2015-01-19 12:18:34 +02:00
|
|
|
case XOR:
|
2015-03-10 01:25:27 +02:00
|
|
|
x, y := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base.Xor(x, y))
|
2015-01-19 12:18:34 +02:00
|
|
|
case BYTE:
|
2015-03-10 01:25:27 +02:00
|
|
|
th, val := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
if th.Cmp(big.NewInt(32)) < 0 {
|
2015-03-16 12:27:38 +02:00
|
|
|
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
base.Set(byt)
|
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
base.Set(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case ADDMOD:
|
2015-03-10 01:25:27 +02:00
|
|
|
x := stack.pop()
|
|
|
|
y := stack.pop()
|
|
|
|
z := stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-12 19:22:35 +02:00
|
|
|
if z.Cmp(Zero) > 0 {
|
2015-03-13 14:44:15 +02:00
|
|
|
add := new(big.Int).Add(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
base.Mod(add, z)
|
|
|
|
|
2015-03-12 19:22:35 +02:00
|
|
|
base = U256(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
case MULMOD:
|
2015-03-10 01:25:27 +02:00
|
|
|
x := stack.pop()
|
|
|
|
y := stack.pop()
|
|
|
|
z := stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-13 14:44:15 +02:00
|
|
|
if z.Cmp(Zero) > 0 {
|
|
|
|
mul := new(big.Int).Mul(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
base.Mod(mul, z)
|
|
|
|
|
|
|
|
U256(base)
|
|
|
|
}
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(base)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case SHA3:
|
2015-03-13 00:26:58 +02:00
|
|
|
offset, size := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
|
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigD(data))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case ADDRESS:
|
2015-03-16 19:42:18 +02:00
|
|
|
stack.push(common.Bytes2Big(context.Address().Bytes()))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case BALANCE:
|
2015-03-16 19:42:18 +02:00
|
|
|
addr := common.BigToAddress(stack.pop())
|
2015-03-12 23:29:10 +02:00
|
|
|
balance := statedb.GetBalance(addr)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(balance)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case ORIGIN:
|
|
|
|
origin := self.env.Origin()
|
|
|
|
|
2015-03-16 19:42:18 +02:00
|
|
|
stack.push(origin.Big())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CALLER:
|
|
|
|
caller := context.caller.Address()
|
2015-03-16 19:42:18 +02:00
|
|
|
stack.push(common.Bytes2Big(caller.Bytes()))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CALLVALUE:
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(value)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CALLDATALOAD:
|
2015-06-10 18:40:13 +03:00
|
|
|
data := getData(input, stack.pop(), common.Big32)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-28 21:30:16 +02:00
|
|
|
stack.push(common.Bytes2Big(data))
|
2015-01-19 12:18:34 +02:00
|
|
|
case CALLDATASIZE:
|
2015-06-10 18:40:13 +03:00
|
|
|
l := int64(len(input))
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(big.NewInt(l))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CALLDATACOPY:
|
|
|
|
var (
|
2015-03-19 16:06:56 +02:00
|
|
|
mOff = stack.pop()
|
|
|
|
cOff = stack.pop()
|
|
|
|
l = stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
)
|
2015-06-10 18:40:13 +03:00
|
|
|
data := getData(input, cOff, l)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-19 16:06:56 +02:00
|
|
|
mem.Set(mOff.Uint64(), l.Uint64(), data)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CODESIZE, EXTCODESIZE:
|
|
|
|
var code []byte
|
|
|
|
if op == EXTCODESIZE {
|
2015-03-16 19:42:18 +02:00
|
|
|
addr := common.BigToAddress(stack.pop())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
code = statedb.GetCode(addr)
|
|
|
|
} else {
|
|
|
|
code = context.Code
|
|
|
|
}
|
|
|
|
|
|
|
|
l := big.NewInt(int64(len(code)))
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(l)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case CODECOPY, EXTCODECOPY:
|
|
|
|
var code []byte
|
|
|
|
if op == EXTCODECOPY {
|
2015-03-16 19:42:18 +02:00
|
|
|
addr := common.BigToAddress(stack.pop())
|
|
|
|
code = statedb.GetCode(addr)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
|
|
|
code = context.Code
|
|
|
|
}
|
2015-03-19 16:06:56 +02:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
var (
|
2015-03-19 16:06:56 +02:00
|
|
|
mOff = stack.pop()
|
|
|
|
cOff = stack.pop()
|
|
|
|
l = stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
)
|
|
|
|
|
2015-03-19 23:45:03 +02:00
|
|
|
codeCopy := getData(code, cOff, l)
|
2015-03-19 16:06:56 +02:00
|
|
|
|
|
|
|
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case GASPRICE:
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(context.Price)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case BLOCKHASH:
|
2015-03-10 01:25:27 +02:00
|
|
|
num := stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
|
2015-01-19 12:18:34 +02:00
|
|
|
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
|
2015-03-17 12:19:23 +02:00
|
|
|
stack.push(self.env.GetHash(num.Uint64()).Big())
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.Big0)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case COINBASE:
|
|
|
|
coinbase := self.env.Coinbase()
|
|
|
|
|
2015-03-17 12:19:23 +02:00
|
|
|
stack.push(coinbase.Big())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case TIMESTAMP:
|
|
|
|
time := self.env.Time()
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(big.NewInt(time))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case NUMBER:
|
|
|
|
number := self.env.BlockNumber()
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(U256(number))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case DIFFICULTY:
|
|
|
|
difficulty := self.env.Difficulty()
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(difficulty)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case GASLIMIT:
|
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(self.env.GasLimit())
|
2015-01-19 12:18:34 +02: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:
|
2015-06-10 11:44:46 +03:00
|
|
|
size := uint64(op - PUSH1 + 1)
|
|
|
|
byts := getData(code, new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
|
2015-03-10 01:25:27 +02:00
|
|
|
// push value to stack
|
2015-03-28 21:30:16 +02:00
|
|
|
stack.push(common.Bytes2Big(byts))
|
2015-06-10 11:44:46 +03:00
|
|
|
pc += size
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case POP:
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.pop()
|
2015-01-19 12:18:34 +02: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-10 01:25:27 +02:00
|
|
|
stack.dup(n)
|
2015-01-19 12:18:34 +02: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-10 01:25:27 +02:00
|
|
|
stack.swap(n)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
|
|
|
n := int(op - LOG0)
|
2015-03-17 00:10:26 +02:00
|
|
|
topics := make([]common.Hash, n)
|
2015-03-10 01:25:27 +02:00
|
|
|
mStart, mSize := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
for i := 0; i < n; i++ {
|
2015-05-26 13:42:33 +03:00
|
|
|
topics[i] = common.BigToHash(stack.pop())
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
data := mem.Get(mStart.Int64(), mSize.Int64())
|
2015-04-08 18:14:58 +03:00
|
|
|
log := state.NewLog(context.Address(), topics, data, self.env.BlockNumber().Uint64())
|
2015-01-19 12:18:34 +02:00
|
|
|
self.env.AddLog(log)
|
|
|
|
|
|
|
|
case MLOAD:
|
2015-03-10 01:25:27 +02:00
|
|
|
offset := stack.pop()
|
2015-03-16 12:27:38 +02:00
|
|
|
val := common.BigD(mem.Get(offset.Int64(), 32))
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(val)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-05-26 13:42:33 +03:00
|
|
|
case MSTORE:
|
2015-03-10 01:25:27 +02:00
|
|
|
// pop value of the stack
|
|
|
|
mStart, val := stack.pop(), stack.pop()
|
2015-03-16 12:27:38 +02:00
|
|
|
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case MSTORE8:
|
2015-03-19 23:45:03 +02:00
|
|
|
off, val := stack.pop().Int64(), stack.pop().Int64()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-19 23:45:03 +02:00
|
|
|
mem.store[off] = byte(val & 0xff)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case SLOAD:
|
2015-03-16 19:42:18 +02:00
|
|
|
loc := common.BigToHash(stack.pop())
|
|
|
|
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(val)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case SSTORE:
|
2015-03-16 19:42:18 +02:00
|
|
|
loc := common.BigToHash(stack.pop())
|
|
|
|
val := stack.pop()
|
|
|
|
|
|
|
|
statedb.SetState(context.Address(), loc, val)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
case JUMP:
|
2015-03-27 17:09:57 +02:00
|
|
|
if err := jump(pc, stack.pop()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
continue
|
|
|
|
case JUMPI:
|
2015-03-10 01:25:27 +02:00
|
|
|
pos, cond := stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if cond.Cmp(common.BigTrue) >= 0 {
|
2015-03-27 17:09:57 +02:00
|
|
|
if err := jump(pc, pos); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
case JUMPDEST:
|
|
|
|
case PC:
|
2015-06-10 11:44:46 +03:00
|
|
|
stack.push(new(big.Int).SetUint64(pc))
|
2015-01-19 12:18:34 +02:00
|
|
|
case MSIZE:
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(big.NewInt(int64(mem.Len())))
|
2015-01-19 12:18:34 +02:00
|
|
|
case GAS:
|
2015-03-10 01:25:27 +02:00
|
|
|
stack.push(context.Gas)
|
2015-02-04 17:39:02 +02:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
case CREATE:
|
|
|
|
|
|
|
|
var (
|
2015-03-10 01:25:27 +02:00
|
|
|
value = stack.pop()
|
|
|
|
offset, size = stack.pop(), stack.pop()
|
2015-01-19 12:18:34 +02:00
|
|
|
input = mem.Get(offset.Int64(), size.Int64())
|
|
|
|
gas = new(big.Int).Set(context.Gas)
|
2015-03-16 19:42:18 +02:00
|
|
|
addr common.Address
|
2015-01-19 12:18:34 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
context.UseGas(context.Gas)
|
2015-03-24 16:23:16 +02:00
|
|
|
ret, suberr, ref := self.env.Create(context, input, gas, price, value)
|
2015-01-19 12:18:34 +02:00
|
|
|
if suberr != nil {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// gas < len(ret) * CreateDataGas == NO_CODE
|
|
|
|
dataGas := big.NewInt(int64(len(ret)))
|
2015-04-02 06:17:15 +03:00
|
|
|
dataGas.Mul(dataGas, params.CreateDataGas)
|
2015-01-19 12:18:34 +02:00
|
|
|
if context.UseGas(dataGas) {
|
|
|
|
ref.SetCode(ret)
|
|
|
|
}
|
|
|
|
addr = ref.Address()
|
|
|
|
|
2015-03-16 19:42:18 +02:00
|
|
|
stack.push(addr.Big())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
case CALL, CALLCODE:
|
2015-03-10 01:25:27 +02:00
|
|
|
gas := stack.pop()
|
|
|
|
// pop gas and value of the stack.
|
|
|
|
addr, value := stack.pop(), stack.pop()
|
2015-02-19 12:09:46 +02:00
|
|
|
value = U256(value)
|
2015-03-10 01:25:27 +02: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 12:18:34 +02:00
|
|
|
|
2015-03-16 19:42:18 +02:00
|
|
|
address := common.BigToAddress(addr)
|
2015-02-03 06:01:10 +02:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
// Get the arguments from the memory
|
|
|
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
|
|
|
|
2015-03-03 12:56:43 +02:00
|
|
|
if len(value.Bytes()) > 0 {
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, params.CallStipend)
|
2015-03-03 12:56:43 +02:00
|
|
|
}
|
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
var (
|
|
|
|
ret []byte
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if op == CALLCODE {
|
2015-02-03 06:01:10 +02:00
|
|
|
ret, err = self.env.CallCode(context, address, args, gas, price, value)
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
2015-02-03 06:01:10 +02:00
|
|
|
ret, err = self.env.Call(context, address, args, gas, price, value)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigFalse)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
} else {
|
2015-03-16 12:27:38 +02:00
|
|
|
stack.push(common.BigTrue)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
|
|
|
}
|
2015-06-10 13:23:49 +03:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
case RETURN:
|
2015-03-10 01:25:27 +02:00
|
|
|
offset, size := stack.pop(), stack.pop()
|
2015-05-19 18:26:38 +03:00
|
|
|
ret := mem.GetPtr(offset.Int64(), size.Int64())
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
return context.Return(ret), nil
|
|
|
|
case SUICIDE:
|
2015-03-16 19:42:18 +02:00
|
|
|
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
|
2015-01-19 12:18:34 +02:00
|
|
|
balance := statedb.GetBalance(context.Address())
|
|
|
|
|
2015-02-26 19:39:05 +02:00
|
|
|
receiver.AddBalance(balance)
|
2015-03-09 12:28:35 +02:00
|
|
|
|
2015-01-19 12:18:34 +02:00
|
|
|
statedb.Delete(context.Address())
|
|
|
|
|
|
|
|
fallthrough
|
|
|
|
case STOP: // Stop the context
|
|
|
|
|
|
|
|
return context.Return(nil), nil
|
|
|
|
default:
|
|
|
|
|
2015-03-27 17:09:57 +02:00
|
|
|
return nil, fmt.Errorf("Invalid opcode %x", op)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-06-10 11:44:46 +03:00
|
|
|
pc++
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
}
|
2014-07-22 12:54:48 +03:00
|
|
|
}
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// calculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
|
|
|
|
// the operation. This does not reduce gas or resizes the memory.
|
2015-06-10 18:45:21 +03: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 17:32:02 +02:00
|
|
|
var (
|
|
|
|
gas = new(big.Int)
|
|
|
|
newMemSize *big.Int = new(big.Int)
|
|
|
|
)
|
2015-03-27 17:09:57 +02:00
|
|
|
err := baseCheck(op, stack, gas)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
// stack Check, memory resize & gas phase
|
2015-01-19 12:18:34 +02: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 17:09:57 +02:00
|
|
|
err := stack.require(n)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-03-03 12:11:11 +02:00
|
|
|
gas.Set(GasFastestStep)
|
2015-01-19 12:18:34 +02: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 17:09:57 +02:00
|
|
|
err := stack.require(n)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-03-03 12:11:11 +02:00
|
|
|
gas.Set(GasFastestStep)
|
2015-01-19 12:18:34 +02:00
|
|
|
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
|
|
|
n := int(op - LOG0)
|
2015-03-27 17:09:57 +02:00
|
|
|
err := stack.require(n + 2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
2015-03-02 17:32:02 +02:00
|
|
|
|
2015-04-02 06:17:15 +03: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 12:18:34 +02:00
|
|
|
|
|
|
|
newMemSize = calcMemSize(mStart, mSize)
|
|
|
|
case EXP:
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
|
2015-01-19 12:18:34 +02:00
|
|
|
case SSTORE:
|
2015-03-27 17:09:57 +02:00
|
|
|
err := stack.require(2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-02 17:32:02 +02:00
|
|
|
var g *big.Int
|
2015-03-10 01:25:27 +02:00
|
|
|
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
|
2015-03-16 19:42:18 +02:00
|
|
|
val := statedb.GetState(context.Address(), common.BigToHash(x))
|
2015-01-19 12:18:34 +02:00
|
|
|
if len(val) == 0 && len(y.Bytes()) > 0 {
|
|
|
|
// 0 => non 0
|
2015-04-02 06:17:15 +03:00
|
|
|
g = params.SstoreSetGas
|
2015-01-19 12:18:34 +02:00
|
|
|
} else if len(val) > 0 && len(y.Bytes()) == 0 {
|
2015-04-02 06:17:15 +03:00
|
|
|
statedb.Refund(self.env.Origin(), params.SstoreRefundGas)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-04-02 06:17:15 +03:00
|
|
|
g = params.SstoreClearGas
|
2015-01-19 12:18:34 +02:00
|
|
|
} else {
|
|
|
|
// non 0 => non 0 (or 0 => 0)
|
2015-04-02 06:17:15 +03:00
|
|
|
g = params.SstoreClearGas
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
2015-03-02 17:32:02 +02:00
|
|
|
gas.Set(g)
|
2015-03-09 12:28:35 +02:00
|
|
|
case SUICIDE:
|
|
|
|
if !statedb.IsDeleted(context.Address()) {
|
2015-04-02 06:17:15 +03:00
|
|
|
statedb.Refund(self.env.Origin(), params.SuicideRefundGas)
|
2015-03-09 12:28:35 +02:00
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
case MLOAD:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), u256(32))
|
2015-01-19 12:18:34 +02:00
|
|
|
case MSTORE8:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), u256(1))
|
2015-03-02 18:55:45 +02:00
|
|
|
case MSTORE:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), u256(32))
|
2015-01-19 12:18:34 +02:00
|
|
|
case RETURN:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
2015-01-19 12:18:34 +02:00
|
|
|
case SHA3:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
words := toWordSize(stack.data[stack.len()-2])
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, words.Mul(words, params.Sha3WordGas))
|
2015-03-02 17:32:02 +02:00
|
|
|
case CALLDATACOPY:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
words := toWordSize(stack.data[stack.len()-3])
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, words.Mul(words, params.CopyGas))
|
2015-03-02 17:32:02 +02:00
|
|
|
case CODECOPY:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
words := toWordSize(stack.data[stack.len()-3])
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, words.Mul(words, params.CopyGas))
|
2015-03-02 17:32:02 +02:00
|
|
|
case EXTCODECOPY:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
|
2015-03-02 17:32:02 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
words := toWordSize(stack.data[stack.len()-4])
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, words.Mul(words, params.CopyGas))
|
2015-03-03 14:29:52 +02:00
|
|
|
|
2015-03-02 17:32:02 +02:00
|
|
|
case CREATE:
|
2015-03-10 01:25:27 +02:00
|
|
|
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
|
2015-01-19 12:18:34 +02:00
|
|
|
case CALL, CALLCODE:
|
2015-03-10 01:25:27 +02:00
|
|
|
gas.Add(gas, stack.data[stack.len()-1])
|
2015-03-02 17:32:02 +02:00
|
|
|
|
|
|
|
if op == CALL {
|
2015-03-16 19:42:18 +02:00
|
|
|
if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, params.CallNewAccountGas)
|
2015-03-02 17:32:02 +02:00
|
|
|
}
|
2015-03-03 14:29:52 +02:00
|
|
|
}
|
2015-03-02 17:32:02 +02:00
|
|
|
|
2015-03-10 01:25:27 +02:00
|
|
|
if len(stack.data[stack.len()-3].Bytes()) > 0 {
|
2015-04-02 06:17:15 +03:00
|
|
|
gas.Add(gas, params.CallValueTransferGas)
|
2015-03-02 17:32:02 +02:00
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-10 01:25:27 +02: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 12:18:34 +02:00
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
newMemSize = common.BigMax(x, y)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
if newMemSize.Cmp(common.Big0) > 0 {
|
2015-03-03 12:56:43 +02:00
|
|
|
newMemSizeWords := toWordSize(newMemSize)
|
|
|
|
newMemSize.Mul(newMemSizeWords, u256(32))
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
|
2015-03-03 12:11:11 +02:00
|
|
|
oldSize := toWordSize(big.NewInt(int64(mem.Len())))
|
2015-03-16 12:27:38 +02:00
|
|
|
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
|
2015-04-02 06:17:15 +03:00
|
|
|
linCoef := new(big.Int).Mul(oldSize, params.MemoryGas)
|
|
|
|
quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
|
2015-03-03 12:11:11 +02:00
|
|
|
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
|
|
|
|
|
2015-03-16 12:27:38 +02:00
|
|
|
pow.Exp(newMemSizeWords, common.Big2, Zero)
|
2015-04-02 06:17:15 +03:00
|
|
|
linCoef = new(big.Int).Mul(newMemSizeWords, params.MemoryGas)
|
|
|
|
quadCoef = new(big.Int).Div(pow, params.QuadCoeffDiv)
|
2015-03-03 12:11:11 +02:00
|
|
|
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
|
|
|
|
|
2015-04-01 11:53:32 +03:00
|
|
|
fee := new(big.Int).Sub(newTotalFee, oldTotalFee)
|
|
|
|
gas.Add(gas, fee)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
2014-07-22 12:54:48 +03:00
|
|
|
}
|
2015-01-19 12:18:34 +02:00
|
|
|
|
2015-03-27 17:09:57 +02:00
|
|
|
return newMemSize, gas, nil
|
2014-09-15 02:11:01 +03:00
|
|
|
}
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
|
|
|
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, input []byte, context *Context) (ret []byte, err error) {
|
|
|
|
gas := p.Gas(len(input))
|
2015-01-19 12:18:34 +02:00
|
|
|
if context.UseGas(gas) {
|
2015-06-10 18:40:13 +03:00
|
|
|
ret = p.Call(input)
|
2015-01-19 12:18:34 +02:00
|
|
|
|
|
|
|
return context.Return(ret), nil
|
|
|
|
} else {
|
|
|
|
tmp := new(big.Int).Set(context.Gas)
|
|
|
|
|
2015-03-27 17:09:57 +02:00
|
|
|
return nil, OOG(gas, tmp)
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
2014-07-22 12:54:48 +03:00
|
|
|
}
|
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
|
|
|
|
// LOG* opcode.
|
2015-06-10 20:56:40 +03:00
|
|
|
func (self *Vm) log(pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *stack, context *Context) {
|
2015-06-10 13:23:49 +03:00
|
|
|
if Debug {
|
|
|
|
mem := make([]byte, len(memory.Data()))
|
|
|
|
copy(mem, memory.Data())
|
|
|
|
stck := make([]*big.Int, len(stack.Data()))
|
|
|
|
copy(stck, stack.Data())
|
2015-06-10 13:57:37 +03:00
|
|
|
|
|
|
|
object := context.self.(*state.StateObject)
|
|
|
|
storage := make(map[common.Hash][]byte)
|
|
|
|
object.EachStorage(func(k, v []byte) {
|
|
|
|
storage[common.BytesToHash(k)] = v
|
|
|
|
})
|
|
|
|
|
2015-06-10 20:56:40 +03:00
|
|
|
self.env.AddStructLog(StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage})
|
2015-01-19 12:18:34 +02:00
|
|
|
}
|
2014-09-19 14:19:19 +03:00
|
|
|
}
|
2014-10-14 14:37:26 +03:00
|
|
|
|
2015-06-10 18:40:13 +03:00
|
|
|
// Environment returns the current workable state of the VM
|
2015-01-19 12:18:34 +02:00
|
|
|
func (self *Vm) Env() Environment {
|
|
|
|
return self.env
|
|
|
|
}
|