Transcribe vm changes from vm_fixes by Ethan

This commit is contained in:
Jae Kwon
2015-03-29 00:07:10 -07:00
parent 79304b0dd3
commit 4be97fa9d4
3 changed files with 253 additions and 125 deletions

View File

@ -1,8 +1,6 @@
package vm package vm
import ( import (
"fmt"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/vm" . "github.com/tendermint/tendermint/vm"
"github.com/tendermint/tendermint/vm/sha3" "github.com/tendermint/tendermint/vm/sha3"
@ -85,33 +83,6 @@ func (fas *FakeAppState) AddLog(log *Log) {
fas.logs = append(fas.logs, log) fas.logs = append(fas.logs, log)
} }
func main() {
appState := &FakeAppState{
accounts: make(map[string]*Account),
storage: make(map[string]Word256),
logs: nil,
}
params := Params{
BlockHeight: 0,
BlockHash: Zero256,
BlockTime: 0,
GasLimit: 0,
}
ourVm := NewVM(appState, params, Zero256)
// Create accounts
account1 := &Account{
Address: Uint64ToWord256(100),
}
account2 := &Account{
Address: Uint64ToWord256(101),
}
var gas uint64 = 1000
output, err := ourVm.Call(account1, account2, []byte{0x5B, 0x60, 0x00, 0x56}, []byte{}, 0, &gas)
fmt.Printf("Output: %v Error: %v\n", output, err)
}
// Creates a 20 byte address and bumps the nonce. // Creates a 20 byte address and bumps the nonce.
func createAddress(creator *Account) Word256 { func createAddress(creator *Account) Word256 {
nonce := creator.Nonce nonce := creator.Nonce

99
vm/test/vm_test.go Normal file
View File

@ -0,0 +1,99 @@
package vm
import (
"crypto/rand"
"encoding/hex"
"fmt"
"strings"
"testing"
"time"
. "github.com/tendermint/tendermint/common"
. "github.com/tendermint/tendermint/vm"
)
func newAppState() *FakeAppState {
return &FakeAppState{
accounts: make(map[string]*Account),
storage: make(map[string]Word256),
logs: nil,
}
}
func newParams() Params {
return Params{
BlockHeight: 0,
BlockHash: Zero256,
BlockTime: 0,
GasLimit: 0,
}
}
func makeBytes(n int) []byte {
b := make([]byte, n)
rand.Read(b)
return b
}
func TestVM(t *testing.T) {
ourVm := NewVM(newAppState(), newParams(), Zero256)
// Create accounts
account1 := &Account{
Address: Uint64ToWord256(100),
}
account2 := &Account{
Address: Uint64ToWord256(101),
}
var gas uint64 = 1000
N := []byte{0xff, 0xff}
// Loop N times
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)}
for i := 0; i < len(N); i++ {
code = append(code, N[i])
}
code = append(code, []byte{0x60, 0x20, 0x51, 0x12, 0x15, 0x60, byte(0x1b + len(N)), 0x57, 0x60, 0x01, 0x60, 0x20, 0x51, 0x01, 0x60, 0x20, 0x52, 0x60, 0x05, 0x56, 0x5B}...)
start := time.Now()
output, err := ourVm.Call(account1, account2, code, []byte{}, 0, &gas)
fmt.Printf("Output: %v Error: %v\n", output, err)
fmt.Println("Call took:", time.Since(start))
}
func TestSubcurrency(t *testing.T) {
st := newAppState()
// Create accounts
account1 := &Account{
Address: RightPadWord256(makeBytes(20)),
}
account2 := &Account{
Address: RightPadWord256(makeBytes(20)),
}
st.accounts[account1.Address.String()] = account1
st.accounts[account2.Address.String()] = account2
ourVm := NewVM(st, newParams(), Zero256)
var gas uint64 = 1000
code_parts := []string{"620f42403355",
"7c0100000000000000000000000000000000000000000000000000000000",
"600035046315cf268481141561004657",
"6004356040526040515460605260206060f35b63693200ce81141561008757",
"60043560805260243560a052335460c0523360e05260a05160c05112151561008657",
"60a05160c0510360e0515560a0516080515401608051555b5b505b6000f3"}
code, _ := hex.DecodeString(strings.Join(code_parts, ""))
fmt.Printf("Code: %x\n", code)
data, _ := hex.DecodeString("693200CE0000000000000000000000004B4363CDE27C2EB05E66357DB05BC5C88F850C1A0000000000000000000000000000000000000000000000000000000000000005")
output, err := ourVm.Call(account1, account2, code, data, 0, &gas)
fmt.Printf("Output: %v Error: %v\n", output, err)
}
/*
// infinite loop
code := []byte{0x5B, 0x60, 0x00, 0x56}
// mstore
code := []byte{0x60, 0x00, 0x60, 0x20}
// mstore, mload
code := []byte{0x60, 0x01, 0x60, 0x20, 0x52, 0x60, 0x20, 0x51}
*/

250
vm/vm.go
View File

@ -3,7 +3,7 @@ package vm
import ( import (
"errors" "errors"
"fmt" "fmt"
"math" "math/big"
. "github.com/tendermint/tendermint/common" . "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/vm/sha3" "github.com/tendermint/tendermint/vm/sha3"
@ -24,12 +24,21 @@ var (
ErrInvalidContract = errors.New("Invalid contract") ErrInvalidContract = errors.New("Invalid contract")
) )
type Debug bool
const ( const (
dataStackCapacity = 1024 dataStackCapacity = 1024
callStackCapacity = 100 // TODO ensure usage. callStackCapacity = 100 // TODO ensure usage.
memoryCapacity = 1024 * 1024 // 1 MB memoryCapacity = 1024 * 1024 // 1 MB
dbg Debug = true
) )
func (d Debug) Printf(s string, a ...interface{}) {
if d {
fmt.Printf(s, a...)
}
}
type VM struct { type VM struct {
appState AppState appState AppState
params Params params Params
@ -74,7 +83,7 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, ga
// Just like Call() but does not transfer 'value' or modify the callDepth. // 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) { func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
fmt.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input) dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
var ( var (
pc uint64 = 0 pc uint64 = 0
@ -90,7 +99,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} }
var op = codeGetOp(code, pc) var op = codeGetOp(code, pc)
fmt.Printf("(pc) %-3d (op) %-14s (st) %-4d ", pc, op.String(), stack.Len()) dbg.Printf("(pc) %-3d (op) %-14s (st) %-4d ", pc, op.String(), stack.Len())
switch op { switch op {
@ -98,90 +107,123 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, nil return nil, nil
case ADD: // 0x01 case ADD: // 0x01
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x + y) //stack.Push64(x + y)
fmt.Printf(" %v + %v = %v\n", x, y, x+y) x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
sum := new(big.Int).Add(xb, yb)
stack.Push(RightPadWord256(flip(sum.Bytes())))
dbg.Printf(" %v + %v = %v\n", xb, yb, sum)
case MUL: // 0x02 case MUL: // 0x02
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x * y) //stack.Push64(x * y)
fmt.Printf(" %v * %v = %v\n", x, y, x*y) x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
prod := new(big.Int).Mul(xb, yb)
stack.Push(RightPadWord256(flip(prod.Bytes())))
dbg.Printf(" %v * %v = %v\n", xb, yb, prod)
case SUB: // 0x03 case SUB: // 0x03
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x - y) //stack.Push64(x - y)
fmt.Printf(" %v - %v = %v\n", x, y, x-y) x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
diff := new(big.Int).Sub(xb, yb)
stack.Push(RightPadWord256(flip(diff.Bytes())))
dbg.Printf(" %v - %v = %v\n", xb, yb, diff)
case DIV: // 0x04 case DIV: // 0x04
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
if y == 0 { // TODO //stack.Push64(x / y)
x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0)
} else { } else {
stack.Push64(x / y) xb := new(big.Int).SetBytes(flip(x[:]))
fmt.Printf(" %v / %v = %v\n", x, y, x/y) yb := new(big.Int).SetBytes(flip(y[:]))
div := new(big.Int).Div(xb, yb)
stack.Push(RightPadWord256(flip(div.Bytes())))
dbg.Printf(" %v / %v = %v\n", xb, yb, div)
} }
case SDIV: // 0x05 case SDIV: // 0x05
// TODO ... big?
x, y := int64(stack.Pop64()), int64(stack.Pop64()) x, y := int64(stack.Pop64()), int64(stack.Pop64())
if y == 0 { // TODO if y == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0)
} else { } else {
stack.Push64(uint64(x / y)) stack.Push64(uint64(x / y))
fmt.Printf(" %v / %v = %v\n", x, y, x/y) dbg.Printf(" %v / %v = %v\n", x, y, x/y)
} }
case MOD: // 0x06 case MOD: // 0x06
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
if y == 0 { // TODO x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
} else { } else {
stack.Push64(x % y) xb := new(big.Int).SetBytes(flip(x[:]))
fmt.Printf(" %v %% %v = %v\n", x, y, x%y) yb := new(big.Int).SetBytes(flip(y[:]))
mod := new(big.Int).Mod(xb, yb)
stack.Push(RightPadWord256(flip(mod.Bytes())))
dbg.Printf(" %v %% %v = %v\n", xb, yb, mod)
} }
case SMOD: // 0x07 case SMOD: // 0x07
// TODO ... big?
x, y := int64(stack.Pop64()), int64(stack.Pop64()) x, y := int64(stack.Pop64()), int64(stack.Pop64())
if y == 0 { // TODO if y == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
} else { } else {
stack.Push64(uint64(x % y)) stack.Push64(uint64(x % y))
fmt.Printf(" %v %% %v = %v\n", x, y, x%y) dbg.Printf(" %v %% %v = %v\n", x, y, x%y)
} }
case ADDMOD: // 0x08 case ADDMOD: // 0x08
// TODO ... big?
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
if z == 0 { // TODO if z == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0)
} else { } else {
stack.Push64(x % y) stack.Push64((x + y) % z)
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z) dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z)
} }
case MULMOD: // 0x09 case MULMOD: // 0x09
// TODO ... big?
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
if z == 0 { // TODO if z == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0)
} else { } else {
stack.Push64(x % y) stack.Push64((x * y) % z)
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z) dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z)
} }
case EXP: // 0x0A case EXP: // 0x0A
x, y := stack.Pop64(), stack.Pop64() //x, y := stack.Pop64(), stack.Pop64()
stack.Push64(ExpUint64(x, y)) //stack.Push64(ExpUint64(x, y))
fmt.Printf(" %v ** %v = %v\n", x, y, uint64(math.Pow(float64(x), float64(y)))) x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
pow := new(big.Int).Exp(xb, yb, big.NewInt(0))
stack.Push(RightPadWord256(flip(pow.Bytes())))
dbg.Printf(" %v ** %v = %v\n", xb, yb, pow)
case SIGNEXTEND: // 0x0B case SIGNEXTEND: // 0x0B
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
res := (y << uint(x)) >> x res := (y << uint(x)) >> x
stack.Push64(res) stack.Push64(res)
fmt.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res) dbg.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res)
case LT: // 0x10 case LT: // 0x10
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
@ -190,7 +232,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v < %v = %v\n", x, y, x < y) dbg.Printf(" %v < %v = %v\n", x, y, x < y)
case GT: // 0x11 case GT: // 0x11
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
@ -199,7 +241,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v > %v = %v\n", x, y, x > y) dbg.Printf(" %v > %v = %v\n", x, y, x > y)
case SLT: // 0x12 case SLT: // 0x12
x, y := int64(stack.Pop64()), int64(stack.Pop64()) x, y := int64(stack.Pop64()), int64(stack.Pop64())
@ -208,7 +250,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v < %v = %v\n", x, y, x < y) dbg.Printf(" %v < %v = %v\n", x, y, x < y)
case SGT: // 0x13 case SGT: // 0x13
x, y := int64(stack.Pop64()), int64(stack.Pop64()) x, y := int64(stack.Pop64()), int64(stack.Pop64())
@ -217,16 +259,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v > %v = %v\n", x, y, x > y) dbg.Printf(" %v > %v = %v\n", x, y, x > y)
case EQ: // 0x14 case EQ: // 0x14
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
if x > y { if x == y {
stack.Push64(1) stack.Push64(1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v == %v = %v\n", x, y, x == y) dbg.Printf(" %v == %v = %v\n", x, y, x == y)
case ISZERO: // 0x15 case ISZERO: // 0x15
x := stack.Pop64() x := stack.Pop64()
@ -235,27 +277,27 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
} }
fmt.Printf(" %v == 0 = %v\n", x, x == 0) dbg.Printf(" %v == 0 = %v\n", x, x == 0)
case AND: // 0x16 case AND: // 0x16
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x & y) stack.Push64(x & y)
fmt.Printf(" %v & %v = %v\n", x, y, x&y) dbg.Printf(" %v & %v = %v\n", x, y, x&y)
case OR: // 0x17 case OR: // 0x17
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x | y) stack.Push64(x | y)
fmt.Printf(" %v | %v = %v\n", x, y, x|y) dbg.Printf(" %v | %v = %v\n", x, y, x|y)
case XOR: // 0x18 case XOR: // 0x18
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x ^ y) stack.Push64(x ^ y)
fmt.Printf(" %v ^ %v = %v\n", x, y, x^y) dbg.Printf(" %v ^ %v = %v\n", x, y, x^y)
case NOT: // 0x19 case NOT: // 0x19
x := stack.Pop64() x := stack.Pop64()
stack.Push64(^x) stack.Push64(^x)
fmt.Printf(" !%v = %v\n", x, ^x) dbg.Printf(" !%v = %v\n", x, ^x)
case BYTE: // 0x1A case BYTE: // 0x1A
idx, val := stack.Pop64(), stack.Pop() idx, val := stack.Pop64(), stack.Pop()
@ -264,7 +306,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
res = val[idx] res = val[idx]
} }
stack.Push64(uint64(res)) stack.Push64(uint64(res))
fmt.Printf(" => 0x%X\n", res) dbg.Printf(" => 0x%X\n", res)
case SHA3: // 0x20 case SHA3: // 0x20
if ok = useGas(gas, GasSha3); !ok { if ok = useGas(gas, GasSha3); !ok {
@ -277,11 +319,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} }
data = sha3.Sha3(data) data = sha3.Sha3(data)
stack.PushBytes(data) stack.PushBytes(data)
fmt.Printf(" => (%v) %X\n", size, data) dbg.Printf(" => (%v) %X\n", size, data)
case ADDRESS: // 0x30 case ADDRESS: // 0x30
stack.Push(callee.Address) stack.Push(callee.Address)
fmt.Printf(" => %X\n", callee.Address) dbg.Printf(" => %X\n", callee.Address)
case BALANCE: // 0x31 case BALANCE: // 0x31
addr := stack.Pop() addr := stack.Pop()
@ -294,19 +336,19 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} }
balance := acc.Balance balance := acc.Balance
stack.Push64(balance) stack.Push64(balance)
fmt.Printf(" => %v (%X)\n", balance, addr) dbg.Printf(" => %v (%X)\n", balance, addr)
case ORIGIN: // 0x32 case ORIGIN: // 0x32
stack.Push(vm.origin) stack.Push(vm.origin)
fmt.Printf(" => %X\n", vm.origin) dbg.Printf(" => %X\n", vm.origin)
case CALLER: // 0x33 case CALLER: // 0x33
stack.Push(caller.Address) stack.Push(caller.Address)
fmt.Printf(" => %X\n", caller.Address) dbg.Printf(" => %X\n", caller.Address)
case CALLVALUE: // 0x34 case CALLVALUE: // 0x34
stack.Push64(value) stack.Push64(value)
fmt.Printf(" => %v\n", value) dbg.Printf(" => %v\n", value)
case CALLDATALOAD: // 0x35 case CALLDATALOAD: // 0x35
offset := stack.Pop64() offset := stack.Pop64()
@ -315,11 +357,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInputOutOfBounds) return nil, firstErr(err, ErrInputOutOfBounds)
} }
stack.Push(RightPadWord256(data)) stack.Push(RightPadWord256(data))
fmt.Printf(" => 0x%X\n", data) dbg.Printf(" => 0x%X\n", data)
case CALLDATASIZE: // 0x36 case CALLDATASIZE: // 0x36
stack.Push64(uint64(len(input))) stack.Push64(uint64(len(input)))
fmt.Printf(" => %d\n", len(input)) dbg.Printf(" => %d\n", len(input))
case CALLDATACOPY: // 0x37 case CALLDATACOPY: // 0x37
memOff := stack.Pop64() memOff := stack.Pop64()
@ -334,18 +376,17 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
copy(dest, data) copy(dest, data)
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data) dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
case CODESIZE: // 0x38 case CODESIZE: // 0x38
l := uint64(len(code)) l := uint64(len(code))
stack.Push64(l) stack.Push64(l)
fmt.Printf(" => %d\n", l) dbg.Printf(" => %d\n", l)
case CODECOPY: // 0x39 case CODECOPY: // 0x39
memOff := stack.Pop64() memOff := stack.Pop64()
codeOff := stack.Pop64() codeOff := stack.Pop64()
length := stack.Pop64() length := stack.Pop64()
fmt.Println("CODECOPY: codeOff, length, codelength", codeOff, length, len(code))
data, ok := subslice(code, codeOff, length, false) data, ok := subslice(code, codeOff, length, false)
if !ok { if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds) return nil, firstErr(err, ErrCodeOutOfBounds)
@ -355,11 +396,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
copy(dest, data) copy(dest, data)
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
case GASPRICE_DEPRECATED: // 0x3A case GASPRICE_DEPRECATED: // 0x3A
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" => %X (GASPRICE IS DEPRECATED)\n") dbg.Printf(" => %X (GASPRICE IS DEPRECATED)\n")
case EXTCODESIZE: // 0x3B case EXTCODESIZE: // 0x3B
addr := stack.Pop() addr := stack.Pop()
@ -373,7 +414,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
code := acc.Code code := acc.Code
l := uint64(len(code)) l := uint64(len(code))
stack.Push64(l) stack.Push64(l)
fmt.Printf(" => %d\n", l) dbg.Printf(" => %d\n", l)
case EXTCODECOPY: // 0x3C case EXTCODECOPY: // 0x3C
addr := stack.Pop() addr := stack.Pop()
@ -397,33 +438,33 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
copy(dest, data) copy(dest, data)
fmt.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data) dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
case BLOCKHASH: // 0x40 case BLOCKHASH: // 0x40
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes())
case COINBASE: // 0x41 case COINBASE: // 0x41
stack.Push(Zero256) stack.Push(Zero256)
fmt.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes()) dbg.Printf(" => 0x%X (NOT SUPPORTED)\n", stack.Peek().Bytes())
case TIMESTAMP: // 0x42 case TIMESTAMP: // 0x42
time := vm.params.BlockTime time := vm.params.BlockTime
stack.Push64(uint64(time)) stack.Push64(uint64(time))
fmt.Printf(" => 0x%X\n", time) dbg.Printf(" => 0x%X\n", time)
case BLOCKHEIGHT: // 0x43 case BLOCKHEIGHT: // 0x43
number := uint64(vm.params.BlockHeight) number := uint64(vm.params.BlockHeight)
stack.Push64(number) stack.Push64(number)
fmt.Printf(" => 0x%X\n", number) dbg.Printf(" => 0x%X\n", number)
case GASLIMIT: // 0x45 case GASLIMIT: // 0x45
stack.Push64(vm.params.GasLimit) stack.Push64(vm.params.GasLimit)
fmt.Printf(" => %v\n", vm.params.GasLimit) dbg.Printf(" => %v\n", vm.params.GasLimit)
case POP: // 0x50 case POP: // 0x50
stack.Pop() stack.Pop()
fmt.Printf(" => %v\n", vm.params.GasLimit) dbg.Printf(" => %v\n", vm.params.GasLimit)
case MLOAD: // 0x51 case MLOAD: // 0x51
offset := stack.Pop64() offset := stack.Pop64()
@ -432,16 +473,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
stack.Push(RightPadWord256(data)) stack.Push(RightPadWord256(data))
fmt.Printf(" => 0x%X\n", data) dbg.Printf(" => 0x%X\n", data)
case MSTORE: // 0x52 case MSTORE: // 0x52
offset, data := stack.Pop64(), stack.Pop() offset, data := stack.Pop64(), stack.Pop()
dest, ok := subslice(memory, offset, 32, true) dest, ok := subslice(memory, offset, 32, false)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
copy(dest, data[:]) copy(dest, flip(data[:]))
fmt.Printf(" => 0x%X\n", data) dbg.Printf(" => 0x%X\n", data)
case MSTORE8: // 0x53 case MSTORE8: // 0x53
offset, val := stack.Pop64(), byte(stack.Pop64()&0xFF) offset, val := stack.Pop64(), byte(stack.Pop64()&0xFF)
@ -449,19 +490,21 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
memory[offset] = val memory[offset] = val
fmt.Printf(" => [%v] 0x%X\n", offset, val) dbg.Printf(" => [%v] 0x%X\n", offset, val)
case SLOAD: // 0x54 case SLOAD: // 0x54
loc := stack.Pop() loc := stack.Pop()
data := vm.appState.GetStorage(callee.Address, loc) data := vm.appState.GetStorage(callee.Address, loc)
stack.Push(data) stack.Push(flipWord(data))
fmt.Printf(" {0x%X : 0x%X}\n", loc, data) dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
case SSTORE: // 0x55 case SSTORE: // 0x55
loc, data := stack.Pop(), stack.Pop() loc, data := stack.Pop(), stack.Pop()
loc = flipWord(loc)
data = flipWord(data)
vm.appState.SetStorage(callee.Address, loc, data) vm.appState.SetStorage(callee.Address, loc, data)
useGas(gas, GasStorageUpdate) useGas(gas, GasStorageUpdate)
fmt.Printf(" {0x%X : 0x%X}\n", loc, data) dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
case JUMP: // 0x56 case JUMP: // 0x56
err = jump(code, stack.Pop64(), &pc) err = jump(code, stack.Pop64(), &pc)
@ -473,7 +516,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
err = jump(code, pos, &pc) err = jump(code, pos, &pc)
continue continue
} }
fmt.Printf(" ~> false\n") dbg.Printf(" ~> false\n")
case PC: // 0x58 case PC: // 0x58
stack.Push64(pc) stack.Push64(pc)
@ -483,10 +526,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case GAS: // 0x5A case GAS: // 0x5A
stack.Push64(*gas) stack.Push64(*gas)
fmt.Printf(" => %X\n", *gas) dbg.Printf(" => %X\n", *gas)
case JUMPDEST: // 0x5B case JUMPDEST: // 0x5B
fmt.Printf("\n") dbg.Printf("\n")
// Do nothing // Do nothing
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: 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:
@ -498,17 +541,17 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
res := RightPadWord256(codeSegment) res := RightPadWord256(codeSegment)
stack.Push(res) stack.Push(res)
pc += a pc += a
fmt.Printf(" => 0x%X\n", res) dbg.Printf(" => 0x%X\n", res)
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1) n := int(op - DUP1 + 1)
stack.Dup(n) stack.Dup(n)
fmt.Printf(" => [%d] 0x%X\n", n, stack.Peek().Bytes()) dbg.Printf(" => [%d] 0x%X\n", n, stack.Peek().Bytes())
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16: case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2) n := int(op - SWAP1 + 2)
stack.Swap(n) stack.Swap(n)
fmt.Printf(" => [%d]\n", n) dbg.Printf(" => [%d]\n", n)
case LOG0, LOG1, LOG2, LOG3, LOG4: case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0) n := int(op - LOG0)
@ -528,7 +571,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
vm.params.BlockHeight, vm.params.BlockHeight,
} }
vm.appState.AddLog(log) vm.appState.AddLog(log)
fmt.Printf(" => %v\n", log) dbg.Printf(" => %v\n", log)
case CREATE: // 0xF0 case CREATE: // 0xF0
contractValue := stack.Pop64() contractValue := stack.Pop64()
@ -560,7 +603,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
addr, value := stack.Pop(), stack.Pop64() addr, value := stack.Pop(), stack.Pop64()
inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs
retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs
fmt.Printf(" => %X\n", addr) dbg.Printf(" => %X\n", addr)
// Get the arguments from the memory // Get the arguments from the memory
args, ok := subslice(memory, inOffset, inSize, false) args, ok := subslice(memory, inOffset, inSize, false)
@ -613,7 +656,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
// Handle remaining gas. // Handle remaining gas.
*gas += gasLimit *gas += gasLimit
fmt.Printf("resume %X (%v)\n", callee.Address, gas) dbg.Printf("resume %X (%v)\n", callee.Address, gas)
case RETURN: // 0xF3 case RETURN: // 0xF3
offset, size := stack.Pop64(), stack.Pop64() offset, size := stack.Pop64(), stack.Pop64()
@ -621,7 +664,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
fmt.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret) dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret)
return ret, nil return ret, nil
case SUICIDE: // 0xFF case SUICIDE: // 0xFF
@ -629,7 +672,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
if ok = useGas(gas, GasGetAccount); !ok { if ok = useGas(gas, GasGetAccount); !ok {
return nil, firstErr(err, ErrInsufficientGas) return nil, firstErr(err, ErrInsufficientGas)
} }
// TODO if the receiver is Zero256, then make it the fee. // TODO if the receiver is , then make it the fee.
receiver := vm.appState.GetAccount(addr) receiver := vm.appState.GetAccount(addr)
if receiver == nil { if receiver == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
@ -638,11 +681,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
receiver.Balance += balance receiver.Balance += balance
vm.appState.UpdateAccount(receiver) vm.appState.UpdateAccount(receiver)
vm.appState.RemoveAccount(callee) vm.appState.RemoveAccount(callee)
fmt.Printf(" => (%X) %v\n", addr[:4], balance) dbg.Printf(" => (%X) %v\n", addr[:4], balance)
fallthrough fallthrough
default: default:
fmt.Printf("(pc) %-3v Invalid opcode %X\n", pc, op) dbg.Printf("(pc) %-3v Invalid opcode %X\n", pc, op)
panic(fmt.Errorf("Invalid opcode %X", op)) panic(fmt.Errorf("Invalid opcode %X", op))
} }
@ -677,10 +720,10 @@ func codeGetOp(code []byte, n uint64) OpCode {
func jump(code []byte, to uint64, pc *uint64) (err error) { func jump(code []byte, to uint64, pc *uint64) (err error) {
dest := codeGetOp(code, to) dest := codeGetOp(code, to)
if dest != JUMPDEST { if dest != JUMPDEST {
fmt.Printf(" ~> %v invalid jump dest %v\n", to, dest) dbg.Printf(" ~> %v invalid jump dest %v\n", to, dest)
return ErrInvalidJumpDest return ErrInvalidJumpDest
} }
fmt.Printf(" ~> %v\n", to) dbg.Printf(" ~> %v\n", to)
*pc = to *pc = to
return nil return nil
} }
@ -713,10 +756,25 @@ func transfer(from, to *Account, amount uint64) error {
} }
func flip(in []byte) []byte { func flip(in []byte) []byte {
l2 := len(in) / 2
flipped := make([]byte, len(in)) flipped := make([]byte, len(in))
for i := 0; i < len(flipped)/2; i++ { // copy the middle bit (if its even it will get overwritten)
if len(in) != 0 {
flipped[l2] = in[l2]
}
for i := 0; i < l2; i++ {
flipped[i] = in[len(in)-1-i] flipped[i] = in[len(in)-1-i]
flipped[len(in)-1-i] = in[i] flipped[len(in)-1-i] = in[i]
} }
return flipped return flipped
} }
func flipWord(in Word256) Word256 {
word := Word256{}
// copy the middle bit (if its even it will get overwritten)
for i := 0; i < 16; i++ {
word[i] = in[len(in)-1-i]
word[len(in)-1-i] = in[i]
}
return word
}