tendermint/vm/vm.go

844 lines
22 KiB
Go
Raw Normal View History

2015-03-16 02:24:08 -07:00
package vm
import (
2015-04-17 16:05:36 -07:00
"bytes"
2015-03-17 21:46:26 -07:00
"errors"
2015-03-16 02:24:08 -07:00
"fmt"
"math/big"
2015-03-16 02:24:08 -07:00
2015-04-01 17:30:16 -07:00
. "github.com/tendermint/tendermint/common"
2015-04-13 21:43:13 -07:00
"github.com/tendermint/tendermint/events"
"github.com/tendermint/tendermint/types"
2015-04-01 17:30:16 -07:00
"github.com/tendermint/tendermint/vm/sha3"
2015-03-16 02:24:08 -07:00
)
2015-03-17 21:46:26 -07:00
var (
ErrUnknownAddress = errors.New("Unknown address")
2015-03-17 21:46:26 -07:00
ErrInsufficientBalance = errors.New("Insufficient balance")
ErrInvalidJumpDest = errors.New("Invalid jump dest")
ErrInsufficientGas = errors.New("Insuffient gas")
ErrMemoryOutOfBounds = errors.New("Memory out of bounds")
ErrCodeOutOfBounds = errors.New("Code out of bounds")
ErrInputOutOfBounds = errors.New("Input out of bounds")
ErrCallStackOverflow = errors.New("Call stack overflow")
ErrCallStackUnderflow = errors.New("Call stack underflow")
ErrDataStackOverflow = errors.New("Data stack overflow")
ErrDataStackUnderflow = errors.New("Data stack underflow")
ErrInvalidContract = errors.New("Invalid contract")
)
2015-03-16 02:24:08 -07:00
type Debug bool
2015-03-17 21:46:26 -07:00
const (
dataStackCapacity = 1024
callStackCapacity = 100 // TODO ensure usage.
memoryCapacity = 1024 * 1024 // 1 MB
dbg Debug = true
2015-03-17 21:46:26 -07:00
)
func (d Debug) Printf(s string, a ...interface{}) {
if d {
fmt.Printf(s, a...)
}
}
2015-03-17 21:46:26 -07:00
type VM struct {
appState AppState
2015-03-20 05:47:52 -07:00
params Params
origin Word256
txid []byte
2015-03-17 21:46:26 -07:00
callDepth int
2015-04-13 21:43:13 -07:00
2015-04-15 23:40:27 -07:00
evc events.Fireable
2015-03-16 02:24:08 -07:00
}
func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
2015-03-17 21:46:26 -07:00
return &VM{
appState: appState,
params: params,
2015-03-20 05:47:52 -07:00
origin: origin,
2015-03-17 21:46:26 -07:00
callDepth: 0,
txid: txid,
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
}
2015-03-16 02:24:08 -07:00
2015-04-13 21:43:13 -07:00
// satisfies events.Eventable
2015-04-15 23:40:27 -07:00
func (vm *VM) SetFireable(evc events.Fireable) {
vm.evc = evc
2015-04-13 21:43:13 -07:00
}
// CONTRACT appState is aware of caller and callee, so we can just mutate them.
// value: To be transferred from caller to callee. Refunded upon error.
// gas: Available gas. No refunds for gas.
2015-03-17 21:46:26 -07:00
func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
2015-03-16 02:24:08 -07:00
2015-03-18 23:12:53 -07:00
if len(code) == 0 {
panic("Call() requires code")
2015-03-17 21:46:26 -07:00
}
2015-03-16 02:24:08 -07:00
if err = transfer(caller, callee, value); err != nil {
return
}
vm.callDepth += 1
output, err = vm.call(caller, callee, code, input, value, gas)
vm.callDepth -= 1
exception := ""
if err != nil {
exception = err.Error()
err := transfer(callee, caller, value)
if err != nil {
panic("Could not return value to caller")
}
}
2015-04-15 19:14:08 -07:00
// if callDepth is 0 the event is fired from ExecTx (along with the Input event)
// otherwise, we fire from here.
2015-04-15 23:40:27 -07:00
if vm.callDepth != 0 && vm.evc != nil {
vm.evc.FireEvent(types.EventStringAccReceive(callee.Address.Postfix(20)), types.EventMsgCall{
&types.CallData{caller.Address.Postfix(20), callee.Address.Postfix(20), input, value, *gas},
vm.origin.Postfix(20),
vm.txid,
output,
exception,
})
}
return
}
// Just like Call() but does not transfer 'value' or modify the callDepth.
func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
2015-03-16 02:24:08 -07:00
var (
pc uint64 = 0
2015-03-17 21:46:26 -07:00
stack = NewStack(dataStackCapacity, gas, &err)
memory = make([]byte, memoryCapacity)
ok = false // convenience
2015-03-16 02:24:08 -07:00
)
for {
// If there is an error, return
if err != nil {
return nil, err
}
2015-03-17 21:46:26 -07:00
var op = codeGetOp(code, pc)
dbg.Printf("(pc) %-3d (op) %-14s (st) %-4d ", pc, op.String(), stack.Len())
2015-03-16 02:24:08 -07:00
switch op {
2015-03-17 21:46:26 -07:00
case STOP: // 0x00
return nil, nil
2015-03-16 02:24:08 -07:00
case ADD: // 0x01
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
sum := new(big.Int).Add(xb, yb)
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(sum).Bytes())
stack.Push(res)
dbg.Printf(" %v + %v = %v (%X)\n", xb, yb, sum, res)
2015-03-16 02:24:08 -07:00
case MUL: // 0x02
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
prod := new(big.Int).Mul(xb, yb)
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(prod).Bytes())
stack.Push(res)
dbg.Printf(" %v * %v = %v (%X)\n", xb, yb, prod, res)
2015-03-16 02:24:08 -07:00
case SUB: // 0x03
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
diff := new(big.Int).Sub(xb, yb)
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(diff).Bytes())
stack.Push(res)
dbg.Printf(" %v - %v = %v (%X)\n", xb, yb, diff, res)
2015-03-16 02:24:08 -07:00
case DIV: // 0x04
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
if y.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %x / %x = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
div := new(big.Int).Div(xb, yb)
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(div).Bytes())
stack.Push(res)
dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res)
2015-03-16 02:24:08 -07:00
}
case SDIV: // 0x05
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
if y.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %x / %x = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
div := new(big.Int).Div(xb, yb)
res := LeftPadWord256(U256(div).Bytes())
stack.Push(res)
dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res)
2015-03-16 02:24:08 -07:00
}
case MOD: // 0x06
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
if y.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
mod := new(big.Int).Mod(xb, yb)
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
2015-03-16 02:24:08 -07:00
}
case SMOD: // 0x07
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
if y.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
mod := new(big.Int).Mod(xb, yb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
2015-03-16 02:24:08 -07:00
}
case ADDMOD: // 0x08
2015-04-17 16:05:36 -07:00
x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
if z.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
zb := new(big.Int).SetBytes(z[:])
add := new(big.Int).Add(xb, yb)
mod := new(big.Int).Mod(add, zb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v + %v %% %v = %v (%X)\n",
xb, yb, zb, mod, res)
2015-03-16 02:24:08 -07:00
}
case MULMOD: // 0x09
2015-04-17 16:05:36 -07:00
x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
if z.IsZero() {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
} else {
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
zb := new(big.Int).SetBytes(z[:])
mul := new(big.Int).Mul(xb, yb)
mod := new(big.Int).Mod(mul, zb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v * %v %% %v = %v (%X)\n",
xb, yb, zb, mod, res)
2015-03-16 02:24:08 -07:00
}
case EXP: // 0x0A
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
pow := new(big.Int).Exp(xb, yb, big.NewInt(0))
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(U256(pow).Bytes())
2015-04-17 20:51:01 -07:00
stack.Push(res)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v ** %v = %v (%X)\n", xb, yb, pow, res)
2015-03-16 02:24:08 -07:00
case SIGNEXTEND: // 0x0B
2015-04-17 16:05:36 -07:00
back := stack.Pop()
backb := new(big.Int).SetBytes(back[:])
if backb.Cmp(big.NewInt(31)) < 0 {
bit := uint(backb.Uint64()*8 + 7)
num := stack.Pop()
numb := new(big.Int).SetBytes(num[:])
mask := new(big.Int).Lsh(big.NewInt(1), bit)
mask.Sub(mask, big.NewInt(1))
if numb.Bit(int(bit)) == 1 {
numb.Or(numb, mask.Not(mask))
} else {
numb.Add(numb, mask)
}
res := LeftPadWord256(U256(numb).Bytes())
dbg.Printf(" = %v (%X)", numb, res)
stack.Push(res)
}
2015-03-16 02:24:08 -07:00
case LT: // 0x10
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) < 0 {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v < %v = %v\n", xb, yb, 0)
2015-03-16 02:24:08 -07:00
}
case GT: // 0x11
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) > 0 {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v > %v = %v\n", xb, yb, 0)
2015-03-16 02:24:08 -07:00
}
case SLT: // 0x12
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) < 0 {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v < %v = %v\n", xb, yb, 0)
2015-03-16 02:24:08 -07:00
}
case SGT: // 0x13
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) > 0 {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v > %v = %v\n", xb, yb, 0)
2015-03-16 02:24:08 -07:00
}
case EQ: // 0x14
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
if bytes.Equal(x[:], y[:]) {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %X == %X = %v\n", x, y, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %X == %X = %v\n", x, y, 0)
2015-03-16 02:24:08 -07:00
}
case ISZERO: // 0x15
2015-04-17 16:05:36 -07:00
x := stack.Pop()
if x.IsZero() {
2015-03-16 02:24:08 -07:00
stack.Push64(1)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v == 0 = %v\n", x, 1)
2015-03-16 02:24:08 -07:00
} else {
stack.Push(Zero256)
2015-04-17 16:05:36 -07:00
dbg.Printf(" %v == 0 = %v\n", x, 0)
2015-03-16 02:24:08 -07:00
}
case AND: // 0x16
2015-04-17 17:43:45 -07:00
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] & y[i]
}
stack.Push(z)
dbg.Printf(" %X & %X = %X\n", x, y, z)
2015-03-16 02:24:08 -07:00
case OR: // 0x17
2015-04-17 17:43:45 -07:00
x, y := stack.Pop(), stack.Pop()
2015-04-17 16:05:36 -07:00
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] | y[i]
}
stack.Push(z)
dbg.Printf(" %X | %X = %X\n", x, y, z)
2015-03-16 02:24:08 -07:00
case XOR: // 0x18
2015-04-17 16:05:36 -07:00
x, y := stack.Pop(), stack.Pop()
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] ^ y[i]
}
stack.Push(z)
dbg.Printf(" %X ^ %X = %X\n", x, y, z)
2015-03-16 02:24:08 -07:00
case NOT: // 0x19
2015-04-17 16:05:36 -07:00
x := stack.Pop()
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = ^x[i]
}
stack.Push(z)
dbg.Printf(" !%X = %X\n", x, z)
2015-03-16 02:24:08 -07:00
case BYTE: // 0x1A
idx, val := stack.Pop64(), stack.Pop()
2015-03-17 21:46:26 -07:00
res := byte(0)
2015-03-16 02:24:08 -07:00
if idx < 32 {
2015-03-17 21:46:26 -07:00
res = val[idx]
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
stack.Push64(uint64(res))
dbg.Printf(" => 0x%X\n", res)
2015-03-16 02:24:08 -07:00
case SHA3: // 0x20
2015-03-17 21:46:26 -07:00
if ok = useGas(gas, GasSha3); !ok {
return nil, firstErr(err, ErrInsufficientGas)
2015-03-16 02:24:08 -07:00
}
offset, size := stack.Pop64(), stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(memory, offset, size)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
data = sha3.Sha3(data)
2015-04-17 16:05:36 -07:00
stack.PushBytes(data)
dbg.Printf(" => (%v) %X\n", size, data)
2015-03-16 02:24:08 -07:00
case ADDRESS: // 0x30
2015-04-17 20:51:01 -07:00
stack.Push(callee.Address)
dbg.Printf(" => %X\n", callee.Address)
2015-03-16 02:24:08 -07:00
case BALANCE: // 0x31
2015-03-17 21:46:26 -07:00
addr := stack.Pop()
if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas)
}
2015-04-17 16:05:36 -07:00
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
2015-03-16 02:24:08 -07:00
}
balance := acc.Balance
2015-03-16 02:24:08 -07:00
stack.Push64(balance)
dbg.Printf(" => %v (%X)\n", balance, addr)
2015-03-16 02:24:08 -07:00
case ORIGIN: // 0x32
2015-04-17 20:51:01 -07:00
stack.Push(vm.origin)
dbg.Printf(" => %X\n", vm.origin)
2015-03-16 02:24:08 -07:00
case CALLER: // 0x33
2015-04-17 20:51:01 -07:00
stack.Push(caller.Address)
dbg.Printf(" => %X\n", caller.Address)
2015-03-16 02:24:08 -07:00
case CALLVALUE: // 0x34
stack.Push64(value)
dbg.Printf(" => %v\n", value)
2015-03-16 02:24:08 -07:00
case CALLDATALOAD: // 0x35
offset := stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(input, offset, 32)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrInputOutOfBounds)
}
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(data)
stack.Push(res)
dbg.Printf(" => 0x%X\n", res)
2015-03-16 02:24:08 -07:00
case CALLDATASIZE: // 0x36
2015-03-17 21:46:26 -07:00
stack.Push64(uint64(len(input)))
dbg.Printf(" => %d\n", len(input))
2015-03-16 02:24:08 -07:00
case CALLDATACOPY: // 0x37
memOff := stack.Pop64()
inputOff := stack.Pop64()
length := stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(input, inputOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrInputOutOfBounds)
2015-03-16 02:24:08 -07:00
}
2015-04-17 16:05:36 -07:00
dest, ok := subslice(memory, memOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
copy(dest, data)
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
2015-03-16 02:24:08 -07:00
case CODESIZE: // 0x38
l := uint64(len(code))
stack.Push64(l)
dbg.Printf(" => %d\n", l)
2015-03-16 02:24:08 -07:00
case CODECOPY: // 0x39
memOff := stack.Pop64()
codeOff := stack.Pop64()
length := stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(code, codeOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds)
}
2015-04-17 16:05:36 -07:00
dest, ok := subslice(memory, memOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
copy(dest, data)
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
2015-03-16 02:24:08 -07:00
2015-03-18 23:12:53 -07:00
case GASPRICE_DEPRECATED: // 0x3A
stack.Push(Zero256)
dbg.Printf(" => %X (GASPRICE IS DEPRECATED)\n")
2015-03-16 02:24:08 -07:00
case EXTCODESIZE: // 0x3B
2015-03-17 21:46:26 -07:00
addr := stack.Pop()
if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas)
}
2015-04-17 16:05:36 -07:00
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
2015-03-17 21:46:26 -07:00
}
code := acc.Code
2015-03-16 02:24:08 -07:00
l := uint64(len(code))
stack.Push64(l)
dbg.Printf(" => %d\n", l)
2015-03-16 02:24:08 -07:00
case EXTCODECOPY: // 0x3C
2015-03-17 21:46:26 -07:00
addr := stack.Pop()
if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas)
}
2015-04-17 16:05:36 -07:00
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
2015-03-17 21:46:26 -07:00
}
code := acc.Code
2015-03-16 02:24:08 -07:00
memOff := stack.Pop64()
codeOff := stack.Pop64()
length := stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(code, codeOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
2015-03-20 05:47:52 -07:00
return nil, firstErr(err, ErrCodeOutOfBounds)
2015-03-16 02:24:08 -07:00
}
2015-04-17 16:05:36 -07:00
dest, ok := subslice(memory, memOff, length)
2015-03-17 21:46:26 -07:00
if !ok {
2015-03-20 05:47:52 -07:00
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-17 21:46:26 -07:00
}
copy(dest, data)
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
2015-03-16 02:24:08 -07:00
case BLOCKHASH: // 0x40
stack.Push(Zero256)
dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes())
2015-03-16 02:24:08 -07:00
case COINBASE: // 0x41
stack.Push(Zero256)
dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes())
2015-03-16 02:24:08 -07:00
case TIMESTAMP: // 0x42
time := vm.params.BlockTime
stack.Push64(uint64(time))
dbg.Printf(" => 0x%X\n", time)
2015-03-16 02:24:08 -07:00
case BLOCKHEIGHT: // 0x43
number := uint64(vm.params.BlockHeight)
stack.Push64(number)
dbg.Printf(" => 0x%X\n", number)
2015-03-16 02:24:08 -07:00
case GASLIMIT: // 0x45
stack.Push64(vm.params.GasLimit)
dbg.Printf(" => %v\n", vm.params.GasLimit)
2015-03-16 02:24:08 -07:00
case POP: // 0x50
stack.Pop()
dbg.Printf(" => %v\n", vm.params.GasLimit)
2015-03-16 02:24:08 -07:00
case MLOAD: // 0x51
offset := stack.Pop64()
2015-04-17 16:05:36 -07:00
data, ok := subslice(memory, offset, 32)
2015-03-17 21:46:26 -07:00
if !ok {
2015-03-20 05:47:52 -07:00
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-17 21:46:26 -07:00
}
2015-04-17 16:05:36 -07:00
stack.Push(LeftPadWord256(data))
dbg.Printf(" => 0x%X\n", data)
2015-03-17 21:46:26 -07:00
case MSTORE: // 0x52
offset, data := stack.Pop64(), stack.Pop()
2015-04-17 16:05:36 -07:00
dest, ok := subslice(memory, offset, 32)
2015-03-17 21:46:26 -07:00
if !ok {
2015-03-20 05:47:52 -07:00
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-17 21:46:26 -07:00
}
2015-04-17 16:05:36 -07:00
copy(dest, data[:])
dbg.Printf(" => 0x%X\n", data)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case MSTORE8: // 0x53
offset, val := stack.Pop64(), byte(stack.Pop64()&0xFF)
if len(memory) <= int(offset) {
2015-03-20 05:47:52 -07:00
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-17 21:46:26 -07:00
}
memory[offset] = val
dbg.Printf(" => [%v] 0x%X\n", offset, val)
2015-03-17 21:46:26 -07:00
case SLOAD: // 0x54
loc := stack.Pop()
data := vm.appState.GetStorage(callee.Address, loc)
2015-03-29 19:05:29 -07:00
stack.Push(data)
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
2015-03-17 21:46:26 -07:00
case SSTORE: // 0x55
loc, data := stack.Pop(), stack.Pop()
vm.appState.SetStorage(callee.Address, loc, data)
useGas(gas, GasStorageUpdate)
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case JUMP: // 0x56
err = jump(code, stack.Pop64(), &pc)
2015-03-16 02:24:08 -07:00
continue
2015-03-17 21:46:26 -07:00
case JUMPI: // 0x57
2015-04-17 16:05:36 -07:00
pos, cond := stack.Pop64(), stack.Pop()
if !cond.IsZero() {
err = jump(code, pos, &pc)
2015-03-16 02:24:08 -07:00
continue
}
dbg.Printf(" ~> false\n")
2015-03-17 21:46:26 -07:00
case PC: // 0x58
stack.Push64(pc)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case MSIZE: // 0x59
stack.Push64(uint64(len(memory)))
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case GAS: // 0x5A
stack.Push64(*gas)
dbg.Printf(" => %X\n", *gas)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case JUMPDEST: // 0x5B
dbg.Printf("\n")
2015-03-17 21:46:26 -07:00
// Do nothing
2015-03-16 02:24:08 -07: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:
a := uint64(op - PUSH1 + 1)
2015-04-17 16:05:36 -07:00
codeSegment, ok := subslice(code, pc+1, a)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds)
}
2015-04-17 16:05:36 -07:00
res := LeftPadWord256(codeSegment)
2015-03-17 21:46:26 -07:00
stack.Push(res)
2015-03-16 02:24:08 -07:00
pc += a
dbg.Printf(" => 0x%X\n", res)
2015-04-17 20:51:01 -07:00
stack.Print(10)
2015-03-16 02:24:08 -07: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-17 21:46:26 -07:00
stack.Dup(n)
dbg.Printf(" => [%d] 0x%X\n", n, stack.Peek().Bytes())
2015-03-16 02:24:08 -07: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-17 21:46:26 -07:00
stack.Swap(n)
2015-04-17 20:51:01 -07:00
dbg.Printf(" => [%d] %X\n", n, stack.Peek())
stack.Print(10)
2015-03-16 02:24:08 -07:00
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics := make([]Word256, n)
2015-03-17 21:46:26 -07:00
offset, size := stack.Pop64(), stack.Pop64()
2015-03-16 02:24:08 -07:00
for i := 0; i < n; i++ {
2015-03-17 21:46:26 -07:00
topics[i] = stack.Pop()
2015-03-16 02:24:08 -07:00
}
2015-04-17 16:05:36 -07:00
data, ok := subslice(memory, offset, size)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
log := &Log{
callee.Address,
topics,
data,
vm.params.BlockHeight,
}
vm.appState.AddLog(log)
dbg.Printf(" => %v\n", log)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case CREATE: // 0xF0
2015-03-20 20:50:38 -07:00
contractValue := stack.Pop64()
2015-03-17 21:46:26 -07:00
offset, size := stack.Pop64(), stack.Pop64()
2015-04-17 16:05:36 -07:00
input, ok := subslice(memory, offset, size)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
// Check balance
2015-03-20 20:50:38 -07:00
if callee.Balance < contractValue {
2015-03-17 21:46:26 -07:00
return nil, firstErr(err, ErrInsufficientBalance)
}
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
// TODO charge for gas to create account _ the code length * GasCreateByte
2015-03-16 02:24:08 -07:00
newAccount := vm.appState.CreateAccount(callee)
// Run the input to get the contract code.
ret, err_ := vm.Call(callee, newAccount, input, input, contractValue, gas)
if err_ != nil {
stack.Push(Zero256)
2015-03-16 02:24:08 -07:00
} else {
newAccount.Code = ret // Set the code
2015-04-17 20:51:01 -07:00
stack.Push(newAccount.Address)
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
case CALL, CALLCODE: // 0xF1, 0xF2
gasLimit := stack.Pop64()
addr, value := stack.Pop(), stack.Pop64()
inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs
retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs
dbg.Printf(" => %X\n", addr)
2015-03-16 02:24:08 -07:00
// Get the arguments from the memory
2015-04-17 16:05:36 -07:00
args, ok := subslice(memory, inOffset, inSize)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
// Ensure that gasLimit is reasonable
if *gas < gasLimit {
return nil, firstErr(err, ErrInsufficientGas)
2015-03-16 02:24:08 -07:00
} else {
2015-03-17 21:46:26 -07:00
*gas -= gasLimit
// NOTE: we will return any used gas later.
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
// Begin execution
var ret []byte
var err error
if nativeContract := nativeContracts[addr]; nativeContract != nil {
2015-03-20 05:47:52 -07:00
// Native contract
2015-03-17 21:46:26 -07:00
ret, err = nativeContract(args, &gasLimit)
2015-03-16 02:24:08 -07:00
} else {
2015-03-20 05:47:52 -07:00
// EVM contract
2015-03-17 21:46:26 -07:00
if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas)
}
2015-04-17 16:05:36 -07:00
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
2015-03-17 21:46:26 -07:00
}
if op == CALLCODE {
ret, err = vm.Call(callee, callee, acc.Code, args, value, gas)
2015-03-17 21:46:26 -07:00
} else {
ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
2015-03-17 21:46:26 -07:00
}
2015-03-16 02:24:08 -07:00
}
2015-03-17 21:46:26 -07:00
// Push result
if err != nil {
stack.Push(Zero256)
2015-03-17 21:46:26 -07:00
} else {
stack.Push(One256)
2015-04-17 16:05:36 -07:00
dest, ok := subslice(memory, retOffset, retSize)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
copy(dest, ret)
}
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
// Handle remaining gas.
*gas += gasLimit
2015-03-16 02:24:08 -07:00
dbg.Printf("resume %X (%v)\n", callee.Address, gas)
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case RETURN: // 0xF3
offset, size := stack.Pop64(), stack.Pop64()
2015-04-17 16:05:36 -07:00
ret, ok := subslice(memory, offset, size)
2015-03-17 21:46:26 -07:00
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret)
2015-03-17 21:46:26 -07:00
return ret, nil
2015-03-16 02:24:08 -07:00
2015-03-17 21:46:26 -07:00
case SUICIDE: // 0xFF
addr := stack.Pop()
if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas)
}
// TODO if the receiver is , then make it the fee.
2015-04-17 16:05:36 -07:00
receiver := vm.appState.GetAccount(addr)
if receiver == nil {
return nil, firstErr(err, ErrUnknownAddress)
2015-03-17 21:46:26 -07:00
}
balance := callee.Balance
receiver.Balance += balance
vm.appState.UpdateAccount(receiver)
vm.appState.RemoveAccount(callee)
dbg.Printf(" => (%X) %v\n", addr[:4], balance)
2015-03-16 02:24:08 -07:00
fallthrough
default:
dbg.Printf("(pc) %-3v Invalid opcode %X\n", pc, op)
2015-03-16 02:24:08 -07:00
panic(fmt.Errorf("Invalid opcode %X", op))
}
pc++
}
}
2015-04-17 16:05:36 -07:00
func subslice(data []byte, offset, length uint64) (ret []byte, ok bool) {
2015-03-16 02:24:08 -07:00
size := uint64(len(data))
if size < offset {
return nil, false
} else if size < offset+length {
2015-04-17 13:18:50 -07:00
ret, ok = data[offset:], true
ret = RightPadBytes(ret, 32)
2015-03-16 02:24:08 -07:00
} else {
ret, ok = data[offset:offset+length], true
2015-03-16 02:24:08 -07:00
}
2015-04-17 13:18:50 -07:00
return
2015-03-16 02:24:08 -07:00
}
2015-04-17 17:43:45 -07:00
func rightMostBytes(data []byte, n int) []byte {
size := MinInt(len(data), n)
offset := len(data) - size
return data[offset:]
}
2015-03-17 21:46:26 -07:00
func codeGetOp(code []byte, n uint64) OpCode {
if uint64(len(code)) <= n {
return OpCode(0) // stop
2015-03-16 02:24:08 -07:00
} else {
2015-03-17 21:46:26 -07:00
return OpCode(code[n])
2015-03-16 02:24:08 -07:00
}
}
2015-03-17 21:46:26 -07:00
func jump(code []byte, to uint64, pc *uint64) (err error) {
2015-03-17 21:46:26 -07:00
dest := codeGetOp(code, to)
if dest != JUMPDEST {
dbg.Printf(" ~> %v invalid jump dest %v\n", to, dest)
2015-03-17 21:46:26 -07:00
return ErrInvalidJumpDest
}
dbg.Printf(" ~> %v\n", to)
*pc = to
2015-03-17 21:46:26 -07:00
return nil
}
func firstErr(errA, errB error) error {
if errA != nil {
return errA
} else {
return errB
}
}
func useGas(gas *uint64, gasToUse uint64) bool {
if *gas > gasToUse {
*gas -= gasToUse
return true
} else {
return false
}
}
2015-03-20 05:47:52 -07:00
func transfer(from, to *Account, amount uint64) error {
if from.Balance < amount {
return ErrInsufficientBalance
} else {
from.Balance -= amount
to.Balance += amount
return nil
}
}