mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-26 19:21:44 +00:00
Transcribe vm changes from vm_fixes by Ethan
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
. "github.com/tendermint/tendermint/vm"
|
||||
"github.com/tendermint/tendermint/vm/sha3"
|
||||
@ -85,33 +83,6 @@ func (fas *FakeAppState) AddLog(log *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.
|
||||
func createAddress(creator *Account) Word256 {
|
||||
nonce := creator.Nonce
|
||||
|
99
vm/test/vm_test.go
Normal file
99
vm/test/vm_test.go
Normal 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
250
vm/vm.go
@ -3,7 +3,7 @@ package vm
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
"github.com/tendermint/tendermint/vm/sha3"
|
||||
@ -24,12 +24,21 @@ var (
|
||||
ErrInvalidContract = errors.New("Invalid contract")
|
||||
)
|
||||
|
||||
type Debug bool
|
||||
|
||||
const (
|
||||
dataStackCapacity = 1024
|
||||
callStackCapacity = 100 // TODO ensure usage.
|
||||
memoryCapacity = 1024 * 1024 // 1 MB
|
||||
dataStackCapacity = 1024
|
||||
callStackCapacity = 100 // TODO ensure usage.
|
||||
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 {
|
||||
appState AppState
|
||||
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.
|
||||
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 (
|
||||
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)
|
||||
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 {
|
||||
|
||||
@ -98,90 +107,123 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
return nil, nil
|
||||
|
||||
case ADD: // 0x01
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
stack.Push64(x + y)
|
||||
fmt.Printf(" %v + %v = %v\n", x, y, x+y)
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
//stack.Push64(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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
stack.Push64(x * y)
|
||||
fmt.Printf(" %v * %v = %v\n", x, y, x*y)
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
//stack.Push64(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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
stack.Push64(x - y)
|
||||
fmt.Printf(" %v - %v = %v\n", x, y, x-y)
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
//stack.Push64(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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
if y == 0 { // TODO
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
//stack.Push64(x / y)
|
||||
x, y := stack.Pop(), stack.Pop()
|
||||
if y.IsZero() { // TODO
|
||||
stack.Push(Zero256)
|
||||
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0)
|
||||
dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0)
|
||||
} else {
|
||||
stack.Push64(x / y)
|
||||
fmt.Printf(" %v / %v = %v\n", x, y, x/y)
|
||||
xb := new(big.Int).SetBytes(flip(x[:]))
|
||||
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
|
||||
// TODO ... big?
|
||||
x, y := int64(stack.Pop64()), int64(stack.Pop64())
|
||||
if y == 0 { // TODO
|
||||
stack.Push(Zero256)
|
||||
fmt.Printf(" %v / %v = %v (TODO)\n", x, y, 0)
|
||||
dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0)
|
||||
} else {
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
if y == 0 { // TODO
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
x, y := stack.Pop(), stack.Pop()
|
||||
if y.IsZero() { // TODO
|
||||
stack.Push(Zero256)
|
||||
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
|
||||
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
|
||||
} else {
|
||||
stack.Push64(x % y)
|
||||
fmt.Printf(" %v %% %v = %v\n", x, y, x%y)
|
||||
xb := new(big.Int).SetBytes(flip(x[:]))
|
||||
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
|
||||
// TODO ... big?
|
||||
x, y := int64(stack.Pop64()), int64(stack.Pop64())
|
||||
if y == 0 { // TODO
|
||||
stack.Push(Zero256)
|
||||
fmt.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
|
||||
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
|
||||
} else {
|
||||
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
|
||||
// TODO ... big?
|
||||
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
|
||||
if z == 0 { // TODO
|
||||
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 {
|
||||
stack.Push64(x % y)
|
||||
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z)
|
||||
stack.Push64((x + y) % z)
|
||||
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z)
|
||||
}
|
||||
|
||||
case MULMOD: // 0x09
|
||||
// TODO ... big?
|
||||
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
|
||||
if z == 0 { // TODO
|
||||
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 {
|
||||
stack.Push64(x % y)
|
||||
fmt.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z)
|
||||
stack.Push64((x * y) % z)
|
||||
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z)
|
||||
}
|
||||
|
||||
case EXP: // 0x0A
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
stack.Push64(ExpUint64(x, y))
|
||||
fmt.Printf(" %v ** %v = %v\n", x, y, uint64(math.Pow(float64(x), float64(y))))
|
||||
//x, y := stack.Pop64(), stack.Pop64()
|
||||
//stack.Push64(ExpUint64(x, 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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
res := (y << uint(x)) >> x
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
@ -190,7 +232,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
} else {
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
@ -199,7 +241,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
} else {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
if x > y {
|
||||
if x == y {
|
||||
stack.Push64(1)
|
||||
} else {
|
||||
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
|
||||
x := stack.Pop64()
|
||||
@ -235,27 +277,27 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
} else {
|
||||
stack.Push(Zero256)
|
||||
}
|
||||
fmt.Printf(" %v == 0 = %v\n", x, x == 0)
|
||||
dbg.Printf(" %v == 0 = %v\n", x, x == 0)
|
||||
|
||||
case AND: // 0x16
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
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
|
||||
x, y := stack.Pop64(), stack.Pop64()
|
||||
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
|
||||
x := stack.Pop64()
|
||||
stack.Push64(^x)
|
||||
fmt.Printf(" !%v = %v\n", x, ^x)
|
||||
dbg.Printf(" !%v = %v\n", x, ^x)
|
||||
|
||||
case BYTE: // 0x1A
|
||||
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]
|
||||
}
|
||||
stack.Push64(uint64(res))
|
||||
fmt.Printf(" => 0x%X\n", res)
|
||||
dbg.Printf(" => 0x%X\n", res)
|
||||
|
||||
case SHA3: // 0x20
|
||||
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)
|
||||
stack.PushBytes(data)
|
||||
fmt.Printf(" => (%v) %X\n", size, data)
|
||||
dbg.Printf(" => (%v) %X\n", size, data)
|
||||
|
||||
case ADDRESS: // 0x30
|
||||
stack.Push(callee.Address)
|
||||
fmt.Printf(" => %X\n", callee.Address)
|
||||
dbg.Printf(" => %X\n", callee.Address)
|
||||
|
||||
case BALANCE: // 0x31
|
||||
addr := stack.Pop()
|
||||
@ -294,19 +336,19 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
}
|
||||
balance := acc.Balance
|
||||
stack.Push64(balance)
|
||||
fmt.Printf(" => %v (%X)\n", balance, addr)
|
||||
dbg.Printf(" => %v (%X)\n", balance, addr)
|
||||
|
||||
case ORIGIN: // 0x32
|
||||
stack.Push(vm.origin)
|
||||
fmt.Printf(" => %X\n", vm.origin)
|
||||
dbg.Printf(" => %X\n", vm.origin)
|
||||
|
||||
case CALLER: // 0x33
|
||||
stack.Push(caller.Address)
|
||||
fmt.Printf(" => %X\n", caller.Address)
|
||||
dbg.Printf(" => %X\n", caller.Address)
|
||||
|
||||
case CALLVALUE: // 0x34
|
||||
stack.Push64(value)
|
||||
fmt.Printf(" => %v\n", value)
|
||||
dbg.Printf(" => %v\n", value)
|
||||
|
||||
case CALLDATALOAD: // 0x35
|
||||
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)
|
||||
}
|
||||
stack.Push(RightPadWord256(data))
|
||||
fmt.Printf(" => 0x%X\n", data)
|
||||
dbg.Printf(" => 0x%X\n", data)
|
||||
|
||||
case CALLDATASIZE: // 0x36
|
||||
stack.Push64(uint64(len(input)))
|
||||
fmt.Printf(" => %d\n", len(input))
|
||||
dbg.Printf(" => %d\n", len(input))
|
||||
|
||||
case CALLDATACOPY: // 0x37
|
||||
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)
|
||||
}
|
||||
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
|
||||
l := uint64(len(code))
|
||||
stack.Push64(l)
|
||||
fmt.Printf(" => %d\n", l)
|
||||
dbg.Printf(" => %d\n", l)
|
||||
|
||||
case CODECOPY: // 0x39
|
||||
memOff := stack.Pop64()
|
||||
codeOff := stack.Pop64()
|
||||
length := stack.Pop64()
|
||||
fmt.Println("CODECOPY: codeOff, length, codelength", codeOff, length, len(code))
|
||||
data, ok := subslice(code, codeOff, length, false)
|
||||
if !ok {
|
||||
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)
|
||||
}
|
||||
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
|
||||
stack.Push(Zero256)
|
||||
fmt.Printf(" => %X (GASPRICE IS DEPRECATED)\n")
|
||||
dbg.Printf(" => %X (GASPRICE IS DEPRECATED)\n")
|
||||
|
||||
case EXTCODESIZE: // 0x3B
|
||||
addr := stack.Pop()
|
||||
@ -373,7 +414,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
code := acc.Code
|
||||
l := uint64(len(code))
|
||||
stack.Push64(l)
|
||||
fmt.Printf(" => %d\n", l)
|
||||
dbg.Printf(" => %d\n", l)
|
||||
|
||||
case EXTCODECOPY: // 0x3C
|
||||
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)
|
||||
}
|
||||
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
|
||||
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
|
||||
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
|
||||
time := vm.params.BlockTime
|
||||
stack.Push64(uint64(time))
|
||||
fmt.Printf(" => 0x%X\n", time)
|
||||
dbg.Printf(" => 0x%X\n", time)
|
||||
|
||||
case BLOCKHEIGHT: // 0x43
|
||||
number := uint64(vm.params.BlockHeight)
|
||||
stack.Push64(number)
|
||||
fmt.Printf(" => 0x%X\n", number)
|
||||
dbg.Printf(" => 0x%X\n", number)
|
||||
|
||||
case GASLIMIT: // 0x45
|
||||
stack.Push64(vm.params.GasLimit)
|
||||
fmt.Printf(" => %v\n", vm.params.GasLimit)
|
||||
dbg.Printf(" => %v\n", vm.params.GasLimit)
|
||||
|
||||
case POP: // 0x50
|
||||
stack.Pop()
|
||||
fmt.Printf(" => %v\n", vm.params.GasLimit)
|
||||
dbg.Printf(" => %v\n", vm.params.GasLimit)
|
||||
|
||||
case MLOAD: // 0x51
|
||||
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)
|
||||
}
|
||||
stack.Push(RightPadWord256(data))
|
||||
fmt.Printf(" => 0x%X\n", data)
|
||||
dbg.Printf(" => 0x%X\n", data)
|
||||
|
||||
case MSTORE: // 0x52
|
||||
offset, data := stack.Pop64(), stack.Pop()
|
||||
dest, ok := subslice(memory, offset, 32, true)
|
||||
dest, ok := subslice(memory, offset, 32, false)
|
||||
if !ok {
|
||||
return nil, firstErr(err, ErrMemoryOutOfBounds)
|
||||
}
|
||||
copy(dest, data[:])
|
||||
fmt.Printf(" => 0x%X\n", data)
|
||||
copy(dest, flip(data[:]))
|
||||
dbg.Printf(" => 0x%X\n", data)
|
||||
|
||||
case MSTORE8: // 0x53
|
||||
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)
|
||||
}
|
||||
memory[offset] = val
|
||||
fmt.Printf(" => [%v] 0x%X\n", offset, val)
|
||||
dbg.Printf(" => [%v] 0x%X\n", offset, val)
|
||||
|
||||
case SLOAD: // 0x54
|
||||
loc := stack.Pop()
|
||||
data := vm.appState.GetStorage(callee.Address, loc)
|
||||
stack.Push(data)
|
||||
fmt.Printf(" {0x%X : 0x%X}\n", loc, data)
|
||||
stack.Push(flipWord(data))
|
||||
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
|
||||
|
||||
case SSTORE: // 0x55
|
||||
loc, data := stack.Pop(), stack.Pop()
|
||||
loc = flipWord(loc)
|
||||
data = flipWord(data)
|
||||
vm.appState.SetStorage(callee.Address, loc, data)
|
||||
useGas(gas, GasStorageUpdate)
|
||||
fmt.Printf(" {0x%X : 0x%X}\n", loc, data)
|
||||
dbg.Printf(" {0x%X : 0x%X}\n", loc, data)
|
||||
|
||||
case JUMP: // 0x56
|
||||
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)
|
||||
continue
|
||||
}
|
||||
fmt.Printf(" ~> false\n")
|
||||
dbg.Printf(" ~> false\n")
|
||||
|
||||
case PC: // 0x58
|
||||
stack.Push64(pc)
|
||||
@ -483,10 +526,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
|
||||
case GAS: // 0x5A
|
||||
stack.Push64(*gas)
|
||||
fmt.Printf(" => %X\n", *gas)
|
||||
dbg.Printf(" => %X\n", *gas)
|
||||
|
||||
case JUMPDEST: // 0x5B
|
||||
fmt.Printf("\n")
|
||||
dbg.Printf("\n")
|
||||
// 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:
|
||||
@ -498,17 +541,17 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
res := RightPadWord256(codeSegment)
|
||||
stack.Push(res)
|
||||
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:
|
||||
n := int(op - DUP1 + 1)
|
||||
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:
|
||||
n := int(op - SWAP1 + 2)
|
||||
stack.Swap(n)
|
||||
fmt.Printf(" => [%d]\n", n)
|
||||
dbg.Printf(" => [%d]\n", n)
|
||||
|
||||
case LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||
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.appState.AddLog(log)
|
||||
fmt.Printf(" => %v\n", log)
|
||||
dbg.Printf(" => %v\n", log)
|
||||
|
||||
case CREATE: // 0xF0
|
||||
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()
|
||||
inOffset, inSize := stack.Pop64(), stack.Pop64() // inputs
|
||||
retOffset, retSize := stack.Pop64(), stack.Pop64() // outputs
|
||||
fmt.Printf(" => %X\n", addr)
|
||||
dbg.Printf(" => %X\n", addr)
|
||||
|
||||
// Get the arguments from the memory
|
||||
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.
|
||||
*gas += gasLimit
|
||||
|
||||
fmt.Printf("resume %X (%v)\n", callee.Address, gas)
|
||||
dbg.Printf("resume %X (%v)\n", callee.Address, gas)
|
||||
|
||||
case RETURN: // 0xF3
|
||||
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 {
|
||||
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
|
||||
|
||||
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 {
|
||||
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)
|
||||
if receiver == nil {
|
||||
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
|
||||
vm.appState.UpdateAccount(receiver)
|
||||
vm.appState.RemoveAccount(callee)
|
||||
fmt.Printf(" => (%X) %v\n", addr[:4], balance)
|
||||
dbg.Printf(" => (%X) %v\n", addr[:4], balance)
|
||||
fallthrough
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@ -677,10 +720,10 @@ func codeGetOp(code []byte, n uint64) OpCode {
|
||||
func jump(code []byte, to uint64, pc *uint64) (err error) {
|
||||
dest := codeGetOp(code, to)
|
||||
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
|
||||
}
|
||||
fmt.Printf(" ~> %v\n", to)
|
||||
dbg.Printf(" ~> %v\n", to)
|
||||
*pc = to
|
||||
return nil
|
||||
}
|
||||
@ -713,10 +756,25 @@ func transfer(from, to *Account, amount uint64) error {
|
||||
}
|
||||
|
||||
func flip(in []byte) []byte {
|
||||
l2 := len(in) / 2
|
||||
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[len(in)-1-i] = in[i]
|
||||
}
|
||||
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
|
||||
}
|
||||
|
Reference in New Issue
Block a user