mirror of https://github.com/ethereum/go-ethereum
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.
898 lines
21 KiB
898 lines
21 KiB
10 years ago
|
package vm
|
||
10 years ago
|
|
||
10 years ago
|
import (
|
||
|
"fmt"
|
||
|
"math/big"
|
||
10 years ago
|
|
||
10 years ago
|
"github.com/ethereum/go-ethereum/common"
|
||
10 years ago
|
"github.com/ethereum/go-ethereum/crypto"
|
||
10 years ago
|
"github.com/ethereum/go-ethereum/core/state"
|
||
10 years ago
|
)
|
||
10 years ago
|
|
||
10 years ago
|
type Vm struct {
|
||
10 years ago
|
env Environment
|
||
|
|
||
|
logTy byte
|
||
|
logStr string
|
||
|
|
||
|
err error
|
||
10 years ago
|
// 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
|
||
10 years ago
|
|
||
|
return &Vm{debug: Debug, env: env, logTy: lt, Recoverable: true}
|
||
10 years ago
|
}
|
||
|
|
||
10 years ago
|
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
|
||
10 years ago
|
self.env.SetDepth(self.env.Depth() + 1)
|
||
10 years ago
|
var (
|
||
|
caller = context.caller
|
||
|
code = context.Code
|
||
|
value = context.value
|
||
|
price = context.Price
|
||
|
)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[: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)
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
|
||
10 years ago
|
if context.CodeAddr != nil {
|
||
|
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
|
||
|
return self.RunPrecompiled(p, callData, context)
|
||
|
}
|
||
10 years ago
|
}
|
||
|
|
||
|
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)
|
||
|
|
||
10 years ago
|
if y.Cmp(common.Big0) != 0 {
|
||
10 years ago
|
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)
|
||
|
|
||
10 years ago
|
if y.Cmp(common.Big0) == 0 {
|
||
|
base.Set(common.Big0)
|
||
10 years ago
|
} else {
|
||
|
n := new(big.Int)
|
||
10 years ago
|
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
|
||
10 years ago
|
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)
|
||
|
|
||
10 years ago
|
if y.Cmp(common.Big0) == 0 {
|
||
|
base.Set(common.Big0)
|
||
10 years ago
|
} 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)
|
||
|
|
||
10 years ago
|
if y.Cmp(common.Big0) == 0 {
|
||
|
base.Set(common.Big0)
|
||
10 years ago
|
} else {
|
||
|
n := new(big.Int)
|
||
10 years ago
|
if x.Cmp(common.Big0) < 0 {
|
||
10 years ago
|
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()
|
||
|
if back.Cmp(big.NewInt(31)) < 0 {
|
||
|
bit := uint(back.Uint64()*8 + 7)
|
||
10 years ago
|
num := stack.pop()
|
||
10 years ago
|
mask := new(big.Int).Lsh(common.Big1, bit)
|
||
|
mask.Sub(mask, common.Big1)
|
||
|
if common.BitTest(num, int(bit)) {
|
||
10 years ago
|
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
|
stack.push(U256(new(big.Int).Not(stack.pop())))
|
||
10 years ago
|
//base.Sub(Pow256, stack.pop()).Sub(base, common.Big1)
|
||
10 years ago
|
//base = U256(base)
|
||
|
//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 {
|
||
10 years ago
|
stack.push(common.BigTrue)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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 {
|
||
10 years ago
|
stack.push(common.BigTrue)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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 {
|
||
10 years ago
|
stack.push(common.BigTrue)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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 {
|
||
10 years ago
|
stack.push(common.BigTrue)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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(common.BigTrue)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.BigFalse)
|
||
10 years ago
|
}
|
||
|
case ISZERO:
|
||
10 years ago
|
x := stack.pop()
|
||
10 years ago
|
if x.Cmp(common.BigFalse) > 0 {
|
||
|
stack.push(common.BigFalse)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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 {
|
||
10 years ago
|
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
|
||
10 years ago
|
|
||
|
base.Set(byt)
|
||
|
} else {
|
||
10 years ago
|
base.Set(common.BigFalse)
|
||
10 years ago
|
}
|
||
|
|
||
|
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
|
|
||
10 years ago
|
if z.Cmp(Zero) > 0 {
|
||
10 years ago
|
add := new(big.Int).Add(x, y)
|
||
10 years ago
|
base.Mod(add, z)
|
||
|
|
||
10 years ago
|
base = U256(base)
|
||
10 years ago
|
}
|
||
|
|
||
|
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
|
|
||
10 years ago
|
if z.Cmp(Zero) > 0 {
|
||
|
mul := new(big.Int).Mul(x, y)
|
||
10 years ago
|
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
|
offset, size := stack.pop(), stack.pop()
|
||
10 years ago
|
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
|
||
|
|
||
10 years ago
|
stack.push(common.BigD(data))
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" => (%v) %x", size, data)
|
||
10 years ago
|
// 0x30 range
|
||
|
case ADDRESS:
|
||
10 years ago
|
stack.push(common.Bytes2Big(context.Address().Bytes()))
|
||
10 years ago
|
|
||
|
self.Printf(" => %x", context.Address())
|
||
|
case BALANCE:
|
||
10 years ago
|
addr := common.BigToAddress(stack.pop())
|
||
10 years ago
|
balance := statedb.GetBalance(addr)
|
||
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(origin.Big())
|
||
10 years ago
|
|
||
|
self.Printf(" => %x", origin)
|
||
|
case CALLER:
|
||
|
caller := context.caller.Address()
|
||
10 years ago
|
stack.push(common.Bytes2Big(caller.Bytes()))
|
||
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 {
|
||
10 years ago
|
length := new(big.Int).Add(offset, common.Big32)
|
||
|
length = common.BigMin(length, lenData)
|
||
10 years ago
|
|
||
|
copy(data, callData[offset.Int64():length.Int64()])
|
||
|
}
|
||
|
|
||
|
self.Printf(" => 0x%x", data)
|
||
|
|
||
10 years ago
|
stack.push(common.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 (
|
||
10 years ago
|
mOff = stack.pop()
|
||
|
cOff = stack.pop()
|
||
|
l = stack.pop()
|
||
10 years ago
|
)
|
||
10 years ago
|
data := getData(callData, cOff, l)
|
||
10 years ago
|
|
||
10 years ago
|
mem.Set(mOff.Uint64(), l.Uint64(), data)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" => [%v, %v, %v]", mOff, cOff, l)
|
||
10 years ago
|
case CODESIZE, EXTCODESIZE:
|
||
|
var code []byte
|
||
|
if op == EXTCODESIZE {
|
||
10 years ago
|
addr := common.BigToAddress(stack.pop())
|
||
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
|
addr := common.BigToAddress(stack.pop())
|
||
|
code = statedb.GetCode(addr)
|
||
10 years ago
|
} else {
|
||
|
code = context.Code
|
||
|
}
|
||
10 years ago
|
|
||
10 years ago
|
var (
|
||
10 years ago
|
mOff = stack.pop()
|
||
|
cOff = stack.pop()
|
||
|
l = stack.pop()
|
||
10 years ago
|
)
|
||
|
|
||
10 years ago
|
codeCopy := getData(code, cOff, l)
|
||
10 years ago
|
|
||
|
mem.Set(mOff.Uint64(), l.Uint64(), codeCopy)
|
||
10 years ago
|
|
||
|
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
|
|
||
10 years ago
|
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
|
||
10 years ago
|
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
|
||
10 years ago
|
stack.push(self.env.GetHash(num.Uint64()).Big())
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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(coinbase.Big())
|
||
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
|
||
10 years ago
|
stack.push(common.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)
|
||
10 years ago
|
topics := make([]common.Hash, n)
|
||
10 years ago
|
mStart, mSize := stack.pop(), stack.pop()
|
||
10 years ago
|
for i := 0; i < n; i++ {
|
||
10 years ago
|
topics[i] = common.BigToHash(stack.pop()) //common.LeftPadBytes(stack.pop().Bytes(), 32)
|
||
10 years ago
|
}
|
||
|
|
||
|
data := mem.Get(mStart.Int64(), mSize.Int64())
|
||
10 years ago
|
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 := common.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, common.BigToBytes(val, 256))
|
||
10 years ago
|
|
||
|
self.Printf(" => 0x%x", val)
|
||
|
case MSTORE8:
|
||
10 years ago
|
off, val := stack.pop().Int64(), stack.pop().Int64()
|
||
10 years ago
|
|
||
10 years ago
|
mem.store[off] = byte(val & 0xff)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" => [%v] 0x%x", off, mem.store[off])
|
||
10 years ago
|
case SLOAD:
|
||
10 years ago
|
loc := common.BigToHash(stack.pop())
|
||
|
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
|
||
10 years ago
|
stack.push(val)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
||
10 years ago
|
case SSTORE:
|
||
10 years ago
|
loc := common.BigToHash(stack.pop())
|
||
|
val := stack.pop()
|
||
|
|
||
|
statedb.SetState(context.Address(), loc, val)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf(" {0x%x : 0x%x}", loc, val.Bytes())
|
||
10 years ago
|
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
|
|
||
10 years ago
|
if cond.Cmp(common.BigTrue) >= 0 {
|
||
10 years ago
|
jump(pc, pos)
|
||
|
|
||
|
continue
|
||
|
}
|
||
|
|
||
10 years ago
|
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)
|
||
10 years ago
|
addr common.Address
|
||
10 years ago
|
)
|
||
10 years ago
|
self.Endl()
|
||
10 years ago
|
|
||
|
context.UseGas(context.Gas)
|
||
10 years ago
|
ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value)
|
||
10 years ago
|
if suberr != nil {
|
||
10 years ago
|
stack.push(common.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(addr.Big())
|
||
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
|
|
||
10 years ago
|
address := common.BigToAddress(addr)
|
||
10 years ago
|
self.Printf(" => %x", address).Endl()
|
||
|
|
||
10 years ago
|
// Get the arguments from the memory
|
||
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||
|
|
||
10 years ago
|
if len(value.Bytes()) > 0 {
|
||
|
gas.Add(gas, GasStipend)
|
||
|
}
|
||
|
|
||
10 years ago
|
var (
|
||
|
ret []byte
|
||
|
err error
|
||
|
)
|
||
|
if op == CALLCODE {
|
||
10 years ago
|
ret, err = self.env.CallCode(context, address, args, gas, price, value)
|
||
10 years ago
|
} else {
|
||
10 years ago
|
ret, err = self.env.Call(context, address, args, gas, price, value)
|
||
10 years ago
|
}
|
||
|
|
||
|
if err != nil {
|
||
10 years ago
|
stack.push(common.BigFalse)
|
||
10 years ago
|
|
||
10 years ago
|
self.Printf("%v").Endl()
|
||
10 years ago
|
} else {
|
||
10 years ago
|
stack.push(common.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(common.BigToAddress(stack.pop()))
|
||
10 years ago
|
balance := statedb.GetBalance(context.Address())
|
||
|
|
||
10 years ago
|
self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance)
|
||
10 years ago
|
|
||
10 years ago
|
receiver.AddBalance(balance)
|
||
10 years ago
|
|
||
10 years ago
|
statedb.Delete(context.Address())
|
||
|
|
||
|
fallthrough
|
||
|
case STOP: // Stop the context
|
||
|
self.Endl()
|
||
|
|
||
|
return context.Return(nil), nil
|
||
|
default:
|
||
10 years ago
|
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
|
}
|
||
|
|
||
10 years ago
|
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) {
|
||
10 years ago
|
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]
|
||
10 years ago
|
|
||
|
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)
|
||
|
|
||
10 years ago
|
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(), common.BigToHash(x))
|
||
10 years ago
|
if len(val) == 0 && len(y.Bytes()) > 0 {
|
||
|
// 0 => non 0
|
||
10 years ago
|
g = GasStorageAdd
|
||
10 years ago
|
} else if len(val) > 0 && len(y.Bytes()) == 0 {
|
||
10 years ago
|
statedb.Refund(self.env.Origin(), RefundStorage)
|
||
10 years ago
|
|
||
10 years ago
|
g = GasStorageMod
|
||
10 years ago
|
} else {
|
||
|
// non 0 => non 0 (or 0 => 0)
|
||
10 years ago
|
g = GasStorageMod
|
||
10 years ago
|
}
|
||
10 years ago
|
gas.Set(g)
|
||
10 years ago
|
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])
|
||
10 years ago
|
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])
|
||
10 years ago
|
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])
|
||
10 years ago
|
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
|
|
||
10 years ago
|
words := toWordSize(stack.data[stack.len()-4])
|
||
10 years ago
|
gas.Add(gas, words.Mul(words, GasCopyWord))
|
||
10 years ago
|
|
||
10 years ago
|
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])
|
||
10 years ago
|
|
||
|
if op == CALL {
|
||
10 years ago
|
if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
|
||
10 years ago
|
gas.Add(gas, GasCallNewAccount)
|
||
|
}
|
||
10 years ago
|
}
|
||
10 years ago
|
|
||
10 years ago
|
if len(stack.data[stack.len()-3].Bytes()) > 0 {
|
||
10 years ago
|
gas.Add(gas, GasCallValueTransfer)
|
||
10 years ago
|
}
|
||
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
|
|
||
10 years ago
|
newMemSize = common.BigMax(x, y)
|
||
10 years ago
|
}
|
||
|
|
||
10 years ago
|
if newMemSize.Cmp(common.Big0) > 0 {
|
||
10 years ago
|
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())))
|
||
10 years ago
|
pow := new(big.Int).Exp(oldSize, common.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)
|
||
|
|
||
10 years ago
|
pow.Exp(newMemSizeWords, common.Big2, Zero)
|
||
10 years ago
|
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
|
}
|
||
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
|
}
|
||
|
|
||
10 years ago
|
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
|
||
10 years ago
|
if self.debug {
|
||
|
if self.logTy == LogTyPretty {
|
||
|
self.logStr += fmt.Sprintf(format, v...)
|
||
|
}
|
||
10 years ago
|
}
|
||
|
|
||
|
return self
|
||
10 years ago
|
}
|
||
|
|
||
10 years ago
|
func (self *Vm) Endl() VirtualMachine {
|
||
10 years ago
|
if self.debug {
|
||
|
if self.logTy == LogTyPretty {
|
||
10 years ago
|
vmlogger.Infoln(self.logStr)
|
||
10 years ago
|
self.logStr = ""
|
||
|
}
|
||
10 years ago
|
}
|
||
|
|
||
|
return self
|
||
10 years ago
|
}
|
||
10 years ago
|
|
||
10 years ago
|
func (self *Vm) Env() Environment {
|
||
|
return self.env
|
||
|
}
|