Merge branch 'unflip' into develop

This commit is contained in:
Jae Kwon 2015-04-18 02:18:17 -07:00
commit e007d1a58d
17 changed files with 287 additions and 208 deletions

View File

@ -22,10 +22,18 @@ func (p Uint64Slice) Search(x uint64) int { return SearchUint64s(p, x) }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func PutUint64(dest []byte, i uint64) { func PutUint64LE(dest []byte, i uint64) {
binary.LittleEndian.PutUint64(dest, i) binary.LittleEndian.PutUint64(dest, i)
} }
func GetUint64(src []byte) uint64 { func GetUint64LE(src []byte) uint64 {
return binary.LittleEndian.Uint64(src) return binary.LittleEndian.Uint64(src)
} }
func PutUint64BE(dest []byte, i uint64) {
binary.BigEndian.PutUint64(dest, i)
}
func GetUint64BE(src []byte) uint64 {
return binary.BigEndian.Uint64(src)
}

View File

@ -2,7 +2,6 @@ package common
import ( import (
"bytes" "bytes"
"encoding/binary"
"sort" "sort"
) )
@ -30,9 +29,9 @@ func (w Word256) Compare(other Word256) int {
} }
func Uint64ToWord256(i uint64) Word256 { func Uint64ToWord256(i uint64) Word256 {
word := Word256{} buf := [8]byte{}
PutUint64(word[:], i) PutUint64BE(buf[:], i)
return word return LeftPadWord256(buf[:])
} }
func RightPadWord256(bz []byte) (word Word256) { func RightPadWord256(bz []byte) (word Word256) {
@ -46,7 +45,8 @@ func LeftPadWord256(bz []byte) (word Word256) {
} }
func Uint64FromWord256(word Word256) uint64 { func Uint64FromWord256(word Word256) uint64 {
return binary.LittleEndian.Uint64(word[:]) buf := word.Postfix(8)
return GetUint64BE(buf)
} }
//------------------------------------- //-------------------------------------

View File

@ -235,9 +235,9 @@ func (ndb *nodeDB) SaveNode(t *IAVLTree, node *IAVLNode) {
if node.persisted { if node.persisted {
panic("Shouldn't be calling save on an already persisted node.") panic("Shouldn't be calling save on an already persisted node.")
} }
if _, ok := ndb.cache[string(node.hash)]; ok { /*if _, ok := ndb.cache[string(node.hash)]; ok {
panic("Shouldn't be calling save on an already cached node.") panic("Shouldn't be calling save on an already cached node.")
} }*/
// Save node bytes to db // Save node bytes to db
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
_, _, err := node.writeToCountHashes(t, buf) _, _, err := node.writeToCountHashes(t, buf)

View File

@ -36,7 +36,7 @@ func GetStorage(address, key []byte) (*ctypes.ResponseGetStorage, error) {
storageRoot := account.StorageRoot storageRoot := account.StorageRoot
storageTree := state.LoadStorage(storageRoot) storageTree := state.LoadStorage(storageRoot)
_, value := storageTree.Get(RightPadWord256(key).Bytes()) _, value := storageTree.Get(LeftPadWord256(key).Bytes())
if value == nil { if value == nil {
return &ctypes.ResponseGetStorage{key, nil}, nil return &ctypes.ResponseGetStorage{key, nil}, nil
} }

View File

@ -12,11 +12,11 @@ import (
func toVMAccount(acc *account.Account) *vm.Account { func toVMAccount(acc *account.Account) *vm.Account {
return &vm.Account{ return &vm.Account{
Address: RightPadWord256(acc.Address), Address: LeftPadWord256(acc.Address),
Balance: acc.Balance, Balance: acc.Balance,
Code: acc.Code, // This is crazy. Code: acc.Code, // This is crazy.
Nonce: uint64(acc.Sequence), Nonce: uint64(acc.Sequence),
StorageRoot: RightPadWord256(acc.StorageRoot), StorageRoot: LeftPadWord256(acc.StorageRoot),
Other: acc.PubKey, Other: acc.PubKey,
} }
} }
@ -26,9 +26,8 @@ func toVMAccount(acc *account.Account) *vm.Account {
// Run a contract's code on an isolated and unpersisted state // Run a contract's code on an isolated and unpersisted state
// Cannot be used to create new contracts // Cannot be used to create new contracts
func Call(address, data []byte) (*ctypes.ResponseCall, error) { func Call(address, data []byte) (*ctypes.ResponseCall, error) {
st := consensusState.GetState() // performs a copy st := consensusState.GetState() // performs a copy
cache := mempoolReactor.Mempool.GetCache() cache := state.NewBlockCache(st)
outAcc := cache.GetAccount(address) outAcc := cache.GetAccount(address)
if outAcc == nil { if outAcc == nil {
return nil, fmt.Errorf("Account %x does not exist", address) return nil, fmt.Errorf("Account %x does not exist", address)
@ -38,7 +37,7 @@ func Call(address, data []byte) (*ctypes.ResponseCall, error) {
txCache := state.NewTxCache(cache) txCache := state.NewTxCache(cache)
params := vm.Params{ params := vm.Params{
BlockHeight: uint64(st.LastBlockHeight), BlockHeight: uint64(st.LastBlockHeight),
BlockHash: RightPadWord256(st.LastBlockHash), BlockHash: LeftPadWord256(st.LastBlockHash),
BlockTime: st.LastBlockTime.Unix(), BlockTime: st.LastBlockTime.Unix(),
GasLimit: 10000000, GasLimit: 10000000,
} }
@ -63,7 +62,7 @@ func CallCode(code, data []byte) (*ctypes.ResponseCall, error) {
txCache := state.NewTxCache(cache) txCache := state.NewTxCache(cache)
params := vm.Params{ params := vm.Params{
BlockHeight: uint64(st.LastBlockHeight), BlockHeight: uint64(st.LastBlockHeight),
BlockHash: RightPadWord256(st.LastBlockHash), BlockHash: LeftPadWord256(st.LastBlockHash),
BlockTime: st.LastBlockTime.Unix(), BlockTime: st.LastBlockTime.Unix(),
GasLimit: 10000000, GasLimit: 10000000,
} }

View File

@ -225,6 +225,7 @@ type WSConnection struct {
id string id string
wsConn *websocket.Conn wsConn *websocket.Conn
writeChan chan WSResponse writeChan chan WSResponse
quitChan chan struct{}
failedSends uint failedSends uint
started uint32 started uint32
stopped uint32 stopped uint32
@ -238,6 +239,7 @@ func NewWSConnection(wsConn *websocket.Conn) *WSConnection {
id: wsConn.RemoteAddr().String(), id: wsConn.RemoteAddr().String(),
wsConn: wsConn, wsConn: wsConn,
writeChan: make(chan WSResponse, WriteChanBufferSize), // buffered. we keep track when its full writeChan: make(chan WSResponse, WriteChanBufferSize), // buffered. we keep track when its full
quitChan: make(chan struct{}),
} }
} }
@ -256,8 +258,10 @@ func (con *WSConnection) Start(evsw *events.EventSwitch) {
// close the connection // close the connection
func (con *WSConnection) Stop() { func (con *WSConnection) Stop() {
if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) { if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) {
con.wsConn.Close() close(con.quitChan)
close(con.writeChan) // the write loop closes the websocket connection
// when it exits its loop, and the read loop
// closes the writeChan
} }
} }
@ -277,6 +281,7 @@ func (con *WSConnection) safeWrite(resp WSResponse) {
// read from the socket and subscribe to or unsubscribe from events // read from the socket and subscribe to or unsubscribe from events
func (con *WSConnection) read() { func (con *WSConnection) read() {
defer close(con.writeChan)
reaper := time.Tick(time.Second * WSConnectionReaperSeconds) reaper := time.Tick(time.Second * WSConnectionReaperSeconds)
for { for {
select { select {
@ -322,32 +327,30 @@ func (con *WSConnection) read() {
default: default:
con.safeWrite(WSResponse{Error: "Unknown request type: " + req.Type}) con.safeWrite(WSResponse{Error: "Unknown request type: " + req.Type})
} }
} }
} }
} }
// receives on a write channel and writes out on the socket // receives on a write channel and writes out on the socket
func (con *WSConnection) write() { func (con *WSConnection) write() {
defer con.wsConn.Close()
n, err := new(int64), new(error) n, err := new(int64), new(error)
for { for {
msg, more := <-con.writeChan select {
if !more { case msg := <-con.writeChan:
// the channel was closed, so ensure buf := new(bytes.Buffer)
// connection is stopped and return binary.WriteJSON(msg, buf, n, err)
con.Stop() if *err != nil {
return log.Error("Failed to marshal WSResponse to JSON", "error", err)
} } else {
buf := new(bytes.Buffer) if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
binary.WriteJSON(msg, buf, n, err) log.Error("Failed to write response on websocket", "error", err)
if *err != nil { con.Stop()
log.Error("Failed to write JSON WSResponse", "error", err) return
} else { }
if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
log.Error("Failed to write response on websocket", "error", err)
con.Stop()
return
} }
case <-con.quitChan:
return
} }
} }
} }

View File

@ -288,7 +288,7 @@ func simpleContract() ([]byte, []byte, []byte) {
// the is the code we need to return the contractCode when the contract is initialized // the is the code we need to return the contractCode when the contract is initialized
lenCode := len(contractCode) lenCode := len(contractCode)
// push code to the stack // push code to the stack
//code := append([]byte{byte(0x60 + lenCode - 1)}, LeftPadWord256(contractCode).Bytes()...) //code := append([]byte{byte(0x60 + lenCode - 1)}, RightPadWord256(contractCode).Bytes()...)
code := append([]byte{0x7f}, RightPadWord256(contractCode).Bytes()...) code := append([]byte{0x7f}, RightPadWord256(contractCode).Bytes()...)
// store it in memory // store it in memory
code = append(code, []byte{0x60, 0x0, 0x52}...) code = append(code, []byte{0x60, 0x0, 0x52}...)

View File

@ -119,8 +119,8 @@ func testGetStorage(t *testing.T, typ string) {
mempoolCount = 0 mempoolCount = 0
v := getStorage(t, typ, contractAddr, []byte{0x1}) v := getStorage(t, typ, contractAddr, []byte{0x1})
got := RightPadWord256(v) got := LeftPadWord256(v)
expected := RightPadWord256([]byte{0x5}) expected := LeftPadWord256([]byte{0x5})
if got.Compare(expected) != 0 { if got.Compare(expected) != 0 {
t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), expected.Bytes()) t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), expected.Bytes())
} }

View File

@ -106,7 +106,7 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
_, val_ := storage.Get(key.Bytes()) _, val_ := storage.Get(key.Bytes())
value = Zero256 value = Zero256
if val_ != nil { if val_ != nil {
value = RightPadWord256(val_.([]byte)) value = LeftPadWord256(val_.([]byte))
} }
cache.storages[Tuple256{addr, key}] = storageInfo{value, false} cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
return value return value

View File

@ -395,7 +395,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
txCache = NewTxCache(blockCache) txCache = NewTxCache(blockCache)
params = vm.Params{ params = vm.Params{
BlockHeight: uint64(_s.LastBlockHeight), BlockHeight: uint64(_s.LastBlockHeight),
BlockHash: RightPadWord256(_s.LastBlockHash), BlockHash: LeftPadWord256(_s.LastBlockHash),
BlockTime: _s.LastBlockTime.Unix(), BlockTime: _s.LastBlockTime.Unix(),
GasLimit: 10000000, GasLimit: 10000000,
} }

View File

@ -147,7 +147,7 @@ func (cache *TxCache) AddLog(log *vm.Log) {
func NewContractAddress(caller []byte, nonce uint64) []byte { func NewContractAddress(caller []byte, nonce uint64) []byte {
temp := make([]byte, 32+8) temp := make([]byte, 32+8)
copy(temp, caller) copy(temp, caller)
PutUint64(temp[32:], nonce) PutUint64LE(temp[32:], nonce)
return sha3.Sha3(temp)[:20] return sha3.Sha3(temp)[:20]
} }
@ -158,7 +158,7 @@ func toVMAccount(acc *ac.Account) *vm.Account {
Balance: acc.Balance, Balance: acc.Balance,
Code: acc.Code, // This is crazy. Code: acc.Code, // This is crazy.
Nonce: uint64(acc.Sequence), Nonce: uint64(acc.Sequence),
StorageRoot: RightPadWord256(acc.StorageRoot), StorageRoot: LeftPadWord256(acc.StorageRoot),
Other: acc.PubKey, Other: acc.PubKey,
} }
} }

26
vm/common.go Normal file
View File

@ -0,0 +1,26 @@
package vm
import (
"math/big"
)
// To256
//
// "cast" the big int to a 256 big int (i.e., limit to)
var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
func U256(x *big.Int) *big.Int {
x.And(x, tt256m1)
return x
}
func S256(x *big.Int) *big.Int {
if x.Cmp(tt255) < 0 {
return x
} else {
// We don't want to modify x, ever
return new(big.Int).Sub(x, tt256)
}
}

View File

@ -39,7 +39,7 @@ func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) {
return nil, err return nil, err
} }
hashed := sha3.Sha3(recovered[1:]) hashed := sha3.Sha3(recovered[1:])
return RightPadBytes(hashed, 32), nil return LeftPadBytes(hashed, 32), nil
} }
func sha256Func(input []byte, gas *uint64) (output []byte, err error) { func sha256Func(input []byte, gas *uint64) (output []byte, err error) {
@ -73,7 +73,7 @@ func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return RightPadBytes(hasher.Sum(nil), 32), nil return LeftPadBytes(hasher.Sum(nil), 32), nil
} }
func identityFunc(input []byte, gas *uint64) (output []byte, err error) { func identityFunc(input []byte, gas *uint64) (output []byte, err error) {

View File

@ -51,7 +51,7 @@ func (st *Stack) PushBytes(bz []byte) {
if len(bz) != 32 { if len(bz) != 32 {
panic("Invalid bytes size: expected 32") panic("Invalid bytes size: expected 32")
} }
st.Push(RightPadWord256(bz)) st.Push(LeftPadWord256(bz))
} }
func (st *Stack) Push64(i uint64) { func (st *Stack) Push64(i uint64) {
@ -73,7 +73,8 @@ func (st *Stack) PopBytes() []byte {
} }
func (st *Stack) Pop64() uint64 { func (st *Stack) Pop64() uint64 {
return GetUint64(st.Pop().Bytes()) d := st.Pop()
return Uint64FromWord256(d)
} }
func (st *Stack) Len() int { func (st *Stack) Len() int {
@ -105,11 +106,13 @@ func (st *Stack) Peek() Word256 {
return st.data[st.ptr-1] return st.data[st.ptr-1]
} }
func (st *Stack) Print() { func (st *Stack) Print(n int) {
fmt.Println("### stack ###") fmt.Println("### stack ###")
if st.ptr > 0 { if st.ptr > 0 {
for i, val := range st.data { nn := MinInt(n, st.ptr)
fmt.Printf("%-3d %v\n", i, val) for j, i := 0, st.ptr-1; i > st.ptr-1-nn; i-- {
fmt.Printf("%-3d %X\n", j, st.data[i])
j += 1
} }
} else { } else {
fmt.Println("-- empty --") fmt.Println("-- empty --")

View File

@ -89,6 +89,6 @@ func createAddress(creator *Account) Word256 {
creator.Nonce += 1 creator.Nonce += 1
temp := make([]byte, 32+8) temp := make([]byte, 32+8)
copy(temp, creator.Address[:]) copy(temp, creator.Address[:])
PutUint64(temp[32:], nonce) PutUint64LE(temp[32:], nonce)
return RightPadWord256(sha3.Sha3(temp)[:20]) return LeftPadWord256(sha3.Sha3(temp)[:20])
} }

View File

@ -64,10 +64,10 @@ func TestSubcurrency(t *testing.T) {
st := newAppState() st := newAppState()
// Create accounts // Create accounts
account1 := &Account{ account1 := &Account{
Address: RightPadWord256(makeBytes(20)), Address: LeftPadWord256(makeBytes(20)),
} }
account2 := &Account{ account2 := &Account{
Address: RightPadWord256(makeBytes(20)), Address: LeftPadWord256(makeBytes(20)),
} }
st.accounts[account1.Address.String()] = account1 st.accounts[account1.Address.String()] = account1
st.accounts[account2.Address.String()] = account2 st.accounts[account2.Address.String()] = account2

350
vm/vm.go
View File

@ -1,6 +1,7 @@
package vm package vm
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
@ -131,196 +132,253 @@ 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()
//stack.Push64(x + y)
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
sum := new(big.Int).Add(xb, yb) sum := new(big.Int).Add(xb, yb)
stack.Push(RightPadWord256(flip(sum.Bytes()))) res := LeftPadWord256(U256(sum).Bytes())
dbg.Printf(" %v + %v = %v\n", xb, yb, sum) stack.Push(res)
dbg.Printf(" %v + %v = %v (%X)\n", xb, yb, sum, res)
case MUL: // 0x02 case MUL: // 0x02
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(x * y)
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
prod := new(big.Int).Mul(xb, yb) prod := new(big.Int).Mul(xb, yb)
stack.Push(RightPadWord256(flip(prod.Bytes()))) res := LeftPadWord256(U256(prod).Bytes())
dbg.Printf(" %v * %v = %v\n", xb, yb, prod) stack.Push(res)
dbg.Printf(" %v * %v = %v (%X)\n", xb, yb, prod, res)
case SUB: // 0x03 case SUB: // 0x03
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(x - y)
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
diff := new(big.Int).Sub(xb, yb) diff := new(big.Int).Sub(xb, yb)
stack.Push(RightPadWord256(flip(diff.Bytes()))) res := LeftPadWord256(U256(diff).Bytes())
dbg.Printf(" %v - %v = %v\n", xb, yb, diff) stack.Push(res)
dbg.Printf(" %v - %v = %v (%X)\n", xb, yb, diff, res)
case DIV: // 0x04 case DIV: // 0x04
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(x / y)
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO if y.IsZero() {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0) dbg.Printf(" %x / %x = %v\n", x, y, 0)
} else { } else {
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
div := new(big.Int).Div(xb, yb) div := new(big.Int).Div(xb, yb)
stack.Push(RightPadWord256(flip(div.Bytes()))) res := LeftPadWord256(U256(div).Bytes())
dbg.Printf(" %v / %v = %v\n", xb, yb, div) stack.Push(res)
dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res)
} }
case SDIV: // 0x05 case SDIV: // 0x05
// TODO ... big? x, y := stack.Pop(), stack.Pop()
x, y := int64(stack.Pop64()), int64(stack.Pop64()) if y.IsZero() {
if y == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %x / %x = %v\n", x, y, 0)
} else { } else {
stack.Push64(uint64(x / y)) xb := S256(new(big.Int).SetBytes(x[:]))
dbg.Printf(" %v / %v = %v\n", x, y, x/y) 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)
} }
case MOD: // 0x06 case MOD: // 0x06
//x, y := stack.Pop64(), stack.Pop64()
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO if y.IsZero() {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else { } else {
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
mod := new(big.Int).Mod(xb, yb) mod := new(big.Int).Mod(xb, yb)
stack.Push(RightPadWord256(flip(mod.Bytes()))) res := LeftPadWord256(U256(mod).Bytes())
dbg.Printf(" %v %% %v = %v\n", xb, yb, mod) stack.Push(res)
dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
} }
case SMOD: // 0x07 case SMOD: // 0x07
// TODO ... big? x, y := stack.Pop(), stack.Pop()
x, y := int64(stack.Pop64()), int64(stack.Pop64()) if y.IsZero() {
if y == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0) dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else { } else {
stack.Push64(uint64(x % y)) xb := S256(new(big.Int).SetBytes(x[:]))
dbg.Printf(" %v %% %v = %v\n", x, y, x%y) 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)
} }
case ADDMOD: // 0x08 case ADDMOD: // 0x08
// TODO ... big? x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() if z.IsZero() {
if z == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else { } else {
stack.Push64((x + y) % z) xb := new(big.Int).SetBytes(x[:])
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z) 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)
} }
case MULMOD: // 0x09 case MULMOD: // 0x09
// TODO ... big? x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64() if z.IsZero() {
if z == 0 { // TODO
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" (%v + %v) %% %v = %v (TODO)\n", x, y, z, 0) dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else { } else {
stack.Push64((x * y) % z) xb := new(big.Int).SetBytes(x[:])
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z) 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)
} }
case EXP: // 0x0A case EXP: // 0x0A
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(ExpUint64(x, y))
x, y := stack.Pop(), stack.Pop() x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:])) xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(flip(y[:])) yb := new(big.Int).SetBytes(y[:])
pow := new(big.Int).Exp(xb, yb, big.NewInt(0)) pow := new(big.Int).Exp(xb, yb, big.NewInt(0))
stack.Push(RightPadWord256(flip(pow.Bytes()))) res := LeftPadWord256(U256(pow).Bytes())
dbg.Printf(" %v ** %v = %v\n", xb, yb, pow) stack.Push(res)
dbg.Printf(" %v ** %v = %v (%X)\n", xb, yb, pow, res)
case SIGNEXTEND: // 0x0B case SIGNEXTEND: // 0x0B
x, y := stack.Pop64(), stack.Pop64() back := stack.Pop()
res := (y << uint(x)) >> x backb := new(big.Int).SetBytes(back[:])
stack.Push64(res) if backb.Cmp(big.NewInt(31)) < 0 {
dbg.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res) 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)
}
case LT: // 0x10 case LT: // 0x10
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop(), stack.Pop()
if x < y { xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) < 0 {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v < %v = %v\n", xb, yb, 0)
} }
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.Pop(), stack.Pop()
if x > y { xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) > 0 {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v > %v = %v\n", xb, yb, 0)
} }
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 := stack.Pop(), stack.Pop()
if x < y { xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) < 0 {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v < %v = %v\n", xb, yb, 0)
} }
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 := stack.Pop(), stack.Pop()
if x > y { xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) > 0 {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v > %v = %v\n", xb, yb, 0)
} }
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.Pop(), stack.Pop()
if x == y { if bytes.Equal(x[:], y[:]) {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %X == %X = %v\n", x, y, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %X == %X = %v\n", x, y, 0)
} }
dbg.Printf(" %v == %v = %v\n", x, y, x == y)
case ISZERO: // 0x15 case ISZERO: // 0x15
x := stack.Pop64() x := stack.Pop()
if x == 0 { if x.IsZero() {
stack.Push64(1) stack.Push64(1)
dbg.Printf(" %v == 0 = %v\n", x, 1)
} else { } else {
stack.Push(Zero256) stack.Push(Zero256)
dbg.Printf(" %v == 0 = %v\n", 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.Pop(), stack.Pop()
stack.Push64(x & y) z := [32]byte{}
dbg.Printf(" %v & %v = %v\n", x, y, x&y) for i := 0; i < 32; i++ {
z[i] = x[i] & y[i]
}
stack.Push(z)
dbg.Printf(" %X & %X = %X\n", x, y, z)
case OR: // 0x17 case OR: // 0x17
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop(), stack.Pop()
stack.Push64(x | y) z := [32]byte{}
dbg.Printf(" %v | %v = %v\n", x, y, x|y) for i := 0; i < 32; i++ {
z[i] = x[i] | y[i]
}
stack.Push(z)
dbg.Printf(" %X | %X = %X\n", x, y, z)
case XOR: // 0x18 case XOR: // 0x18
x, y := stack.Pop64(), stack.Pop64() x, y := stack.Pop(), stack.Pop()
stack.Push64(x ^ y) z := [32]byte{}
dbg.Printf(" %v ^ %v = %v\n", x, y, x^y) for i := 0; i < 32; i++ {
z[i] = x[i] ^ y[i]
}
stack.Push(z)
dbg.Printf(" %X ^ %X = %X\n", x, y, z)
case NOT: // 0x19 case NOT: // 0x19
x := stack.Pop64() x := stack.Pop()
stack.Push64(^x) z := [32]byte{}
dbg.Printf(" !%v = %v\n", x, ^x) for i := 0; i < 32; i++ {
z[i] = ^x[i]
}
stack.Push(z)
dbg.Printf(" !%X = %X\n", x, z)
case BYTE: // 0x1A case BYTE: // 0x1A
idx, val := stack.Pop64(), stack.Pop() idx, val := stack.Pop64(), stack.Pop()
@ -336,12 +394,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInsufficientGas) return nil, firstErr(err, ErrInsufficientGas)
} }
offset, size := stack.Pop64(), stack.Pop64() offset, size := stack.Pop64(), stack.Pop64()
data, ok := subslice(memory, offset, size, false) data, ok := subslice(memory, offset, size)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
data = sha3.Sha3(data) data = sha3.Sha3(data)
stack.PushBytes(flip(data)) stack.PushBytes(data)
dbg.Printf(" => (%v) %X\n", size, data) dbg.Printf(" => (%v) %X\n", size, data)
case ADDRESS: // 0x30 case ADDRESS: // 0x30
@ -353,7 +411,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)
} }
acc := vm.appState.GetAccount(flipWord(addr)) // TODO ensure that 20byte lengths are supported. acc := vm.appState.GetAccount(addr)
if acc == nil { if acc == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
@ -375,12 +433,13 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case CALLDATALOAD: // 0x35 case CALLDATALOAD: // 0x35
offset := stack.Pop64() offset := stack.Pop64()
data, ok := subslice(input, offset, 32, true) data, ok := subslice(input, offset, 32)
if !ok { if !ok {
return nil, firstErr(err, ErrInputOutOfBounds) return nil, firstErr(err, ErrInputOutOfBounds)
} }
stack.Push(RightPadWord256(data)) res := LeftPadWord256(data)
dbg.Printf(" => 0x%X\n", RightPadWord256(data)) stack.Push(res)
dbg.Printf(" => 0x%X\n", res)
case CALLDATASIZE: // 0x36 case CALLDATASIZE: // 0x36
stack.Push64(uint64(len(input))) stack.Push64(uint64(len(input)))
@ -390,11 +449,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64() memOff := stack.Pop64()
inputOff := stack.Pop64() inputOff := stack.Pop64()
length := stack.Pop64() length := stack.Pop64()
data, ok := subslice(input, inputOff, length, false) data, ok := subslice(input, inputOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrInputOutOfBounds) return nil, firstErr(err, ErrInputOutOfBounds)
} }
dest, ok := subslice(memory, memOff, length, false) dest, ok := subslice(memory, memOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -410,11 +469,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64() memOff := stack.Pop64()
codeOff := stack.Pop64() codeOff := stack.Pop64()
length := stack.Pop64() length := stack.Pop64()
data, ok := subslice(code, codeOff, length, false) data, ok := subslice(code, codeOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds) return nil, firstErr(err, ErrCodeOutOfBounds)
} }
dest, ok := subslice(memory, memOff, length, false) dest, ok := subslice(memory, memOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -430,7 +489,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)
} }
acc := vm.appState.GetAccount(flipWord(addr)) acc := vm.appState.GetAccount(addr)
if acc == nil { if acc == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
@ -444,7 +503,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)
} }
acc := vm.appState.GetAccount(flipWord(addr)) acc := vm.appState.GetAccount(addr)
if acc == nil { if acc == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
@ -452,11 +511,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64() memOff := stack.Pop64()
codeOff := stack.Pop64() codeOff := stack.Pop64()
length := stack.Pop64() length := stack.Pop64()
data, ok := subslice(code, codeOff, length, false) data, ok := subslice(code, codeOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds) return nil, firstErr(err, ErrCodeOutOfBounds)
} }
dest, ok := subslice(memory, memOff, length, false) dest, ok := subslice(memory, memOff, length)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -491,20 +550,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case MLOAD: // 0x51 case MLOAD: // 0x51
offset := stack.Pop64() offset := stack.Pop64()
data, ok := subslice(memory, offset, 32, true) data, ok := subslice(memory, offset, 32)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
stack.Push(RightPadWord256(data)) stack.Push(LeftPadWord256(data))
dbg.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, false) dest, ok := subslice(memory, offset, 32)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
copy(dest, flip(data[:])) copy(dest, data[:])
dbg.Printf(" => 0x%X\n", data) dbg.Printf(" => 0x%X\n", data)
case MSTORE8: // 0x53 case MSTORE8: // 0x53
@ -532,8 +591,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
continue continue
case JUMPI: // 0x57 case JUMPI: // 0x57
pos, cond := stack.Pop64(), stack.Pop64() pos, cond := stack.Pop64(), stack.Pop()
if cond >= 1 { if !cond.IsZero() {
err = jump(code, pos, &pc) err = jump(code, pos, &pc)
continue continue
} }
@ -555,14 +614,15 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
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:
a := uint64(op - PUSH1 + 1) a := uint64(op - PUSH1 + 1)
codeSegment, ok := subslice(code, pc+1, a, true) codeSegment, ok := subslice(code, pc+1, a)
if !ok { if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds) return nil, firstErr(err, ErrCodeOutOfBounds)
} }
res := RightPadWord256(codeSegment) res := LeftPadWord256(codeSegment)
stack.Push(res) stack.Push(res)
pc += a pc += a
dbg.Printf(" => 0x%X\n", res) dbg.Printf(" => 0x%X\n", res)
stack.Print(10)
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)
@ -572,7 +632,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
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)
dbg.Printf(" => [%d]\n", n) dbg.Printf(" => [%d] %X\n", n, stack.Peek())
stack.Print(10)
case LOG0, LOG1, LOG2, LOG3, LOG4: case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0) n := int(op - LOG0)
@ -581,7 +642,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
topics[i] = stack.Pop() topics[i] = stack.Pop()
} }
data, ok := subslice(memory, offset, size, false) data, ok := subslice(memory, offset, size)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -597,7 +658,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case CREATE: // 0xF0 case CREATE: // 0xF0
contractValue := stack.Pop64() contractValue := stack.Pop64()
offset, size := stack.Pop64(), stack.Pop64() offset, size := stack.Pop64(), stack.Pop64()
input, ok := subslice(memory, offset, size, false) input, ok := subslice(memory, offset, size)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -627,7 +688,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
dbg.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)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -651,7 +712,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)
} }
acc := vm.appState.GetAccount(flipWord(addr)) acc := vm.appState.GetAccount(addr)
if acc == nil { if acc == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
@ -667,7 +728,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
stack.Push(Zero256) stack.Push(Zero256)
} else { } else {
stack.Push(One256) stack.Push(One256)
dest, ok := subslice(memory, retOffset, retSize, false) dest, ok := subslice(memory, retOffset, retSize)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -681,7 +742,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case RETURN: // 0xF3 case RETURN: // 0xF3
offset, size := stack.Pop64(), stack.Pop64() offset, size := stack.Pop64(), stack.Pop64()
ret, ok := subslice(memory, offset, size, false) ret, ok := subslice(memory, offset, size)
if !ok { if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds) return nil, firstErr(err, ErrMemoryOutOfBounds)
} }
@ -694,7 +755,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInsufficientGas) return nil, firstErr(err, ErrInsufficientGas)
} }
// TODO if the receiver is , then make it the fee. // TODO if the receiver is , then make it the fee.
receiver := vm.appState.GetAccount(flipWord(addr)) receiver := vm.appState.GetAccount(addr)
if receiver == nil { if receiver == nil {
return nil, firstErr(err, ErrUnknownAddress) return nil, firstErr(err, ErrUnknownAddress)
} }
@ -715,7 +776,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
} }
} }
func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bool) { func subslice(data []byte, offset, length uint64) (ret []byte, ok bool) {
size := uint64(len(data)) size := uint64(len(data))
if size < offset { if size < offset {
return nil, false return nil, false
@ -726,12 +787,15 @@ func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bo
ret, ok = data[offset:offset+length], true ret, ok = data[offset:offset+length], true
} }
if flip_ {
ret = flip(ret)
}
return return
} }
func rightMostBytes(data []byte, n int) []byte {
size := MinInt(len(data), n)
offset := len(data) - size
return data[offset:]
}
func codeGetOp(code []byte, n uint64) OpCode { func codeGetOp(code []byte, n uint64) OpCode {
if uint64(len(code)) <= n { if uint64(len(code)) <= n {
return OpCode(0) // stop return OpCode(0) // stop
@ -777,27 +841,3 @@ func transfer(from, to *Account, amount uint64) error {
return nil return nil
} }
} }
func flip(in []byte) []byte {
l2 := len(in) / 2
flipped := make([]byte, len(in))
// 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
}