Browse Source

Merge branch 'develop' of https://github.com/tendermint/tendermint into develop

pull/55/head
Ethan Buchman 10 years ago
parent
commit
f7639bf105
32 changed files with 599 additions and 281 deletions
  1. +17
    -2
      cmd/barak/main.go
  2. +31
    -20
      cmd/debora/main.go
  3. +84
    -0
      common/colors.go
  4. +10
    -2
      common/int.go
  5. +34
    -0
      common/os.go
  6. +17
    -0
      common/string.go
  7. +5
    -5
      common/word.go
  8. +44
    -6
      config/config.go
  9. +8
    -2
      consensus/state.go
  10. +34
    -0
      node/id.go
  11. +9
    -4
      node/node.go
  12. +3
    -5
      p2p/addrbook.go
  13. +5
    -12
      process/process.go
  14. +1
    -1
      rpc/core/accounts.go
  15. +7
    -2
      rpc/core/net.go
  16. +3
    -3
      rpc/core/txs.go
  17. +7
    -1
      rpc/core/types/responses.go
  18. +22
    -19
      rpc/handlers.go
  19. +1
    -1
      rpc/test/helpers_test.go
  20. +2
    -2
      rpc/test/tests_test.go
  21. +1
    -1
      state/block_cache.go
  22. +1
    -2
      state/execution.go
  23. +2
    -1
      state/priv_validator.go
  24. +2
    -2
      state/tx_cache.go
  25. +4
    -5
      state/validator_set.go
  26. +11
    -1
      state/validator_set_test.go
  27. +26
    -0
      vm/common.go
  28. +2
    -2
      vm/native.go
  29. +8
    -5
      vm/stack.go
  30. +2
    -2
      vm/test/fake_app_state.go
  31. +2
    -2
      vm/test/vm_test.go
  32. +194
    -171
      vm/vm.go

+ 17
- 2
cmd/barak/main.go View File

@ -14,6 +14,7 @@ import (
"os"
"reflect"
"sync"
"time"
"github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/cmd/barak/types"
@ -41,12 +42,14 @@ var barak = struct {
nonce uint64
processes map[string]*pcm.Process
validators []Validator
rootDir string
}{
mtx: sync.Mutex{},
pid: os.Getpid(),
nonce: 0,
processes: make(map[string]*pcm.Process),
validators: nil,
rootDir: "",
}
func main() {
@ -72,6 +75,13 @@ func main() {
}
barak.nonce = options.StartNonce
barak.validators = options.Validators
barak.rootDir = os.Getenv("BRKROOT")
if barak.rootDir == "" {
barak.rootDir = os.Getenv("HOME") + "/.barak"
}
// Write pid to file.
AtomicWriteFile(barak.rootDir+"/pidfile", []byte(Fmt("%v", barak.pid)))
// Debug.
fmt.Printf("Options: %v\n", options)
@ -111,7 +121,7 @@ func Run(authCommand AuthCommand) (interface{}, error) {
if err != nil {
return nil, err
}
log.Info(Fmt("Run() received command %v", reflect.TypeOf(command)))
log.Info(Fmt("Run() received command %v:\n%v", reflect.TypeOf(command), command))
// Issue command
switch c := command.(type) {
case CommandRunProcess:
@ -174,7 +184,12 @@ func RunProcess(wait bool, label string, execPath string, args []string, input s
}
// Otherwise, create one.
proc, err := pcm.Create(pcm.ProcessModeDaemon, label, execPath, args, input)
err := EnsureDir(barak.rootDir + "/outputs")
if err != nil {
return nil, fmt.Errorf("Failed to create outputs dir: %v", err)
}
outPath := Fmt("%v/outputs/%v_%v.out", barak.rootDir, label, time.Now().Format("2006_01_02_15_04_05_MST"))
proc, err := pcm.Create(pcm.ProcessModeDaemon, label, execPath, args, input, outPath)
if err == nil {
barak.processes[label] = proc
}


+ 31
- 20
cmd/debora/main.go View File

@ -17,25 +17,31 @@ var Config = struct {
PrivKey acm.PrivKey
}{}
var (
configFlag = cli.StringFlag{
Name: "config-file",
Value: ".debora/config.json",
Usage: "config file",
}
waitFlag = cli.BoolFlag{
Name: "wait",
Usage: "whether to wait for termination",
}
inputFlag = cli.StringFlag{
Name: "input",
Value: "",
Usage: "input to the program (e.g. stdin)",
}
)
func main() {
fmt.Printf("New Debora Process (PID: %d)\n", os.Getpid())
rootDir := os.Getenv("DEBROOT")
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.debora"
}
var (
configFlag = cli.StringFlag{
Name: "config-file",
Value: rootDir + "/config.json",
Usage: "config file",
}
waitFlag = cli.BoolFlag{
Name: "wait",
Usage: "whether to wait for termination",
}
inputFlag = cli.StringFlag{
Name: "input",
Value: "",
Usage: "input to the program (e.g. stdin)",
}
)
app := cli.NewApp()
app.Name = "debora"
app.Usage = "summons commands to barak"
@ -171,9 +177,14 @@ func cliListProcesses(c *cli.Context) {
} else {
fmt.Printf("%v processes:\n", remote)
for _, proc := range response.Processes {
fmt.Printf(" \"%v\" => `%v` (%v) start:%v end:%v output:%v\n",
proc.Label, proc.ExecPath, proc.Pid,
proc.StartTime, proc.EndTime, proc.OutputPath)
startTimeStr := Green(proc.StartTime.String())
endTimeStr := proc.EndTime.String()
if !proc.EndTime.IsZero() {
endTimeStr = Red(endTimeStr)
}
fmt.Printf(" %v start:%v end:%v output:%v\n",
RightPadString(Fmt("\"%v\" => `%v` (%v)", proc.Label, proc.ExecPath, proc.Pid), 40),
startTimeStr, endTimeStr, proc.OutputPath)
}
}
}


+ 84
- 0
common/colors.go View File

@ -0,0 +1,84 @@
package common
import (
"fmt"
"strings"
)
const (
ANSIReset = "\x1b[0m"
ANSIBright = "\x1b[1m"
ANSIDim = "\x1b[2m"
ANSIUnderscore = "\x1b[4m"
ANSIBlink = "\x1b[5m"
ANSIReverse = "\x1b[7m"
ANSIHidden = "\x1b[8m"
ANSIFgBlack = "\x1b[30m"
ANSIFgRed = "\x1b[31m"
ANSIFgGreen = "\x1b[32m"
ANSIFgYellow = "\x1b[33m"
ANSIFgBlue = "\x1b[34m"
ANSIFgMagenta = "\x1b[35m"
ANSIFgCyan = "\x1b[36m"
ANSIFgWhite = "\x1b[37m"
ANSIBgBlack = "\x1b[40m"
ANSIBgRed = "\x1b[41m"
ANSIBgGreen = "\x1b[42m"
ANSIBgYellow = "\x1b[43m"
ANSIBgBlue = "\x1b[44m"
ANSIBgMagenta = "\x1b[45m"
ANSIBgCyan = "\x1b[46m"
ANSIBgWhite = "\x1b[47m"
)
// color the string s with color 'color'
// unless s is already colored
func treat(s string, color string) string {
if len(s) > 2 && s[:2] == "\x1b[" {
return s
} else {
return color + s + ANSIReset
}
}
func treatAll(color string, args ...interface{}) string {
var parts []string
for _, arg := range args {
parts = append(parts, treat(fmt.Sprintf("%v", arg), color))
}
return strings.Join(parts, "")
}
func Black(args ...interface{}) string {
return treatAll(ANSIFgBlack, args...)
}
func Red(args ...interface{}) string {
return treatAll(ANSIFgRed, args...)
}
func Green(args ...interface{}) string {
return treatAll(ANSIFgGreen, args...)
}
func Yellow(args ...interface{}) string {
return treatAll(ANSIFgYellow, args...)
}
func Blue(args ...interface{}) string {
return treatAll(ANSIFgBlue, args...)
}
func Magenta(args ...interface{}) string {
return treatAll(ANSIFgMagenta, args...)
}
func Cyan(args ...interface{}) string {
return treatAll(ANSIFgCyan, args...)
}
func White(args ...interface{}) string {
return treatAll(ANSIFgWhite, args...)
}

+ 10
- 2
common/int.go 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)
}
func GetUint64(src []byte) uint64 {
func GetUint64LE(src []byte) uint64 {
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)
}

+ 34
- 0
common/os.go View File

@ -2,6 +2,7 @@ package common
import (
"fmt"
"io/ioutil"
"os"
"os/signal"
)
@ -26,3 +27,36 @@ func Exit(s string) {
fmt.Printf(s + "\n")
os.Exit(1)
}
// Writes to newBytes to filePath.
// Guaranteed not to lose *both* oldBytes and newBytes,
// (assuming that the OS is perfect)
func AtomicWriteFile(filePath string, newBytes []byte) error {
// If a file already exists there, copy to filePath+".bak" (overwrite anything)
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("Failed to read file %v. %v", filePath, err)
}
err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600)
if err != nil {
return fmt.Errorf("Failed to write file %v. %v", filePath+".bak", err)
}
}
// Write newBytes to filePath.
err := ioutil.WriteFile(filePath, newBytes, 0600)
if err != nil {
return fmt.Errorf("Failed to write file %v. %v", filePath, err)
}
return nil
}
func EnsureDir(dir string) error {
if _, err := os.Stat(dir); os.IsNotExist(err) {
err := os.MkdirAll(dir, 0700)
if err != nil {
return fmt.Errorf("Could not create directory %v. %v", dir, err)
}
}
return nil
}

+ 17
- 0
common/string.go View File

@ -2,6 +2,23 @@ package common
import (
"fmt"
"strings"
)
var Fmt = fmt.Sprintf
func RightPadString(s string, totalLength int) string {
remaining := totalLength - len(s)
if remaining > 0 {
s = s + strings.Repeat(" ", remaining)
}
return s
}
func LeftPadString(s string, totalLength int) string {
remaining := totalLength - len(s)
if remaining > 0 {
s = strings.Repeat(" ", remaining) + s
}
return s
}

+ 5
- 5
common/word.go View File

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


+ 44
- 6
config/config.go View File

@ -20,7 +20,7 @@ func App() *confer.Config {
appMtx.Lock()
defer appMtx.Unlock()
if app == nil {
Init(".tendermint")
Init("")
}
return app
}
@ -35,6 +35,7 @@ func SetApp(a *confer.Config) {
var defaultConfig = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
Moniker = "anonymous"
Network = "tendermint_testnet0"
ListenAddr = "0.0.0.0:8080"
# First node to connect to. Command-line overridable.
@ -66,17 +67,47 @@ ListenAddr = "127.0.0.1:8081"
var DefaultGenesis = `{
"Accounts": [
{
"Address": "29BF3A0A13001A0D23533386BE03E74923AF1179",
"Amount": 2099900000000000
"Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C",
"Amount": 2099600000000000
}
],
"Validators": [
{
"PubKey": [1, "3A2C5C341FFC1D5F7AB518519FF8289D3BFAB82DFD6E167B926FAD72C1BF10F8"],
"PubKey": [1, "323A31EB01877858592AB7D593E9447110AFCD3ACF280D60C4F8E7C04FACC955"],
"Amount": 100000000000,
"UnbondTo": [
{
"Address": "29BF3A0A13001A0D23533386BE03E74923AF1179",
"Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C",
"Amount": 100000000000
}
]
},
{
"PubKey": [1, "DD2206E8F889EED3ABAAECEB2D18962D062A887346241820493FFE3B1DEF255D"],
"Amount": 100000000000,
"UnbondTo": [
{
"Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C",
"Amount": 100000000000
}
]
},
{
"PubKey": [1, "1B3256A3754FC6AB01110C166199A2F619E2D76DB3EE751E376FE404AC9FDCFF"],
"Amount": 100000000000,
"UnbondTo": [
{
"Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C",
"Amount": 100000000000
}
]
},
{
"PubKey": [1, "62CF1048BAEBB4FFFF360D5E896E3F4EC72D03D55183596931ED14995D512926"],
"Amount": 100000000000,
"UnbondTo": [
{
"Address": "69988763FCF806AC35D1A2F9C4885B7DD7B0599C",
"Amount": 100000000000
}
]
@ -86,6 +117,7 @@ var DefaultGenesis = `{
// NOTE: If you change this, maybe also change defaultConfig
func initDefaults(rootDir string) {
app.SetDefault("Moniker", "anonymous")
app.SetDefault("Network", "tendermint_testnet0")
app.SetDefault("ListenAddr", "0.0.0.0:8080")
app.SetDefault("DB.Backend", "leveldb")
@ -104,7 +136,13 @@ func initDefaults(rootDir string) {
func Init(rootDir string) {
// Get RootDir
// Get rootdir
if rootDir == "" {
rootDir = os.Getenv("TMROOT")
}
if rootDir == "" {
rootDir = os.Getenv("HOME") + "/.tendermint"
}
configFile := path.Join(rootDir, "config.toml")
genesisFile := path.Join(rootDir, "genesis.json")


+ 8
- 2
consensus/state.go View File

@ -318,10 +318,10 @@ func (cs *ConsensusState) stepTransitionRoutine() {
// For clarity, all state transitions that happen after some timeout are here.
// Schedule the next action by pushing a RoundAction{} to cs.runActionCh.
scheduleNextAction := func() {
rs := cs.getRoundState()
go func() {
// NOTE: We can push directly to runActionCh because
// we're running in a separate goroutine, which avoids deadlocks.
rs := cs.getRoundState()
round, roundStartTime, RoundDuration, _, elapsedRatio := calcRoundInfo(rs.StartTime)
log.Debug("Scheduling next action", "height", rs.Height, "round", round, "step", rs.Step, "roundStartTime", roundStartTime, "elapsedRatio", elapsedRatio)
switch rs.Step {
@ -358,7 +358,12 @@ func (cs *ConsensusState) stepTransitionRoutine() {
}()
}
scheduleNextAction()
if cs.getRoundState().Step < RoundStepCommit {
scheduleNextAction()
} else {
// Race condition with receipt of commits, maybe.
// We shouldn't have to schedule anything.
}
// NOTE: All ConsensusState.RunAction*() calls come from here.
// Since only one routine calls them, it is safe to assume that
@ -533,6 +538,7 @@ func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) {
// After the call cs.Step becomes RoundStepNewRound.
func (cs *ConsensusState) setupNewRound(round uint) {
// XXX Looks like this is just not called.
// Sanity check
if round == 0 {
panic("setupNewRound() should never be called for round 0")


+ 34
- 0
node/id.go View File

@ -0,0 +1,34 @@
package node
import (
acm "github.com/tendermint/tendermint/account"
"time"
)
type NodeID struct {
Name string
PubKey acm.PubKey
}
type PrivNodeID struct {
NodeID
PrivKey acm.PrivKey
}
type NodeGreeting struct {
NodeID
Version string
Network string
Message string
Time time.Time
}
type SignedNodeGreeting struct {
NodeGreeting
Signature acm.Signature
}
func (pnid *PrivNodeID) SignGreeting() *SignedNodeGreeting {
//greeting := NodeGreeting{}
return nil
}

+ 9
- 4
node/node.go View File

@ -45,11 +45,16 @@ func NewNode() *Node {
// Get PrivValidator
var privValidator *sm.PrivValidator
if _, err := os.Stat(config.App().GetString("PrivValidatorFile")); err == nil {
privValidator = sm.LoadPrivValidator(config.App().GetString("PrivValidatorFile"))
log.Info("Loaded PrivValidator", "file", config.App().GetString("PrivValidatorFile"), "privValidator", privValidator)
privValidatorFile := config.App().GetString("PrivValidatorFile")
if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = sm.LoadPrivValidator(privValidatorFile)
log.Info("Loaded PrivValidator",
"file", privValidatorFile, "privValidator", privValidator)
} else {
log.Info("No PrivValidator found", "file", config.App().GetString("PrivValidatorFile"))
privValidator = sm.GenPrivValidator()
privValidator.SetFile(privValidatorFile)
privValidator.Save()
log.Info("Generated PrivValidator", "file", privValidatorFile)
}
eventSwitch := new(events.EventSwitch)


+ 3
- 5
p2p/addrbook.go View File

@ -319,14 +319,12 @@ func (a *AddrBook) saveToFile(filePath string) {
Addrs: addrs,
}
w, err := os.Create(filePath)
jsonBytes, err := json.MarshalIndent(aJSON, "", "\t")
if err != nil {
log.Error("Error opening file", "file", filePath, "error", err)
log.Error("Failed to save AddrBook to file", "err", err)
return
}
defer w.Close()
jsonBytes, err := json.MarshalIndent(aJSON, "", "\t")
_, err = w.Write(jsonBytes)
err = AtomicWriteFile(filePath, jsonBytes)
if err != nil {
log.Error("Failed to save AddrBook to file", "file", filePath, "error", err)
}


+ 5
- 12
process/process.go View File

@ -10,16 +10,6 @@ import (
"time"
)
func makeFile(prefix string) (string, *os.File) {
now := time.Now()
path := fmt.Sprintf("%v_%v.out", prefix, now.Format("2006_01_02_15_04_05_MST"))
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
return path, file
}
type Process struct {
Label string
ExecPath string
@ -40,8 +30,11 @@ const (
// execPath: command name
// args: args to command. (should not include name)
func Create(mode int, label string, execPath string, args []string, input string) (*Process, error) {
outPath, outFile := makeFile("output_" + label)
func Create(mode int, label string, execPath string, args []string, input string, outPath string) (*Process, error) {
outFile, err := os.OpenFile(outPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return nil, err
}
cmd := exec.Command(execPath, args...)
switch mode {
case ProcessModeStd:


+ 1
- 1
rpc/core/accounts.go View File

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


+ 7
- 2
rpc/core/net.go View File

@ -33,16 +33,21 @@ func Status() (*ctypes.ResponseStatus, error) {
func NetInfo() (*ctypes.ResponseNetInfo, error) {
listening := p2pSwitch.IsListening()
moniker := config.App().GetString("Moniker")
network := config.App().GetString("Network")
listeners := []string{}
for _, listener := range p2pSwitch.Listeners() {
listeners = append(listeners, listener.String())
}
peers := []string{}
peers := []ctypes.Peer{}
for _, peer := range p2pSwitch.Peers().List() {
peers = append(peers, peer.String())
peers = append(peers, ctypes.Peer{
Address: peer.Connection().RemoteAddress.String(),
IsOutbound: peer.IsOutbound(),
})
}
return &ctypes.ResponseNetInfo{
Moniker: moniker,
Network: network,
Listening: listening,
Listeners: listeners,


+ 3
- 3
rpc/core/txs.go View File

@ -16,7 +16,7 @@ func toVMAccount(acc *account.Account) *vm.Account {
Balance: acc.Balance,
Code: acc.Code, // This is crazy.
Nonce: uint64(acc.Sequence),
StorageRoot: RightPadWord256(acc.StorageRoot),
StorageRoot: LeftPadWord256(acc.StorageRoot),
Other: acc.PubKey,
}
}
@ -37,7 +37,7 @@ func Call(address, data []byte) (*ctypes.ResponseCall, error) {
txCache := state.NewTxCache(cache)
params := vm.Params{
BlockHeight: uint64(st.LastBlockHeight),
BlockHash: RightPadWord256(st.LastBlockHash),
BlockHash: LeftPadWord256(st.LastBlockHash),
BlockTime: st.LastBlockTime.Unix(),
GasLimit: 10000000,
}
@ -62,7 +62,7 @@ func CallCode(code, data []byte) (*ctypes.ResponseCall, error) {
txCache := state.NewTxCache(cache)
params := vm.Params{
BlockHeight: uint64(st.LastBlockHeight),
BlockHash: RightPadWord256(st.LastBlockHash),
BlockHash: LeftPadWord256(st.LastBlockHash),
BlockTime: st.LastBlockTime.Unix(),
GasLimit: 10000000,
}


+ 7
- 1
rpc/core/types/responses.go View File

@ -70,10 +70,16 @@ type ResponseStatus struct {
}
type ResponseNetInfo struct {
Moniker string
Network string
Listening bool
Listeners []string
Peers []string
Peers []Peer
}
type Peer struct {
Address string
IsOutbound bool
}
type ResponseSignTx struct {


+ 22
- 19
rpc/handlers.go View File

@ -225,6 +225,7 @@ type WSConnection struct {
id string
wsConn *websocket.Conn
writeChan chan WSResponse
quitChan chan struct{}
failedSends uint
started uint32
stopped uint32
@ -238,6 +239,7 @@ func NewWSConnection(wsConn *websocket.Conn) *WSConnection {
id: wsConn.RemoteAddr().String(),
wsConn: wsConn,
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
func (con *WSConnection) Stop() {
if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) {
con.wsConn.Close()
close(con.writeChan)
close(con.quitChan)
// 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
func (con *WSConnection) read() {
defer close(con.writeChan)
reaper := time.Tick(time.Second * WSConnectionReaperSeconds)
for {
select {
@ -322,32 +327,30 @@ func (con *WSConnection) read() {
default:
con.safeWrite(WSResponse{Error: "Unknown request type: " + req.Type})
}
}
}
}
// receives on a write channel and writes out on the socket
func (con *WSConnection) write() {
defer con.wsConn.Close()
n, err := new(int64), new(error)
for {
msg, more := <-con.writeChan
if !more {
// the channel was closed, so ensure
// connection is stopped and return
con.Stop()
return
}
buf := new(bytes.Buffer)
binary.WriteJSON(msg, buf, n, err)
if *err != nil {
log.Error("Failed to write JSON WSResponse", "error", err)
} 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
select {
case msg := <-con.writeChan:
buf := new(bytes.Buffer)
binary.WriteJSON(msg, buf, n, err)
if *err != nil {
log.Error("Failed to marshal WSResponse to JSON", "error", err)
} 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
}
}
}


+ 1
- 1
rpc/test/helpers_test.go 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
lenCode := len(contractCode)
// 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()...)
// store it in memory
code = append(code, []byte{0x60, 0x0, 0x52}...)


+ 2
- 2
rpc/test/tests_test.go View File

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


+ 1
- 1
state/block_cache.go View File

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


+ 1
- 2
state/execution.go View File

@ -152,7 +152,6 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
// Increment validator AccumPowers
s.BondedValidators.IncrementAccum(1)
s.LastBlockHeight = block.Height
s.LastBlockHash = block.Hash()
s.LastBlockParts = blockPartsHeader
@ -395,7 +394,7 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
txCache = NewTxCache(blockCache)
params = vm.Params{
BlockHeight: uint64(_s.LastBlockHeight),
BlockHash: RightPadWord256(_s.LastBlockHash),
BlockHash: LeftPadWord256(_s.LastBlockHash),
BlockTime: _s.LastBlockTime.Unix(),
GasLimit: 10000000,
}


+ 2
- 1
state/priv_validator.go View File

@ -99,8 +99,9 @@ func (privVal *PrivValidator) Save() {
func (privVal *PrivValidator) save() {
jsonBytes := binary.JSONBytes(privVal)
err := ioutil.WriteFile(privVal.filename, jsonBytes, 0700)
err := AtomicWriteFile(privVal.filename, jsonBytes)
if err != nil {
// `@; BOOM!!!
panic(err)
}
}


+ 2
- 2
state/tx_cache.go View File

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


+ 4
- 5
state/validator_set.go View File

@ -45,7 +45,6 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet {
// TODO: mind the overflow when times and votingPower shares too large.
func (valSet *ValidatorSet) IncrementAccum(times uint) {
// Add VotingPower * times to each validator and order into heap.
validatorsHeap := NewHeap()
for _, val := range valSet.Validators {
@ -56,12 +55,12 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) {
// Decrement the validator with most accum, times times.
for i := uint(0); i < times; i++ {
mostest := validatorsHeap.Peek().(*Validator)
if i == times-1 {
valSet.proposer = mostest
}
mostest.Accum -= int64(valSet.TotalVotingPower())
validatorsHeap.Update(mostest, accumComparable(mostest.Accum))
}
// The next proposer is the next most accums remaining
valSet.proposer = validatorsHeap.Peek().(*Validator)
}
func (valSet *ValidatorSet) Copy() *ValidatorSet {
@ -293,5 +292,5 @@ type accumComparable uint64
// We want to find the validator with the greatest accum.
func (ac accumComparable) Less(o interface{}) bool {
return uint64(ac) > uint64(o.(accumComparable))
return uint64(ac) < uint64(o.(accumComparable))
}

+ 11
- 1
state/validator_set_test.go View File

@ -5,6 +5,7 @@ import (
. "github.com/tendermint/tendermint/common"
"bytes"
"fmt"
"testing"
)
@ -41,6 +42,15 @@ func TestCopy(t *testing.T) {
}
}
func TestProposerSelection(t *testing.T) {
vset := randValidatorSet(10)
for i := 0; i < 100; i++ {
val := vset.Proposer()
fmt.Printf("Proposer: %v\n", val)
vset.IncrementAccum(1)
}
}
func BenchmarkValidatorSetCopy(b *testing.B) {
b.StopTimer()
vset := NewValidatorSet([]*Validator{})
@ -51,7 +61,7 @@ func BenchmarkValidatorSetCopy(b *testing.B) {
PubKey: privAccount.PubKey.(account.PubKeyEd25519),
}
if !vset.Add(val) {
panic("Failde to add validator")
panic("Failed to add validator")
}
}
b.StartTimer()


+ 26
- 0
vm/common.go 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)
}
}

+ 2
- 2
vm/native.go View File

@ -39,7 +39,7 @@ func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) {
return nil, err
}
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) {
@ -73,7 +73,7 @@ func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) {
if err != nil {
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) {


+ 8
- 5
vm/stack.go View File

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


+ 2
- 2
vm/test/fake_app_state.go View File

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

+ 2
- 2
vm/test/vm_test.go View File

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


+ 194
- 171
vm/vm.go View File

@ -1,6 +1,7 @@
package vm
import (
"bytes"
"errors"
"fmt"
"math/big"
@ -131,207 +132,253 @@ 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)
x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
sum := new(big.Int).Add(xb, yb)
stack.Push(RightPadWord256(flip(sum.Bytes())))
dbg.Printf(" %v + %v = %v\n", xb, yb, sum)
res := LeftPadWord256(U256(sum).Bytes())
stack.Push(res)
dbg.Printf(" %v + %v = %v (%X)\n", xb, yb, sum, res)
case MUL: // 0x02
//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[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
prod := new(big.Int).Mul(xb, yb)
stack.Push(RightPadWord256(flip(rightMostBytes(prod.Bytes(), 32))))
dbg.Printf(" %v * %v = %v\n", xb, yb, prod)
res := LeftPadWord256(U256(prod).Bytes())
stack.Push(res)
dbg.Printf(" %v * %v = %v (%X)\n", xb, yb, prod, res)
case SUB: // 0x03
//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[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
diff := new(big.Int).Sub(xb, yb)
stack.Push(RightPadWord256(flip(diff.Bytes())))
dbg.Printf(" %v - %v = %v\n", xb, yb, diff)
res := LeftPadWord256(U256(diff).Bytes())
stack.Push(res)
dbg.Printf(" %v - %v = %v (%X)\n", xb, yb, diff, res)
case DIV: // 0x04
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(x / y)
x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO
if y.IsZero() {
stack.Push(Zero256)
dbg.Printf(" %x / %x = %v (TODO)\n", x, y, 0)
dbg.Printf(" %x / %x = %v\n", x, y, 0)
} else {
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
div := new(big.Int).Div(xb, yb)
stack.Push(RightPadWord256(flip(div.Bytes())))
dbg.Printf(" %v / %v = %v\n", xb, yb, div)
res := LeftPadWord256(U256(div).Bytes())
stack.Push(res)
dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res)
}
case SDIV: // 0x05
// TODO ... big?
x, y := int64(stack.Pop64()), int64(stack.Pop64())
if y == 0 { // TODO
x, y := stack.Pop(), stack.Pop()
if y.IsZero() {
stack.Push(Zero256)
dbg.Printf(" %v / %v = %v (TODO)\n", x, y, 0)
dbg.Printf(" %x / %x = %v\n", x, y, 0)
} else {
stack.Push64(uint64(x / y))
dbg.Printf(" %v / %v = %v\n", x, y, x/y)
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
div := new(big.Int).Div(xb, yb)
res := LeftPadWord256(U256(div).Bytes())
stack.Push(res)
dbg.Printf(" %v / %v = %v (%X)\n", xb, yb, div, res)
}
case MOD: // 0x06
//x, y := stack.Pop64(), stack.Pop64()
x, y := stack.Pop(), stack.Pop()
if y.IsZero() { // TODO
if y.IsZero() {
stack.Push(Zero256)
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else {
xb := new(big.Int).SetBytes(flip(x[:]))
yb := new(big.Int).SetBytes(flip(y[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
mod := new(big.Int).Mod(xb, yb)
stack.Push(RightPadWord256(flip(mod.Bytes())))
dbg.Printf(" %v %% %v = %v\n", xb, yb, mod)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
}
case SMOD: // 0x07
// TODO ... big?
x, y := int64(stack.Pop64()), int64(stack.Pop64())
if y == 0 { // TODO
x, y := stack.Pop(), stack.Pop()
if y.IsZero() {
stack.Push(Zero256)
dbg.Printf(" %v %% %v = %v (TODO)\n", x, y, 0)
dbg.Printf(" %v %% %v = %v\n", x, y, 0)
} else {
stack.Push64(uint64(x % y))
dbg.Printf(" %v %% %v = %v\n", x, y, x%y)
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
mod := new(big.Int).Mod(xb, yb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v %% %v = %v (%X)\n", xb, yb, mod, res)
}
case ADDMOD: // 0x08
// TODO ... big?
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
if z == 0 { // TODO
x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
if z.IsZero() {
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 {
stack.Push64((x + y) % z)
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x+y)%z)
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
zb := new(big.Int).SetBytes(z[:])
add := new(big.Int).Add(xb, yb)
mod := new(big.Int).Mod(add, zb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v + %v %% %v = %v (%X)\n",
xb, yb, zb, mod, res)
}
case MULMOD: // 0x09
// TODO ... big?
x, y, z := stack.Pop64(), stack.Pop64(), stack.Pop64()
if z == 0 { // TODO
x, y, z := stack.Pop(), stack.Pop(), stack.Pop()
if z.IsZero() {
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 {
stack.Push64((x * y) % z)
dbg.Printf(" (%v + %v) %% %v = %v\n", x, y, z, (x*y)%z)
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
zb := new(big.Int).SetBytes(z[:])
mul := new(big.Int).Mul(xb, yb)
mod := new(big.Int).Mod(mul, zb)
res := LeftPadWord256(U256(mod).Bytes())
stack.Push(res)
dbg.Printf(" %v * %v %% %v = %v (%X)\n",
xb, yb, zb, mod, res)
}
case EXP: // 0x0A
//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[:]))
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(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)
res := LeftPadWord256(U256(pow).Bytes())
stack.Push(res)
dbg.Printf(" %v ** %v = %v (%X)\n", xb, yb, pow, res)
case SIGNEXTEND: // 0x0B
x, y := stack.Pop64(), stack.Pop64()
res := (y << uint(x)) >> x
stack.Push64(res)
dbg.Printf(" (%v << %v) >> %v = %v\n", y, x, x, res)
back := stack.Pop()
backb := new(big.Int).SetBytes(back[:])
if backb.Cmp(big.NewInt(31)) < 0 {
bit := uint(backb.Uint64()*8 + 7)
num := stack.Pop()
numb := new(big.Int).SetBytes(num[:])
mask := new(big.Int).Lsh(big.NewInt(1), bit)
mask.Sub(mask, big.NewInt(1))
if numb.Bit(int(bit)) == 1 {
numb.Or(numb, mask.Not(mask))
} else {
numb.Add(numb, mask)
}
res := LeftPadWord256(U256(numb).Bytes())
dbg.Printf(" = %v (%X)", numb, res)
stack.Push(res)
}
case LT: // 0x10
x, y := stack.Pop64(), stack.Pop64()
if x < y {
x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) < 0 {
stack.Push64(1)
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
} else {
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
x, y := stack.Pop64(), stack.Pop64()
if x > y {
x, y := stack.Pop(), stack.Pop()
xb := new(big.Int).SetBytes(x[:])
yb := new(big.Int).SetBytes(y[:])
if xb.Cmp(yb) > 0 {
stack.Push64(1)
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
} else {
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
x, y := int64(stack.Pop64()), int64(stack.Pop64())
if x < y {
x, y := stack.Pop(), stack.Pop()
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) < 0 {
stack.Push64(1)
dbg.Printf(" %v < %v = %v\n", xb, yb, 1)
} else {
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
x, y := int64(stack.Pop64()), int64(stack.Pop64())
if x > y {
x, y := stack.Pop(), stack.Pop()
xb := S256(new(big.Int).SetBytes(x[:]))
yb := S256(new(big.Int).SetBytes(y[:]))
if xb.Cmp(yb) > 0 {
stack.Push64(1)
dbg.Printf(" %v > %v = %v\n", xb, yb, 1)
} else {
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
x, y := stack.Pop64(), stack.Pop64()
if x == y {
x, y := stack.Pop(), stack.Pop()
if bytes.Equal(x[:], y[:]) {
stack.Push64(1)
dbg.Printf(" %X == %X = %v\n", x, y, 1)
} else {
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
x := stack.Pop64()
if x == 0 {
x := stack.Pop()
if x.IsZero() {
stack.Push64(1)
dbg.Printf(" %v == 0 = %v\n", x, 1)
} else {
stack.Push(Zero256)
dbg.Printf(" %v == 0 = %v\n", x, 0)
}
dbg.Printf(" %v == 0 = %v\n", x, x == 0)
case AND: // 0x16
//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[:]))
res := new(big.Int).And(xb, yb)
stack.Push(RightPadWord256(flip(res.Bytes())))
dbg.Printf(" %v & %v = %v\n", xb, yb, res)
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] & y[i]
}
stack.Push(z)
dbg.Printf(" %X & %X = %X\n", x, y, z)
case OR: // 0x17
//x, y := stack.Pop64(), stack.Pop64()
//stack.Push64(x | y)
//dbg.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[:]))
res := new(big.Int).Or(xb, yb)
stack.Push(RightPadWord256(flip(res.Bytes())))
dbg.Printf(" %v & %v = %v\n", xb, yb, res)
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] | y[i]
}
stack.Push(z)
dbg.Printf(" %X | %X = %X\n", x, y, z)
case XOR: // 0x18
x, y := stack.Pop64(), stack.Pop64()
stack.Push64(x ^ y)
dbg.Printf(" %v ^ %v = %v\n", x, y, x^y)
x, y := stack.Pop(), stack.Pop()
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = x[i] ^ y[i]
}
stack.Push(z)
dbg.Printf(" %X ^ %X = %X\n", x, y, z)
case NOT: // 0x19
x := stack.Pop64()
stack.Push64(^x)
dbg.Printf(" !%v = %v\n", x, ^x)
x := stack.Pop()
z := [32]byte{}
for i := 0; i < 32; i++ {
z[i] = ^x[i]
}
stack.Push(z)
dbg.Printf(" !%X = %X\n", x, z)
case BYTE: // 0x1A
idx, val := stack.Pop64(), stack.Pop()
@ -347,24 +394,24 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInsufficientGas)
}
offset, size := stack.Pop64(), stack.Pop64()
data, ok := subslice(memory, offset, size, false)
data, ok := subslice(memory, offset, size)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
data = sha3.Sha3(data)
stack.PushBytes(flip(data))
stack.PushBytes(data)
dbg.Printf(" => (%v) %X\n", size, data)
case ADDRESS: // 0x30
stack.Push(flipWord(callee.Address))
dbg.Printf(" => %X\n", flipWord(callee.Address))
stack.Push(callee.Address)
dbg.Printf(" => %X\n", callee.Address)
case BALANCE: // 0x31
addr := stack.Pop()
if ok = useGas(gas, GasGetAccount); !ok {
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 {
return nil, firstErr(err, ErrUnknownAddress)
}
@ -373,12 +420,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
dbg.Printf(" => %v (%X)\n", balance, addr)
case ORIGIN: // 0x32
stack.Push(flipWord(vm.origin))
dbg.Printf(" => %X\n", flipWord(vm.origin))
stack.Push(vm.origin)
dbg.Printf(" => %X\n", vm.origin)
case CALLER: // 0x33
stack.Push(flipWord(caller.Address))
dbg.Printf(" => %X\n", flipWord(caller.Address))
stack.Push(caller.Address)
dbg.Printf(" => %X\n", caller.Address)
case CALLVALUE: // 0x34
stack.Push64(value)
@ -386,12 +433,13 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case CALLDATALOAD: // 0x35
offset := stack.Pop64()
data, ok := subslice(input, offset, 32, true)
data, ok := subslice(input, offset, 32)
if !ok {
return nil, firstErr(err, ErrInputOutOfBounds)
}
stack.Push(RightPadWord256(data))
dbg.Printf(" => 0x%X\n", RightPadWord256(data))
res := LeftPadWord256(data)
stack.Push(res)
dbg.Printf(" => 0x%X\n", res)
case CALLDATASIZE: // 0x36
stack.Push64(uint64(len(input)))
@ -401,11 +449,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64()
inputOff := stack.Pop64()
length := stack.Pop64()
data, ok := subslice(input, inputOff, length, false)
data, ok := subslice(input, inputOff, length)
if !ok {
return nil, firstErr(err, ErrInputOutOfBounds)
}
dest, ok := subslice(memory, memOff, length, false)
dest, ok := subslice(memory, memOff, length)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -421,11 +469,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64()
codeOff := stack.Pop64()
length := stack.Pop64()
data, ok := subslice(code, codeOff, length, false)
data, ok := subslice(code, codeOff, length)
if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds)
}
dest, ok := subslice(memory, memOff, length, false)
dest, ok := subslice(memory, memOff, length)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -441,7 +489,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)
}
acc := vm.appState.GetAccount(flipWord(addr))
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
}
@ -455,7 +503,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)
}
acc := vm.appState.GetAccount(flipWord(addr))
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
}
@ -463,11 +511,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
memOff := stack.Pop64()
codeOff := stack.Pop64()
length := stack.Pop64()
data, ok := subslice(code, codeOff, length, false)
data, ok := subslice(code, codeOff, length)
if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds)
}
dest, ok := subslice(memory, memOff, length, false)
dest, ok := subslice(memory, memOff, length)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -502,20 +550,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case MLOAD: // 0x51
offset := stack.Pop64()
data, ok := subslice(memory, offset, 32, true)
data, ok := subslice(memory, offset, 32)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
stack.Push(RightPadWord256(data))
stack.Push(LeftPadWord256(data))
dbg.Printf(" => 0x%X\n", data)
case MSTORE: // 0x52
offset, data := stack.Pop64(), stack.Pop()
dest, ok := subslice(memory, offset, 32, false)
dest, ok := subslice(memory, offset, 32)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
copy(dest, flip(data[:]))
copy(dest, data[:])
dbg.Printf(" => 0x%X\n", data)
case MSTORE8: // 0x53
@ -543,8 +591,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
continue
case JUMPI: // 0x57
pos, cond := stack.Pop64(), stack.Pop64()
if cond >= 1 {
pos, cond := stack.Pop64(), stack.Pop()
if !cond.IsZero() {
err = jump(code, pos, &pc)
continue
}
@ -566,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:
a := uint64(op - PUSH1 + 1)
codeSegment, ok := subslice(code, pc+1, a, true)
codeSegment, ok := subslice(code, pc+1, a)
if !ok {
return nil, firstErr(err, ErrCodeOutOfBounds)
}
res := RightPadWord256(codeSegment)
res := LeftPadWord256(codeSegment)
stack.Push(res)
pc += a
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:
n := int(op - DUP1 + 1)
@ -583,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:
n := int(op - SWAP1 + 2)
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:
n := int(op - LOG0)
@ -592,7 +642,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
for i := 0; i < n; i++ {
topics[i] = stack.Pop()
}
data, ok := subslice(memory, offset, size, false)
data, ok := subslice(memory, offset, size)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -608,7 +658,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case CREATE: // 0xF0
contractValue := stack.Pop64()
offset, size := stack.Pop64(), stack.Pop64()
input, ok := subslice(memory, offset, size, false)
input, ok := subslice(memory, offset, size)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -627,7 +677,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
stack.Push(Zero256)
} else {
newAccount.Code = ret // Set the code
stack.Push(flipWord(newAccount.Address))
stack.Push(newAccount.Address)
}
case CALL, CALLCODE: // 0xF1, 0xF2
@ -638,7 +688,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
dbg.Printf(" => %X\n", addr)
// Get the arguments from the memory
args, ok := subslice(memory, inOffset, inSize, false)
args, ok := subslice(memory, inOffset, inSize)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -662,7 +712,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)
}
acc := vm.appState.GetAccount(flipWord(addr))
acc := vm.appState.GetAccount(addr)
if acc == nil {
return nil, firstErr(err, ErrUnknownAddress)
}
@ -678,7 +728,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
stack.Push(Zero256)
} else {
stack.Push(One256)
dest, ok := subslice(memory, retOffset, retSize, false)
dest, ok := subslice(memory, retOffset, retSize)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -692,7 +742,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
case RETURN: // 0xF3
offset, size := stack.Pop64(), stack.Pop64()
ret, ok := subslice(memory, offset, size, false)
ret, ok := subslice(memory, offset, size)
if !ok {
return nil, firstErr(err, ErrMemoryOutOfBounds)
}
@ -705,7 +755,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
return nil, firstErr(err, ErrInsufficientGas)
}
// TODO if the receiver is , then make it the fee.
receiver := vm.appState.GetAccount(flipWord(addr))
receiver := vm.appState.GetAccount(addr)
if receiver == nil {
return nil, firstErr(err, ErrUnknownAddress)
}
@ -726,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))
if size < offset {
return nil, false
@ -737,9 +787,6 @@ func subslice(data []byte, offset, length uint64, flip_ bool) (ret []byte, ok bo
ret, ok = data[offset:offset+length], true
}
if flip_ {
ret = flip(ret)
}
return
}
@ -794,27 +841,3 @@ func transfer(from, to *Account, amount uint64) error {
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
}

Loading…
Cancel
Save