diff options
author | obscuren <geffobscura@gmail.com> | 2014-01-11 22:27:08 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-01-11 22:27:08 +0800 |
commit | 9571a512861d4a44c36d368f4baa15b2aa81c37d (patch) | |
tree | c5412a119ab885570351f42e512dd2d62d0bae61 | |
parent | 8bbf879cb31e9cb28700773ed788421f9935ac36 (diff) | |
download | dexon-9571a512861d4a44c36d368f4baa15b2aa81c37d.tar.gz dexon-9571a512861d4a44c36d368f4baa15b2aa81c37d.tar.zst dexon-9571a512861d4a44c36d368f4baa15b2aa81c37d.zip |
gofmt no coding standards
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | block_manager.go | 120 | ||||
-rw-r--r-- | dagger.go | 199 | ||||
-rw-r--r-- | dagger_test.go | 18 | ||||
-rw-r--r-- | dev_console.go | 186 | ||||
-rw-r--r-- | ethereum.go | 132 | ||||
-rw-r--r-- | peer.go | 118 | ||||
-rw-r--r-- | rlp.go | 388 | ||||
-rw-r--r-- | rlp_test.go | 74 | ||||
-rw-r--r-- | server.go | 161 | ||||
-rw-r--r-- | test_runner.go | 30 | ||||
-rw-r--r-- | test_runner_test.go | 28 | ||||
-rw-r--r-- | testing.go | 1 | ||||
-rw-r--r-- | vm.go | 451 |
14 files changed, 973 insertions, 938 deletions
@@ -21,3 +21,8 @@ Command line options -c launch the developer console -m start mining fake blocks and broadcast fake messages to the net + +Contribution +============ + +See CONTRIB.md diff --git a/block_manager.go b/block_manager.go index 59430dca7..968d9a139 100644 --- a/block_manager.go +++ b/block_manager.go @@ -1,90 +1,90 @@ package main import ( - "fmt" - "github.com/ethereum/ethutil-go" + "fmt" + "github.com/ethereum/ethutil-go" ) type BlockChain struct { - lastBlock *ethutil.Block + lastBlock *ethutil.Block - genesisBlock *ethutil.Block + genesisBlock *ethutil.Block } func NewBlockChain() *BlockChain { - bc := &BlockChain{} - bc.genesisBlock = ethutil.NewBlock( ethutil.Encode(ethutil.Genesis) ) + bc := &BlockChain{} + bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis)) - return bc + return bc } type BlockManager struct { - vm *Vm + vm *Vm - blockChain *BlockChain + blockChain *BlockChain } func NewBlockManager() *BlockManager { - bm := &BlockManager{vm: NewVm()} + bm := &BlockManager{vm: NewVm()} - return bm + return bm } // Process a block. func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error { - // TODO Validation (Or move to other part of the application) - if err := bm.ValidateBlock(block); err != nil { - return err - } - - // Get the tx count. Used to create enough channels to 'join' the go routines - txCount := len(block.Transactions()) - // Locking channel. When it has been fully buffered this method will return - lockChan := make(chan bool, txCount) - - // Process each transaction/contract - for _, tx := range block.Transactions() { - // If there's no recipient, it's a contract - if tx.IsContract() { - go bm.ProcessContract(tx, block, lockChan) - } else { - // "finish" tx which isn't a contract - lockChan <- true - } - } - - // Wait for all Tx to finish processing - for i := 0; i < txCount; i++ { - <- lockChan - } - - return nil + // TODO Validation (Or move to other part of the application) + if err := bm.ValidateBlock(block); err != nil { + return err + } + + // Get the tx count. Used to create enough channels to 'join' the go routines + txCount := len(block.Transactions()) + // Locking channel. When it has been fully buffered this method will return + lockChan := make(chan bool, txCount) + + // Process each transaction/contract + for _, tx := range block.Transactions() { + // If there's no recipient, it's a contract + if tx.IsContract() { + go bm.ProcessContract(tx, block, lockChan) + } else { + // "finish" tx which isn't a contract + lockChan <- true + } + } + + // Wait for all Tx to finish processing + for i := 0; i < txCount; i++ { + <-lockChan + } + + return nil } func (bm *BlockManager) ValidateBlock(block *ethutil.Block) error { - return nil + return nil } func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.Block, lockChan chan bool) { - // Recovering function in case the VM had any errors - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered from VM execution with err =", r) - // Let the channel know where done even though it failed (so the execution may resume normally) - lockChan <- true - } - }() - - // Process contract - bm.vm.ProcContract(tx, block, func(opType OpType) bool { - // TODO turn on once big ints are in place - //if !block.PayFee(tx.Hash(), StepFee.Uint64()) { - // return false - //} - - return true // Continue - }) - - // Broadcast we're done - lockChan <- true + // Recovering function in case the VM had any errors + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovered from VM execution with err =", r) + // Let the channel know where done even though it failed (so the execution may resume normally) + lockChan <- true + } + }() + + // Process contract + bm.vm.ProcContract(tx, block, func(opType OpType) bool { + // TODO turn on once big ints are in place + //if !block.PayFee(tx.Hash(), StepFee.Uint64()) { + // return false + //} + + return true // Continue + }) + + // Broadcast we're done + lockChan <- true } @@ -1,142 +1,145 @@ package main import ( - "math/big" - "math/rand" - "time" - "github.com/obscuren/sha3" - "hash" - "github.com/ethereum/ethutil-go" + "github.com/ethereum/ethutil-go" + "github.com/obscuren/sha3" + "hash" + "math/big" + "math/rand" + "time" ) type Dagger struct { - hash *big.Int - xn *big.Int + hash *big.Int + xn *big.Int } var Found bool + func (dag *Dagger) Find(obj *big.Int, resChan chan int64) { - r := rand.New(rand.NewSource(time.Now().UnixNano())) + r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < 1000; i++ { - rnd := r.Int63() + for i := 0; i < 1000; i++ { + rnd := r.Int63() - if dag.Eval(big.NewInt(rnd)).Cmp(obj) < 0 { - // Post back result on the channel - resChan <- rnd - // Notify other threads we've found a valid nonce - Found = true - } + if dag.Eval(big.NewInt(rnd)).Cmp(obj) < 0 { + // Post back result on the channel + resChan <- rnd + // Notify other threads we've found a valid nonce + Found = true + } - // Break out if found - if Found { break } - } + // Break out if found + if Found { + break + } + } - resChan <- 0 + resChan <- 0 } func (dag *Dagger) Search(hash, diff *big.Int) *big.Int { - // TODO fix multi threading. Somehow it results in the wrong nonce - amountOfRoutines := 1 + // TODO fix multi threading. Somehow it results in the wrong nonce + amountOfRoutines := 1 - dag.hash = hash + dag.hash = hash - obj := ethutil.BigPow(2, 256) - obj = obj.Div(obj, diff) + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) - Found = false - resChan := make(chan int64, 3) - var res int64 + Found = false + resChan := make(chan int64, 3) + var res int64 - for k := 0; k < amountOfRoutines; k++ { - go dag.Find(obj, resChan) - } + for k := 0; k < amountOfRoutines; k++ { + go dag.Find(obj, resChan) + } - // Wait for each go routine to finish - for k := 0; k < amountOfRoutines; k++ { - // Get the result from the channel. 0 = quit - if r := <- resChan; r != 0 { - res = r - } - } + // Wait for each go routine to finish + for k := 0; k < amountOfRoutines; k++ { + // Get the result from the channel. 0 = quit + if r := <-resChan; r != 0 { + res = r + } + } - return big.NewInt(res) + return big.NewInt(res) } func DaggerVerify(hash, diff, nonce *big.Int) bool { - dagger := &Dagger{} - dagger.hash = hash + dagger := &Dagger{} + dagger.hash = hash - obj := ethutil.BigPow(2, 256) - obj = obj.Div(obj, diff) + obj := ethutil.BigPow(2, 256) + obj = obj.Div(obj, diff) - return dagger.Eval(nonce).Cmp(obj) < 0 + return dagger.Eval(nonce).Cmp(obj) < 0 } func (dag *Dagger) Node(L uint64, i uint64) *big.Int { - if L == i { - return dag.hash - } - - var m *big.Int - if L == 9 { - m = big.NewInt(16) - } else { - m = big.NewInt(3) - } - - sha := sha3.NewKeccak256() - sha.Reset() - d := sha3.NewKeccak256() - b := new(big.Int) - ret := new(big.Int) - - for k := 0; k < int(m.Uint64()); k++ { - d.Reset() - d.Write(dag.hash.Bytes()) - d.Write(dag.xn.Bytes()) - d.Write(big.NewInt(int64(L)).Bytes()) - d.Write(big.NewInt(int64(i)).Bytes()) - d.Write(big.NewInt(int64(k)).Bytes()) - - b.SetBytes(Sum(d)) - pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) - sha.Write(dag.Node(L - 1, pk).Bytes()) - } - - ret.SetBytes(Sum(sha)) - - return ret + if L == i { + return dag.hash + } + + var m *big.Int + if L == 9 { + m = big.NewInt(16) + } else { + m = big.NewInt(3) + } + + sha := sha3.NewKeccak256() + sha.Reset() + d := sha3.NewKeccak256() + b := new(big.Int) + ret := new(big.Int) + + for k := 0; k < int(m.Uint64()); k++ { + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(big.NewInt(int64(L)).Bytes()) + d.Write(big.NewInt(int64(i)).Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) + + b.SetBytes(Sum(d)) + pk := b.Uint64() & ((1 << ((L - 1) * 3)) - 1) + sha.Write(dag.Node(L-1, pk).Bytes()) + } + + ret.SetBytes(Sum(sha)) + + return ret } func Sum(sha hash.Hash) []byte { - in := make([]byte, 32) - return sha.Sum(in) + in := make([]byte, 32) + return sha.Sum(in) } func (dag *Dagger) Eval(N *big.Int) *big.Int { - pow := ethutil.BigPow(2, 26) - dag.xn = N.Div(N, pow) + pow := ethutil.BigPow(2, 26) + dag.xn = N.Div(N, pow) - sha := sha3.NewKeccak256() - sha.Reset() - ret := new(big.Int) + sha := sha3.NewKeccak256() + sha.Reset() + ret := new(big.Int) - for k := 0; k < 4; k++ { - d := sha3.NewKeccak256() - b := new(big.Int) + for k := 0; k < 4; k++ { + d := sha3.NewKeccak256() + b := new(big.Int) - d.Reset() - d.Write(dag.hash.Bytes()) - d.Write(dag.xn.Bytes()) - d.Write(N.Bytes()) - d.Write(big.NewInt(int64(k)).Bytes()) + d.Reset() + d.Write(dag.hash.Bytes()) + d.Write(dag.xn.Bytes()) + d.Write(N.Bytes()) + d.Write(big.NewInt(int64(k)).Bytes()) - b.SetBytes(Sum(d)) - pk := (b.Uint64() & 0x1ffffff) + b.SetBytes(Sum(d)) + pk := (b.Uint64() & 0x1ffffff) - sha.Write(dag.Node(9, pk).Bytes()) - } + sha.Write(dag.Node(9, pk).Bytes()) + } - return ret.SetBytes(Sum(sha)) + return ret.SetBytes(Sum(sha)) } diff --git a/dagger_test.go b/dagger_test.go index 7953ec1da..58cdd6afd 100644 --- a/dagger_test.go +++ b/dagger_test.go @@ -1,17 +1,17 @@ package main import ( - "testing" - "math/big" + "math/big" + "testing" ) func BenchmarkDaggerSearch(b *testing.B) { - hash := big.NewInt(0) - diff := BigPow(2, 36) - o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity + hash := big.NewInt(0) + diff := BigPow(2, 36) + o := big.NewInt(0) // nonce doesn't matter. We're only testing against speed, not validity - // Reset timer so the big generation isn't included in the benchmark - b.ResetTimer() - // Validate - DaggerVerify(hash, diff, o) + // Reset timer so the big generation isn't included in the benchmark + b.ResetTimer() + // Validate + DaggerVerify(hash, diff, o) } diff --git a/dev_console.go b/dev_console.go index 27fc2e65e..923c483c2 100644 --- a/dev_console.go +++ b/dev_console.go @@ -1,119 +1,121 @@ package main import ( - "fmt" - "bufio" - "strings" - "os" - "errors" - "encoding/hex" - "github.com/ethereum/ethdb-go" - "github.com/ethereum/ethutil-go" + "bufio" + "encoding/hex" + "errors" + "fmt" + "github.com/ethereum/ethdb-go" + "github.com/ethereum/ethutil-go" + "os" + "strings" ) type Console struct { - db *ethdb.MemDatabase - trie *ethutil.Trie + db *ethdb.MemDatabase + trie *ethutil.Trie } func NewConsole() *Console { - db, _ := ethdb.NewMemDatabase() - trie := ethutil.NewTrie(db, "") + db, _ := ethdb.NewMemDatabase() + trie := ethutil.NewTrie(db, "") - return &Console{db: db, trie: trie} + return &Console{db: db, trie: trie} } func (i *Console) ValidateInput(action string, argumentLength int) error { - err := false - var expArgCount int + err := false + var expArgCount int - switch { - case action == "update" && argumentLength != 2: - err = true - expArgCount = 2 - case action == "get" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "dag" && argumentLength != 2: - err = true - expArgCount = 2 - } + switch { + case action == "update" && argumentLength != 2: + err = true + expArgCount = 2 + case action == "get" && argumentLength != 1: + err = true + expArgCount = 1 + case action == "dag" && argumentLength != 2: + err = true + expArgCount = 2 + } - if err { - return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength)) - } else { - return nil - } + if err { + return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength)) + } else { + return nil + } } func (i *Console) ParseInput(input string) bool { - scanner := bufio.NewScanner(strings.NewReader(input)) - scanner.Split(bufio.ScanWords) + scanner := bufio.NewScanner(strings.NewReader(input)) + scanner.Split(bufio.ScanWords) - count := 0 - var tokens []string - for scanner.Scan() { - count++ - tokens = append(tokens, scanner.Text()) - } - if err := scanner.Err(); err != nil { - fmt.Fprintln(os.Stderr, "reading input:", err) - } + count := 0 + var tokens []string + for scanner.Scan() { + count++ + tokens = append(tokens, scanner.Text()) + } + if err := scanner.Err(); err != nil { + fmt.Fprintln(os.Stderr, "reading input:", err) + } - if len(tokens) == 0 { return true } + if len(tokens) == 0 { + return true + } - err := i.ValidateInput(tokens[0], count-1) - if err != nil { - fmt.Println(err) - } else { - switch tokens[0] { - case "update": - i.trie.Update(tokens[1], tokens[2]) + err := i.ValidateInput(tokens[0], count-1) + if err != nil { + fmt.Println(err) + } else { + switch tokens[0] { + case "update": + i.trie.Update(tokens[1], tokens[2]) - fmt.Println(hex.EncodeToString([]byte(i.trie.Root))) - case "get": - fmt.Println(i.trie.Get(tokens[1])) - case "root": - fmt.Println(hex.EncodeToString([]byte(i.trie.Root))) - case "rawroot": - fmt.Println(i.trie.Root) - case "print": - i.db.Print() - case "dag": - fmt.Println(DaggerVerify( ethutil.Big(tokens[1]), // hash - ethutil.BigPow(2, 36), // diff - ethutil.Big(tokens[2])))// nonce - case "exit", "quit", "q": - return false - case "help": - fmt.Printf( "COMMANDS:\n"+ - "\033[1m= DB =\033[0m\n"+ - "update KEY VALUE - Updates/Creates a new value for the given key\n"+ - "get KEY - Retrieves the given key\n"+ - "root - Prints the hex encoded merkle root\n"+ - "rawroot - Prints the raw merkle root\n"+ - "\033[1m= Dagger =\033[0m\n"+ - "dag HASH NONCE - Verifies a nonce with the given hash with dagger\n") - default: - fmt.Println("Unknown command:", tokens[0]) - } - } + fmt.Println(hex.EncodeToString([]byte(i.trie.Root))) + case "get": + fmt.Println(i.trie.Get(tokens[1])) + case "root": + fmt.Println(hex.EncodeToString([]byte(i.trie.Root))) + case "rawroot": + fmt.Println(i.trie.Root) + case "print": + i.db.Print() + case "dag": + fmt.Println(DaggerVerify(ethutil.Big(tokens[1]), // hash + ethutil.BigPow(2, 36), // diff + ethutil.Big(tokens[2]))) // nonce + case "exit", "quit", "q": + return false + case "help": + fmt.Printf("COMMANDS:\n" + + "\033[1m= DB =\033[0m\n" + + "update KEY VALUE - Updates/Creates a new value for the given key\n" + + "get KEY - Retrieves the given key\n" + + "root - Prints the hex encoded merkle root\n" + + "rawroot - Prints the raw merkle root\n" + + "\033[1m= Dagger =\033[0m\n" + + "dag HASH NONCE - Verifies a nonce with the given hash with dagger\n") + default: + fmt.Println("Unknown command:", tokens[0]) + } + } - return true + return true } func (i *Console) Start() { - fmt.Printf("Eth Console. Type (help) for help\n") - reader := bufio.NewReader(os.Stdin) - for { - fmt.Printf("eth >>> ") - str, _, err := reader.ReadLine() - if err != nil { - fmt.Println("Error reading input", err) - } else { - if !i.ParseInput(string(str)) { - return - } - } - } + fmt.Printf("Eth Console. Type (help) for help\n") + reader := bufio.NewReader(os.Stdin) + for { + fmt.Printf("eth >>> ") + str, _, err := reader.ReadLine() + if err != nil { + fmt.Println("Error reading input", err) + } else { + if !i.ParseInput(string(str)) { + return + } + } + } } diff --git a/ethereum.go b/ethereum.go index 96b67f970..dd5b44308 100644 --- a/ethereum.go +++ b/ethereum.go @@ -1,85 +1,85 @@ package main import ( - "fmt" - "os" - "os/signal" - "flag" - "runtime" - "log" - "github.com/ethereum/ethutil-go" + "flag" + "fmt" + "github.com/ethereum/ethutil-go" + "log" + "os" + "os/signal" + "runtime" ) const Debug = true var StartConsole bool var StartMining bool + func Init() { - flag.BoolVar(&StartConsole, "c", false, "debug and testing console") - flag.BoolVar(&StartMining, "m", false, "start dagger mining") + flag.BoolVar(&StartConsole, "c", false, "debug and testing console") + flag.BoolVar(&StartMining, "m", false, "start dagger mining") - flag.Parse() + flag.Parse() } // Register interrupt handlers so we can stop the server func RegisterInterupts(s *Server) { - // Buffered chan of one is enough - c := make(chan os.Signal, 1) - // Notify about interrupts for now - signal.Notify(c, os.Interrupt) - go func() { - for sig := range c { - fmt.Printf("Shutting down (%v) ... \n", sig) - - s.Stop() - } - }() + // Buffered chan of one is enough + c := make(chan os.Signal, 1) + // Notify about interrupts for now + signal.Notify(c, os.Interrupt) + go func() { + for sig := range c { + fmt.Printf("Shutting down (%v) ... \n", sig) + + s.Stop() + } + }() } func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - - ethutil.InitFees() - - Init() - - if StartConsole { - console := NewConsole() - console.Start() - } else{ - log.Println("Starting Ethereum") - server, err := NewServer() - - if err != nil { - log.Println(err) - return - } - - RegisterInterupts(server) - - if StartMining { - log.Println("Mining started") - dagger := &Dagger{} - - go func() { - for { - res := dagger.Search(ethutil.Big("0"), ethutil.BigPow(2, 36)) - server.Broadcast("block", Encode(res.String())) - } - }() - } - - server.Start() - - err = server.ConnectToPeer("localhost:12345") - if err != nil { - log.Println(err) - server.Stop() - return - } - - - // Wait for shutdown - server.WaitForShutdown() - } + runtime.GOMAXPROCS(runtime.NumCPU()) + + ethutil.InitFees() + + Init() + + if StartConsole { + console := NewConsole() + console.Start() + } else { + log.Println("Starting Ethereum") + server, err := NewServer() + + if err != nil { + log.Println(err) + return + } + + RegisterInterupts(server) + + if StartMining { + log.Println("Mining started") + dagger := &Dagger{} + + go func() { + for { + res := dagger.Search(ethutil.Big("0"), ethutil.BigPow(2, 36)) + server.Broadcast("block", Encode(res.String())) + } + }() + } + + server.Start() + + err = server.ConnectToPeer("localhost:12345") + if err != nil { + log.Println(err) + server.Stop() + return + } + + // Wait for shutdown + server.WaitForShutdown() + } } @@ -1,92 +1,92 @@ package main import ( - "net" - "log" - "github.com/ethereum/ethwire-go" + "github.com/ethereum/ethwire-go" + "log" + "net" ) type Peer struct { - // Server interface - server *Server - // Net connection - conn net.Conn - // Output queue which is used to communicate and handle messages - outputQueue chan ethwire.InOutMsg - // Quit channel - quit chan bool + // Server interface + server *Server + // Net connection + conn net.Conn + // Output queue which is used to communicate and handle messages + outputQueue chan ethwire.InOutMsg + // Quit channel + quit chan bool } func NewPeer(conn net.Conn, server *Server) *Peer { - return &Peer{ - outputQueue: make(chan ethwire.InOutMsg, 1), // Buffered chan of 1 is enough - quit: make(chan bool), + return &Peer{ + outputQueue: make(chan ethwire.InOutMsg, 1), // Buffered chan of 1 is enough + quit: make(chan bool), - server: server, - conn: conn, - } + server: server, + conn: conn, + } } // Outputs any RLP encoded data to the peer func (p *Peer) QueueMessage(msgType string, data []byte) { - p.outputQueue <- ethwire.InOutMsg{MsgType: msgType, Data: data} + p.outputQueue <- ethwire.InOutMsg{MsgType: msgType, Data: data} } // Outbound message handler. Outbound messages are handled here func (p *Peer) HandleOutbound() { out: - for { - select { - // Main message queue. All outbound messages are processed through here - case msg := <-p.outputQueue: - // TODO Message checking and handle accordingly - err := ethwire.WriteMessage(p.conn, msg) - if err != nil { - log.Println(err) - - // Stop the client if there was an error writing to it - p.Stop() - } - - // Break out of the for loop if a quit message is posted - case <- p.quit: - break out - } - } + for { + select { + // Main message queue. All outbound messages are processed through here + case msg := <-p.outputQueue: + // TODO Message checking and handle accordingly + err := ethwire.WriteMessage(p.conn, msg) + if err != nil { + log.Println(err) + + // Stop the client if there was an error writing to it + p.Stop() + } + + // Break out of the for loop if a quit message is posted + case <-p.quit: + break out + } + } } // Inbound handler. Inbound messages are received here and passed to the appropriate methods func (p *Peer) HandleInbound() { - defer p.Stop() + defer p.Stop() out: - for { - // Wait for a message from the peer - msg, err := ethwire.ReadMessage(p.conn) - if err != nil { - log.Println(err) - - break out - } - - // TODO - data, _ := Decode(msg.Data, 0) - log.Printf("%s, %s\n", msg.MsgType, data) - } - - // Notify the out handler we're quiting - p.quit <- true + for { + // Wait for a message from the peer + msg, err := ethwire.ReadMessage(p.conn) + if err != nil { + log.Println(err) + + break out + } + + // TODO + data, _ := Decode(msg.Data, 0) + log.Printf("%s, %s\n", msg.MsgType, data) + } + + // Notify the out handler we're quiting + p.quit <- true } func (p *Peer) Start() { - // Run the outbound handler in a new goroutine - go p.HandleOutbound() - // Run the inbound handler in a new goroutine - go p.HandleInbound() + // Run the outbound handler in a new goroutine + go p.HandleOutbound() + // Run the inbound handler in a new goroutine + go p.HandleInbound() } func (p *Peer) Stop() { - p.conn.Close() + p.conn.Close() - p.quit <- true + p.quit <- true } @@ -1,270 +1,278 @@ package main import ( - "fmt" - "bytes" - "math" - "math/big" - "github.com/ethereum/ethutil-go" + "bytes" + "fmt" + "github.com/ethereum/ethutil-go" + "math" + "math/big" ) type RlpEncoder struct { - rlpData []byte + rlpData []byte } + func NewRlpEncoder() *RlpEncoder { - encoder := &RlpEncoder{} + encoder := &RlpEncoder{} - return encoder + return encoder } func (coder *RlpEncoder) EncodeData(rlpData []interface{}) []byte { - return nil + return nil } // Data attributes are returned by the rlp decoder. The data attributes represents // one item within the rlp data structure. It's responsible for all the casting // It always returns something valid type RlpDataAttribute struct { - dataAttrib interface{} + dataAttrib interface{} } func NewRlpDataAttribute(attrib interface{}) *RlpDataAttribute { - return &RlpDataAttribute{dataAttrib: attrib} + return &RlpDataAttribute{dataAttrib: attrib} } func (attr *RlpDataAttribute) Length() int { - if data, ok := attr.dataAttrib.([]interface{}); ok { - return len(data) - } + if data, ok := attr.dataAttrib.([]interface{}); ok { + return len(data) + } - return 0 + return 0 } func (attr *RlpDataAttribute) AsUint() uint64 { - if value, ok := attr.dataAttrib.(uint8); ok { - return uint64(value) - } else if value, ok := attr.dataAttrib.(uint16); ok { - return uint64(value) - } else if value, ok := attr.dataAttrib.(uint32); ok { - return uint64(value) - } else if value, ok := attr.dataAttrib.(uint64); ok { - return value - } - - return 0 + if value, ok := attr.dataAttrib.(uint8); ok { + return uint64(value) + } else if value, ok := attr.dataAttrib.(uint16); ok { + return uint64(value) + } else if value, ok := attr.dataAttrib.(uint32); ok { + return uint64(value) + } else if value, ok := attr.dataAttrib.(uint64); ok { + return value + } + + return 0 } func (attr *RlpDataAttribute) AsBigInt() *big.Int { - if a, ok := attr.dataAttrib.([]byte); ok { - return ethutil.Big(string(a)) - } + if a, ok := attr.dataAttrib.([]byte); ok { + return ethutil.Big(string(a)) + } - return big.NewInt(0) + return big.NewInt(0) } func (attr *RlpDataAttribute) AsString() string { - if a, ok := attr.dataAttrib.([]byte); ok { - return string(a) - } + if a, ok := attr.dataAttrib.([]byte); ok { + return string(a) + } - return "" + return "" } func (attr *RlpDataAttribute) AsBytes() []byte { - if a, ok := attr.dataAttrib.([]byte); ok { - return a - } + if a, ok := attr.dataAttrib.([]byte); ok { + return a + } - return make([]byte, 0) + return make([]byte, 0) } // Threat the attribute as a slice func (attr *RlpDataAttribute) Get(idx int) *RlpDataAttribute { - if d, ok := attr.dataAttrib.([]interface{}); ok { - // Guard for oob - if len(d) < idx { - return NewRlpDataAttribute(nil) - } + if d, ok := attr.dataAttrib.([]interface{}); ok { + // Guard for oob + if len(d) < idx { + return NewRlpDataAttribute(nil) + } - return NewRlpDataAttribute(d[idx]) - } + return NewRlpDataAttribute(d[idx]) + } - // If this wasn't a slice you probably shouldn't be using this function - return NewRlpDataAttribute(nil) + // If this wasn't a slice you probably shouldn't be using this function + return NewRlpDataAttribute(nil) } type RlpDecoder struct { - rlpData interface{} + rlpData interface{} } + func NewRlpDecoder(rlpData []byte) *RlpDecoder { - decoder := &RlpDecoder{} - // Decode the data - data, _ := Decode(rlpData,0) - decoder.rlpData = data + decoder := &RlpDecoder{} + // Decode the data + data, _ := Decode(rlpData, 0) + decoder.rlpData = data - return decoder + return decoder } func (dec *RlpDecoder) Get(idx int) *RlpDataAttribute { - return NewRlpDataAttribute(dec.rlpData).Get(idx) + return NewRlpDataAttribute(dec.rlpData).Get(idx) } /// Raw methods func BinaryLength(n uint64) uint64 { - if n == 0 { return 0 } + if n == 0 { + return 0 + } - return 1 + BinaryLength(n / 256) + return 1 + BinaryLength(n/256) } func ToBinarySlice(n uint64, length uint64) []uint64 { - if length == 0 { - length = BinaryLength(n) - } + if length == 0 { + length = BinaryLength(n) + } - if n == 0 { return make([]uint64, 1) } + if n == 0 { + return make([]uint64, 1) + } - slice := ToBinarySlice(n / 256, 0) - slice = append(slice, n % 256) + slice := ToBinarySlice(n/256, 0) + slice = append(slice, n%256) - return slice + return slice } func ToBin(n uint64, length uint64) string { - var buf bytes.Buffer - for _, val := range ToBinarySlice(n, length) { - buf.WriteString(string(val)) - } + var buf bytes.Buffer + for _, val := range ToBinarySlice(n, length) { + buf.WriteString(string(val)) + } - return buf.String() + return buf.String() } func FromBin(data []byte) uint64 { - if len(data) == 0 { return 0 } + if len(data) == 0 { + return 0 + } - return FromBin(data[:len(data)-1]) * 256 + uint64(data[len(data)-1]) + return FromBin(data[:len(data)-1])*256 + uint64(data[len(data)-1]) } func Decode(data []byte, pos int) (interface{}, int) { - if pos > len(data)-1 { - panic(fmt.Sprintf("index out of range %d for data %q, l = %d", pos, data, len(data))) - } - - char := int(data[pos]) - slice := make([]interface{}, 0) - switch { - case char < 24: - return data[pos], pos + 1 - - case char < 56: - b := int(data[pos]) - 23 - return FromBin(data[pos+1 : pos+1+b]), pos + 1 + b - - case char < 64: - b := int(data[pos]) - 55 - b2 := int(FromBin(data[pos+1 : pos+1+b])) - return FromBin(data[pos+1+b : pos+1+b+b2]), pos+1+b+b2 - - case char < 120: - b := int(data[pos]) - 64 - return data[pos+1:pos+1+b], pos+1+b - - case char < 128: - b := int(data[pos]) - 119 - b2 := int(FromBin(data[pos+1 : pos+1+b])) - return data[pos+1+b : pos+1+b+b2], pos+1+b+b2 - - case char < 184: - b := int(data[pos]) - 128 - pos++ - for i := 0; i < b; i++ { - var obj interface{} - - obj, pos = Decode(data, pos) - slice = append(slice, obj) - } - return slice, pos - - case char < 192: - b := int(data[pos]) - 183 - //b2 := int(FromBin(data[pos+1 : pos+1+b])) (ref implementation has an unused variable) - pos = pos+1+b - for i := 0; i < b; i++ { - var obj interface{} - - obj, pos = Decode(data, pos) - slice = append(slice, obj) - } - return slice, pos - - default: - panic(fmt.Sprintf("byte not supported: %q", char)) - } - - return slice, 0 + if pos > len(data)-1 { + panic(fmt.Sprintf("index out of range %d for data %q, l = %d", pos, data, len(data))) + } + + char := int(data[pos]) + slice := make([]interface{}, 0) + switch { + case char < 24: + return data[pos], pos + 1 + + case char < 56: + b := int(data[pos]) - 23 + return FromBin(data[pos+1 : pos+1+b]), pos + 1 + b + + case char < 64: + b := int(data[pos]) - 55 + b2 := int(FromBin(data[pos+1 : pos+1+b])) + return FromBin(data[pos+1+b : pos+1+b+b2]), pos + 1 + b + b2 + + case char < 120: + b := int(data[pos]) - 64 + return data[pos+1 : pos+1+b], pos + 1 + b + + case char < 128: + b := int(data[pos]) - 119 + b2 := int(FromBin(data[pos+1 : pos+1+b])) + return data[pos+1+b : pos+1+b+b2], pos + 1 + b + b2 + + case char < 184: + b := int(data[pos]) - 128 + pos++ + for i := 0; i < b; i++ { + var obj interface{} + + obj, pos = Decode(data, pos) + slice = append(slice, obj) + } + return slice, pos + + case char < 192: + b := int(data[pos]) - 183 + //b2 := int(FromBin(data[pos+1 : pos+1+b])) (ref implementation has an unused variable) + pos = pos + 1 + b + for i := 0; i < b; i++ { + var obj interface{} + + obj, pos = Decode(data, pos) + slice = append(slice, obj) + } + return slice, pos + + default: + panic(fmt.Sprintf("byte not supported: %q", char)) + } + + return slice, 0 } func Encode(object interface{}) []byte { - var buff bytes.Buffer - - switch t := object.(type) { - case uint32, uint64: - var num uint64 - if _num, ok := t.(uint64); ok { - num = _num - } else if _num, ok := t.(uint32); ok { - num = uint64(_num) - } - - if num >= 0 && num < 24 { - buff.WriteString(string(num)) - } else if num <= uint64(math.Pow(2, 256)) { - b := ToBin(num, 0) - buff.WriteString(string(len(b) + 23) + b) - } else { - b := ToBin(num, 0) - b2 := ToBin(uint64(len(b)), 0) - buff.WriteString(string(len(b2) + 55) + b2 + b) - } - - case *big.Int: - buff.Write(Encode(t.String())) - - case string: - if len(t) < 56 { - buff.WriteString(string(len(t) + 64) + t) - } else { - b2 := ToBin(uint64(len(t)), 0) - buff.WriteString(string(len(b2) + 119) + b2 + t) - } - - case []byte: - // Cast the byte slice to a string - buff.Write(Encode(string(t))) - - case []interface{}, []string: - // Inline function for writing the slice header - WriteSliceHeader := func(length int) { - if length < 56 { - buff.WriteByte(byte(length + 128)) - } else { - b2 := ToBin(uint64(length), 0) - buff.WriteByte(byte(len(b2) + 183)) - buff.WriteString(b2) - } - } - - // FIXME How can I do this "better"? - if interSlice, ok := t.([]interface{}); ok { - WriteSliceHeader(len(interSlice)) - for _, val := range interSlice { - buff.Write(Encode(val)) - } - } else if stringSlice, ok := t.([]string); ok { - WriteSliceHeader(len(stringSlice)) - for _, val := range stringSlice { - buff.Write(Encode(val)) - } - } - } - - return buff.Bytes() + var buff bytes.Buffer + + switch t := object.(type) { + case uint32, uint64: + var num uint64 + if _num, ok := t.(uint64); ok { + num = _num + } else if _num, ok := t.(uint32); ok { + num = uint64(_num) + } + + if num >= 0 && num < 24 { + buff.WriteString(string(num)) + } else if num <= uint64(math.Pow(2, 256)) { + b := ToBin(num, 0) + buff.WriteString(string(len(b)+23) + b) + } else { + b := ToBin(num, 0) + b2 := ToBin(uint64(len(b)), 0) + buff.WriteString(string(len(b2)+55) + b2 + b) + } + + case *big.Int: + buff.Write(Encode(t.String())) + + case string: + if len(t) < 56 { + buff.WriteString(string(len(t)+64) + t) + } else { + b2 := ToBin(uint64(len(t)), 0) + buff.WriteString(string(len(b2)+119) + b2 + t) + } + + case []byte: + // Cast the byte slice to a string + buff.Write(Encode(string(t))) + + case []interface{}, []string: + // Inline function for writing the slice header + WriteSliceHeader := func(length int) { + if length < 56 { + buff.WriteByte(byte(length + 128)) + } else { + b2 := ToBin(uint64(length), 0) + buff.WriteByte(byte(len(b2) + 183)) + buff.WriteString(b2) + } + } + + // FIXME How can I do this "better"? + if interSlice, ok := t.([]interface{}); ok { + WriteSliceHeader(len(interSlice)) + for _, val := range interSlice { + buff.Write(Encode(val)) + } + } else if stringSlice, ok := t.([]string); ok { + WriteSliceHeader(len(stringSlice)) + for _, val := range stringSlice { + buff.Write(Encode(val)) + } + } + } + + return buff.Bytes() } diff --git a/rlp_test.go b/rlp_test.go index 68676d030..65cf34b39 100644 --- a/rlp_test.go +++ b/rlp_test.go @@ -1,54 +1,54 @@ package main import ( - "testing" - "fmt" + "fmt" + "testing" ) func TestEncode(t *testing.T) { - strRes := "Cdog" + strRes := "Cdog" - bytes := Encode("dog") + bytes := Encode("dog") - str := string(bytes) - if str != strRes { - t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) - } - //dec,_ := Decode(bytes, 0) + str := string(bytes) + if str != strRes { + t.Error(fmt.Sprintf("Expected %q, got %q", strRes, str)) + } + //dec,_ := Decode(bytes, 0) - sliceRes := "\x83CdogCgodCcat" - strs := []string{"dog", "god", "cat"} - bytes = Encode(strs) - slice := string(bytes) - if slice != sliceRes { - t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) - } + sliceRes := "\x83CdogCgodCcat" + strs := []string{"dog", "god", "cat"} + bytes = Encode(strs) + slice := string(bytes) + if slice != sliceRes { + t.Error(fmt.Sprintf("Expected %q, got %q", sliceRes, slice)) + } - //dec,_ = Decode(bytes, 0) + //dec,_ = Decode(bytes, 0) } func TestMultiEncode(t *testing.T) { - inter := []interface{}{ - []interface{}{ - "1","2","3", - }, - []string{ - "string", - "string2", - "\x86A0J1234567890A\x00B20A0\x82F395843F657986", - "\x86A0J1234567890A\x00B20A0\x8cF395843F657986I335612448F524099H16716881A0H13114947G2039362G1507139H16719697G1048387E65360", - }, - "test", - } - - bytes := Encode(inter) - - Decode(bytes, 0) + inter := []interface{}{ + []interface{}{ + "1", "2", "3", + }, + []string{ + "string", + "string2", + "\x86A0J1234567890A\x00B20A0\x82F395843F657986", + "\x86A0J1234567890A\x00B20A0\x8cF395843F657986I335612448F524099H16716881A0H13114947G2039362G1507139H16719697G1048387E65360", + }, + "test", + } + + bytes := Encode(inter) + + Decode(bytes, 0) } func BenchmarkEncodeDecode(b *testing.B) { - for i := 0; i < b.N; i++ { - bytes := Encode([]string{"dog", "god", "cat"}) - Decode(bytes, 0) - } + for i := 0; i < b.N; i++ { + bytes := Encode([]string{"dog", "god", "cat"}) + Decode(bytes, 0) + } } @@ -1,121 +1,120 @@ package main import ( - "container/list" - "net" - "log" - _"time" - "github.com/ethereum/ethdb-go" - "github.com/ethereum/ethutil-go" + "container/list" + "github.com/ethereum/ethdb-go" + "github.com/ethereum/ethutil-go" + "log" + "net" + _ "time" ) type Server struct { - // Channel for shutting down the server - shutdownChan chan bool - // DB interface - db *ethdb.LDBDatabase - // Block manager for processing new blocks and managing the block chain - blockManager *BlockManager - // Peers (NYI) - peers *list.List + // Channel for shutting down the server + shutdownChan chan bool + // DB interface + db *ethdb.LDBDatabase + // Block manager for processing new blocks and managing the block chain + blockManager *BlockManager + // Peers (NYI) + peers *list.List } func NewServer() (*Server, error) { - db, err := ethdb.NewLDBDatabase() - if err != nil { - return nil, err - } + db, err := ethdb.NewLDBDatabase() + if err != nil { + return nil, err + } - ethutil.SetConfig(db) + ethutil.SetConfig(db) - server := &Server{ - shutdownChan: make(chan bool), - blockManager: NewBlockManager(), - db: db, - peers: list.New(), - } + server := &Server{ + shutdownChan: make(chan bool), + blockManager: NewBlockManager(), + db: db, + peers: list.New(), + } - return server, nil + return server, nil } func (s *Server) AddPeer(conn net.Conn) { - peer := NewPeer(conn, s) - s.peers.PushBack(peer) - peer.Start() + peer := NewPeer(conn, s) + s.peers.PushBack(peer) + peer.Start() - log.Println("Peer connected ::", conn.RemoteAddr()) + log.Println("Peer connected ::", conn.RemoteAddr()) } func (s *Server) ConnectToPeer(addr string) error { - conn, err := net.Dial("tcp", addr) + conn, err := net.Dial("tcp", addr) - if err != nil { - return err - } + if err != nil { + return err + } - peer := NewPeer(conn, s) - s.peers.PushBack(peer) - peer.Start() + peer := NewPeer(conn, s) + s.peers.PushBack(peer) + peer.Start() + log.Println("Connected to peer ::", conn.RemoteAddr()) - log.Println("Connected to peer ::", conn.RemoteAddr()) - - return nil + return nil } func (s *Server) Broadcast(msgType string, data []byte) { - for e := s.peers.Front(); e != nil; e = e.Next() { - if peer, ok := e.Value.(*Peer); ok { - peer.QueueMessage(msgType, data) - } - } + for e := s.peers.Front(); e != nil; e = e.Next() { + if peer, ok := e.Value.(*Peer); ok { + peer.QueueMessage(msgType, data) + } + } } // Start the server func (s *Server) Start() { - // For now this function just blocks the main thread - ln, err := net.Listen("tcp", ":12345") - if err != nil { - log.Fatal(err) - } - - go func() { - for { - conn, err := ln.Accept() - if err != nil { - log.Println(err) - continue - } - - go s.AddPeer(conn) - } - }() - - // TMP - //go func() { - // for { - // s.Broadcast("block", Encode("blockdata")) -// -// time.Sleep(100 * time.Millisecond) -// } -// }() + // For now this function just blocks the main thread + ln, err := net.Listen("tcp", ":12345") + if err != nil { + log.Fatal(err) + } + + go func() { + for { + conn, err := ln.Accept() + if err != nil { + log.Println(err) + continue + } + + go s.AddPeer(conn) + } + }() + + // TMP + //go func() { + // for { + // s.Broadcast("block", Encode("blockdata")) + // + // time.Sleep(100 * time.Millisecond) + // } + // }() } func (s *Server) Stop() { - // Close the database - defer s.db.Close() + // Close the database + defer s.db.Close() - // Loop thru the peers and close them (if we had them) - for e := s.peers.Front(); e != nil; e = e.Next() { - if peer, ok := e.Value.(*Peer); ok { - peer.Stop() - } - } + // Loop thru the peers and close them (if we had them) + for e := s.peers.Front(); e != nil; e = e.Next() { + if peer, ok := e.Value.(*Peer); ok { + peer.Stop() + } + } - s.shutdownChan <- true + s.shutdownChan <- true } // This function will wait for a shutdown and resumes main thread execution func (s *Server) WaitForShutdown() { - <- s.shutdownChan + <-s.shutdownChan } diff --git a/test_runner.go b/test_runner.go index da93533dd..e8a1698ce 100644 --- a/test_runner.go +++ b/test_runner.go @@ -1,35 +1,35 @@ package main import ( - "fmt" - "testing" - "encoding/json" + "encoding/json" + "fmt" + "testing" ) type TestSource struct { - Inputs map[string]string - Expectation string + Inputs map[string]string + Expectation string } func NewTestSource(source string) *TestSource { - s := &TestSource{} - err := json.Unmarshal([]byte(source), s) - if err != nil { - fmt.Println(err) - } + s := &TestSource{} + err := json.Unmarshal([]byte(source), s) + if err != nil { + fmt.Println(err) + } - return s + return s } type TestRunner struct { - source *TestSource + source *TestSource } func NewTestRunner(t *testing.T) *TestRunner { - return &TestRunner{} + return &TestRunner{} } func (runner *TestRunner) RunFromString(input string, Cb func(*TestSource)) { - source := NewTestSource(input) - Cb(source) + source := NewTestSource(input) + Cb(source) } diff --git a/test_runner_test.go b/test_runner_test.go index 190bf3caf..5abe20002 100644 --- a/test_runner_test.go +++ b/test_runner_test.go @@ -1,9 +1,9 @@ package main import ( - _"fmt" - "testing" - "encoding/hex" + "encoding/hex" + _ "fmt" + "testing" ) var testsource = `{"Inputs":{ @@ -15,17 +15,17 @@ var testsource = `{"Inputs":{ }` func TestTestRunner(t *testing.T) { - db, _ := NewMemDatabase() - trie := NewTrie(db, "") + db, _ := NewMemDatabase() + trie := NewTrie(db, "") - runner := NewTestRunner(t) - runner.RunFromString(testsource, func(source *TestSource) { - for key, value := range source.Inputs { - trie.Update(key, value) - } + runner := NewTestRunner(t) + runner.RunFromString(testsource, func(source *TestSource) { + for key, value := range source.Inputs { + trie.Update(key, value) + } - if hex.EncodeToString([]byte(trie.root)) != source.Expectation { - t.Error("trie root did not match") - } - }) + if hex.EncodeToString([]byte(trie.root)) != source.Expectation { + t.Error("trie root did not match") + } + }) } diff --git a/testing.go b/testing.go index 9b7b7b3ce..5e2aec02b 100644 --- a/testing.go +++ b/testing.go @@ -1,4 +1,5 @@ package main + /* import ( @@ -1,267 +1,284 @@ package main import ( - "math/big" - "fmt" - "strconv" - "github.com/ethereum/ethutil-go" + "fmt" + "github.com/ethereum/ethutil-go" + "math/big" + "strconv" ) // Op codes const ( - oSTOP int = 0x00 - oADD int = 0x01 - oMUL int = 0x02 - oSUB int = 0x03 - oDIV int = 0x04 - oSDIV int = 0x05 - oMOD int = 0x06 - oSMOD int = 0x07 - oEXP int = 0x08 - oNEG int = 0x09 - oLT int = 0x0a - oLE int = 0x0b - oGT int = 0x0c - oGE int = 0x0d - oEQ int = 0x0e - oNOT int = 0x0f - oMYADDRESS int = 0x10 - oTXSENDER int = 0x11 - oTXVALUE int = 0x12 - oTXFEE int = 0x13 - oTXDATAN int = 0x14 - oTXDATA int = 0x15 - oBLK_PREVHASH int = 0x16 - oBLK_COINBASE int = 0x17 - oBLK_TIMESTAMP int = 0x18 - oBLK_NUMBER int = 0x19 - oBLK_DIFFICULTY int = 0x1a - oSHA256 int = 0x20 - oRIPEMD160 int = 0x21 - oECMUL int = 0x22 - oECADD int = 0x23 - oECSIGN int = 0x24 - oECRECOVER int = 0x25 - oECVALID int = 0x26 - oPUSH int = 0x30 - oPOP int = 0x31 - oDUP int = 0x32 - oDUPN int = 0x33 - oSWAP int = 0x34 - oSWAPN int = 0x35 - oLOAD int = 0x36 - oSTORE int = 0x37 - oJMP int = 0x40 - oJMPI int = 0x41 - oIND int = 0x42 - oEXTRO int = 0x50 - oBALANCE int = 0x51 - oMKTX int = 0x60 - oSUICIDE int = 0xff + oSTOP int = 0x00 + oADD int = 0x01 + oMUL int = 0x02 + oSUB int = 0x03 + oDIV int = 0x04 + oSDIV int = 0x05 + oMOD int = 0x06 + oSMOD int = 0x07 + oEXP int = 0x08 + oNEG int = 0x09 + oLT int = 0x0a + oLE int = 0x0b + oGT int = 0x0c + oGE int = 0x0d + oEQ int = 0x0e + oNOT int = 0x0f + oMYADDRESS int = 0x10 + oTXSENDER int = 0x11 + oTXVALUE int = 0x12 + oTXFEE int = 0x13 + oTXDATAN int = 0x14 + oTXDATA int = 0x15 + oBLK_PREVHASH int = 0x16 + oBLK_COINBASE int = 0x17 + oBLK_TIMESTAMP int = 0x18 + oBLK_NUMBER int = 0x19 + oBLK_DIFFICULTY int = 0x1a + oSHA256 int = 0x20 + oRIPEMD160 int = 0x21 + oECMUL int = 0x22 + oECADD int = 0x23 + oECSIGN int = 0x24 + oECRECOVER int = 0x25 + oECVALID int = 0x26 + oPUSH int = 0x30 + oPOP int = 0x31 + oDUP int = 0x32 + oDUPN int = 0x33 + oSWAP int = 0x34 + oSWAPN int = 0x35 + oLOAD int = 0x36 + oSTORE int = 0x37 + oJMP int = 0x40 + oJMPI int = 0x41 + oIND int = 0x42 + oEXTRO int = 0x50 + oBALANCE int = 0x51 + oMKTX int = 0x60 + oSUICIDE int = 0xff ) type OpType int + const ( - tNorm = iota - tData - tExtro - tCrypto + tNorm = iota + tData + tExtro + tCrypto ) + type TxCallback func(opType OpType) bool // Simple push/pop stack mechanism type Stack struct { - data []string + data []string } + func NewStack() *Stack { - return &Stack{} + return &Stack{} } func (st *Stack) Pop() string { - s := len(st.data) + s := len(st.data) - str := st.data[s-1] - st.data = st.data[:s-1] + str := st.data[s-1] + st.data = st.data[:s-1] - return str + return str } func (st *Stack) Popn() (*big.Int, *big.Int) { - s := len(st.data) + s := len(st.data) - strs := st.data[s-2:] - st.data = st.data[:s-2] + strs := st.data[s-2:] + st.data = st.data[:s-2] - return ethutil.Big(strs[0]), ethutil.Big(strs[1]) + return ethutil.Big(strs[0]), ethutil.Big(strs[1]) } func (st *Stack) Push(d string) { - st.data = append(st.data, d) + st.data = append(st.data, d) } func (st *Stack) Print() { - fmt.Println(st.data) + fmt.Println(st.data) } type Vm struct { - // Stack - stack *Stack + // Stack + stack *Stack } func NewVm() *Vm { - return &Vm{ - stack: NewStack(), - } + return &Vm{ + stack: NewStack(), + } } -func (vm *Vm) ProcContract( tx *ethutil.Transaction, - block *ethutil.Block, cb TxCallback) { - // Instruction pointer - pc := 0 +func (vm *Vm) ProcContract(tx *ethutil.Transaction, + block *ethutil.Block, cb TxCallback) { + // Instruction pointer + pc := 0 - contract := block.GetContract(tx.Hash()) - if contract == nil { - fmt.Println("Contract not found") - return - } + contract := block.GetContract(tx.Hash()) + if contract == nil { + fmt.Println("Contract not found") + return + } - Pow256 := ethutil.BigPow(2, 256) + Pow256 := ethutil.BigPow(2, 256) - //fmt.Printf("# op arg\n") + //fmt.Printf("# op arg\n") out: - for { - // The base big int for all calculations. Use this for any results. - base := new(big.Int) - // XXX Should Instr return big int slice instead of string slice? - // Get the next instruction from the contract - //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) - nb := ethutil.NumberToBytes(uint64(pc), 32) - op, _, _ := ethutil.Instr(contract.State().Get(string(nb))) + for { + // The base big int for all calculations. Use this for any results. + base := new(big.Int) + // XXX Should Instr return big int slice instead of string slice? + // Get the next instruction from the contract + //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc))))) + nb := ethutil.NumberToBytes(uint64(pc), 32) + op, _, _ := ethutil.Instr(contract.State().Get(string(nb))) - if !cb(0) { break } + if !cb(0) { + break + } - if Debug { - //fmt.Printf("%-3d %-4d\n", pc, op) - } + if Debug { + //fmt.Printf("%-3d %-4d\n", pc, op) + } - switch op { - case oADD: - x, y := vm.stack.Popn() - // (x + y) % 2 ** 256 - base.Add(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base.String()) - case oSUB: - x, y := vm.stack.Popn() - // (x - y) % 2 ** 256 - base.Sub(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base.String()) - case oMUL: - x, y := vm.stack.Popn() - // (x * y) % 2 ** 256 - base.Mul(x, y) - base.Mod(base, Pow256) - // Pop result back on the stack - vm.stack.Push(base.String()) - case oDIV: - x, y := vm.stack.Popn() - // floor(x / y) - base.Div(x, y) - // Pop result back on the stack - vm.stack.Push(base.String()) - case oSDIV: - x, y := vm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) } - if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) } - z := new(big.Int) - z.Div(x, y) - if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) } - // Push result on to the stack - vm.stack.Push(z.String()) - case oMOD: - x, y := vm.stack.Popn() - base.Mod(x, y) - vm.stack.Push(base.String()) - case oSMOD: - x, y := vm.stack.Popn() - // n > 2**255 - if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) } - if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) } - z := new(big.Int) - z.Mod(x, y) - if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) } - // Push result on to the stack - vm.stack.Push(z.String()) - case oEXP: - x, y := vm.stack.Popn() - base.Exp(x, y, Pow256) + switch op { + case oADD: + x, y := vm.stack.Popn() + // (x + y) % 2 ** 256 + base.Add(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base.String()) + case oSUB: + x, y := vm.stack.Popn() + // (x - y) % 2 ** 256 + base.Sub(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base.String()) + case oMUL: + x, y := vm.stack.Popn() + // (x * y) % 2 ** 256 + base.Mul(x, y) + base.Mod(base, Pow256) + // Pop result back on the stack + vm.stack.Push(base.String()) + case oDIV: + x, y := vm.stack.Popn() + // floor(x / y) + base.Div(x, y) + // Pop result back on the stack + vm.stack.Push(base.String()) + case oSDIV: + x, y := vm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Div(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + vm.stack.Push(z.String()) + case oMOD: + x, y := vm.stack.Popn() + base.Mod(x, y) + vm.stack.Push(base.String()) + case oSMOD: + x, y := vm.stack.Popn() + // n > 2**255 + if x.Cmp(Pow256) > 0 { + x.Sub(Pow256, x) + } + if y.Cmp(Pow256) > 0 { + y.Sub(Pow256, y) + } + z := new(big.Int) + z.Mod(x, y) + if z.Cmp(Pow256) > 0 { + z.Sub(Pow256, z) + } + // Push result on to the stack + vm.stack.Push(z.String()) + case oEXP: + x, y := vm.stack.Popn() + base.Exp(x, y, Pow256) - vm.stack.Push(base.String()) - case oNEG: - base.Sub(Pow256, ethutil.Big(vm.stack.Pop())) - vm.stack.Push(base.String()) - case oLT: - x, y := vm.stack.Popn() - // x < y - if x.Cmp(y) < 0 { - vm.stack.Push("1") - } else { - vm.stack.Push("0") - } - case oLE: - x, y := vm.stack.Popn() - // x <= y - if x.Cmp(y) < 1 { - vm.stack.Push("1") - } else { - vm.stack.Push("0") - } - case oGT: - x, y := vm.stack.Popn() - // x > y - if x.Cmp(y) > 0 { - vm.stack.Push("1") - } else { - vm.stack.Push("0") - } - case oGE: - x, y := vm.stack.Popn() - // x >= y - if x.Cmp(y) > -1 { - vm.stack.Push("1") - } else { - vm.stack.Push("0") - } - case oNOT: - x, y := vm.stack.Popn() - // x != y - if x.Cmp(y) != 0 { - vm.stack.Push("1") - } else { - vm.stack.Push("0") - } - case oMYADDRESS: - vm.stack.Push(string(tx.Hash())) - case oTXSENDER: - vm.stack.Push(string(tx.Sender())) - case oPUSH: - // Get the next entry and pushes the value on the stack - pc++ - vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32)))) - case oPOP: - // Pop current value of the stack - vm.stack.Pop() - case oLOAD: - // Load instruction X on the stack - i, _ := strconv.Atoi(vm.stack.Pop()) - vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32)))) - case oSTOP: - break out - } - pc++ - } + vm.stack.Push(base.String()) + case oNEG: + base.Sub(Pow256, ethutil.Big(vm.stack.Pop())) + vm.stack.Push(base.String()) + case oLT: + x, y := vm.stack.Popn() + // x < y + if x.Cmp(y) < 0 { + vm.stack.Push("1") + } else { + vm.stack.Push("0") + } + case oLE: + x, y := vm.stack.Popn() + // x <= y + if x.Cmp(y) < 1 { + vm.stack.Push("1") + } else { + vm.stack.Push("0") + } + case oGT: + x, y := vm.stack.Popn() + // x > y + if x.Cmp(y) > 0 { + vm.stack.Push("1") + } else { + vm.stack.Push("0") + } + case oGE: + x, y := vm.stack.Popn() + // x >= y + if x.Cmp(y) > -1 { + vm.stack.Push("1") + } else { + vm.stack.Push("0") + } + case oNOT: + x, y := vm.stack.Popn() + // x != y + if x.Cmp(y) != 0 { + vm.stack.Push("1") + } else { + vm.stack.Push("0") + } + case oMYADDRESS: + vm.stack.Push(string(tx.Hash())) + case oTXSENDER: + vm.stack.Push(string(tx.Sender())) + case oPUSH: + // Get the next entry and pushes the value on the stack + pc++ + vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32)))) + case oPOP: + // Pop current value of the stack + vm.stack.Pop() + case oLOAD: + // Load instruction X on the stack + i, _ := strconv.Atoi(vm.stack.Pop()) + vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32)))) + case oSTOP: + break out + } + pc++ + } - vm.stack.Print() + vm.stack.Print() } |