diff options
author | obscuren <geffobscura@gmail.com> | 2014-05-20 23:09:26 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-05-20 23:09:26 +0800 |
commit | c07c454935609bfb0f65dc38bb596a90d5493fbb (patch) | |
tree | b8d4ffc72b06bcd60d6f61de70bea8b680ed8333 | |
parent | 942f552c620471602326c1ded54095c1cf41ed76 (diff) | |
parent | 34014c1c516ea03b28e56db1a0478087d2416f74 (diff) | |
download | go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar.gz go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar.bz2 go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar.lz go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar.xz go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.tar.zst go-tangerine-c07c454935609bfb0f65dc38bb596a90d5493fbb.zip |
Merge branch 'release/poc5-rc7'poc5-rc7
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | ethereal/assets/samplecoin/samplecoin.html | 2 | ||||
-rw-r--r-- | ethereal/config.go | 2 | ||||
-rw-r--r-- | ethereal/ethereum.go | 2 | ||||
-rw-r--r-- | ethereal/ui/ext_app.go | 12 | ||||
-rw-r--r-- | ethereal/ui/gui.go | 23 | ||||
-rw-r--r-- | ethereal/ui/html_container.go | 60 | ||||
-rw-r--r-- | ethereum/config.go | 9 | ||||
-rw-r--r-- | ethereum/dev_console.go | 259 | ||||
-rw-r--r-- | ethereum/ethereum.go | 58 | ||||
-rw-r--r-- | ethereum/javascript_runtime.go | 114 | ||||
-rw-r--r-- | ethereum/js_lib.go | 53 | ||||
-rw-r--r-- | ethereum/repl.go | 97 | ||||
-rw-r--r-- | ethereum/repl_darwin.go | 93 | ||||
l--------- | ethereum/repl_linux.go | 1 | ||||
-rw-r--r-- | ethereum/repl_windows.go | 24 | ||||
-rw-r--r-- | utils/cmd.go | 15 |
17 files changed, 522 insertions, 304 deletions
@@ -5,7 +5,7 @@ Ethereum Ethereum Go Client © 2014 Jeffrey Wilcke. -Current state: Proof of Concept 5.0 RC6. +Current state: Proof of Concept 5.0 RC7. For the development package please see the [eth-go package](https://github.com/ethereum/eth-go). diff --git a/ethereal/assets/samplecoin/samplecoin.html b/ethereal/assets/samplecoin/samplecoin.html index 3f8eacc00..d47c6323c 100644 --- a/ethereal/assets/samplecoin/samplecoin.html +++ b/ethereal/assets/samplecoin/samplecoin.html @@ -9,7 +9,7 @@ <script type="text/javascript"> -var jefcoinAddr = "681fd48ffa236549fbcd16bdf9f98bb541a7f742" +var jefcoinAddr = "739105c31705038744d190332e3a07c8fea8a9eb" var mAddr = "" function createTransaction() { diff --git a/ethereal/config.go b/ethereal/config.go index e4bdb0a00..817befc2c 100644 --- a/ethereal/config.go +++ b/ethereal/config.go @@ -33,7 +33,7 @@ func Init() { flag.StringVar(&OutboundPort, "p", "30303", "listening port") flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") - flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") + flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers") flag.StringVar(&AssetPath, "asset_path", "", "absolute path to GUI assets directory") flag.Parse() diff --git a/ethereal/ethereum.go b/ethereal/ethereum.go index 98fab18e3..206971b41 100644 --- a/ethereal/ethereum.go +++ b/ethereal/ethereum.go @@ -39,7 +39,7 @@ func main() { runtime.GOMAXPROCS(runtime.NumCPU()) ethchain.InitFees() - ethutil.ReadConfig(DataDir) + ethutil.ReadConfig(DataDir, ethutil.LogFile|ethutil.LogStd) // Instantiated a eth stack ethereum, err := eth.New(eth.CapDefault, UseUPnP) diff --git a/ethereal/ui/ext_app.go b/ethereal/ui/ext_app.go index de5f15db6..d1a256cdb 100644 --- a/ethereal/ui/ext_app.go +++ b/ethereal/ui/ext_app.go @@ -18,14 +18,16 @@ type AppContainer interface { NewBlock(*ethchain.Block) ObjectChanged(*ethchain.StateObject) StorageChanged(*ethchain.StorageState) + NewWatcher(chan bool) } type ExtApplication struct { *ethpub.PEthereum - blockChan chan ethutil.React - changeChan chan ethutil.React - quitChan chan bool + blockChan chan ethutil.React + changeChan chan ethutil.React + quitChan chan bool + watcherQuitChan chan bool container AppContainer lib *UiLib @@ -38,6 +40,7 @@ func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication { make(chan ethutil.React, 1), make(chan ethutil.React, 1), make(chan bool), + make(chan bool), container, lib, nil, @@ -66,6 +69,8 @@ func (app *ExtApplication) run() { reactor := app.lib.eth.Reactor() reactor.Subscribe("newBlock", app.blockChan) + app.container.NewWatcher(app.watcherQuitChan) + win := app.container.Window() win.Show() win.Wait() @@ -83,6 +88,7 @@ func (app *ExtApplication) stop() { // Kill the main loop app.quitChan <- true + app.watcherQuitChan <- true close(app.blockChan) close(app.quitChan) diff --git a/ethereal/ui/gui.go b/ethereal/ui/gui.go index aa0364998..e267dabfd 100644 --- a/ethereal/ui/gui.go +++ b/ethereal/ui/gui.go @@ -55,7 +55,7 @@ func New(ethereum *eth.Ethereum) *Gui { } func (gui *Gui) Start(assetPath string) { - const version = "0.5.0 RC6" + const version = "0.5.0 RC7" defer gui.txDb.Close() @@ -178,13 +178,14 @@ func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) { // Simple go routine function that updates the list of peers in the GUI func (gui *Gui) update() { - blockChan := make(chan ethutil.React, 1) reactor := gui.eth.Reactor() - reactor.Subscribe("newBlock", blockChan) + blockChan := make(chan ethutil.React, 1) + txChan := make(chan ethutil.React, 1) - txChan := make(chan ethchain.TxMsg, 1) - gui.eth.TxPool().Subscribe(txChan) + reactor.Subscribe("newBlock", blockChan) + reactor.Subscribe("newTx:pre", txChan) + reactor.Subscribe("newTx:post", txChan) state := gui.eth.StateManager().TransState() @@ -196,21 +197,23 @@ func (gui *Gui) update() { case b := <-blockChan: block := b.Resource.(*ethchain.Block) if bytes.Compare(block.Coinbase, gui.addr) == 0 { - gui.setWalletValue(gui.eth.StateManager().ProcState().GetAccount(gui.addr).Amount, nil) + gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.addr).Amount, nil) } case txMsg := <-txChan: - tx := txMsg.Tx + tx := txMsg.Resource.(*ethchain.Transaction) - if txMsg.Type == ethchain.TxPre { + if txMsg.Event == "newTx:pre" { object := state.GetAccount(gui.addr) if bytes.Compare(tx.Sender(), gui.addr) == 0 && object.Nonce <= tx.Nonce { gui.win.Root().Call("addTx", ethpub.NewPTx(tx)) gui.txDb.Put(tx.Hash(), tx.RlpEncode()) - object.Nonce += 1 - state.SetStateObject(object) + /* + object.Nonce += 1 + state.SetStateObject(object) + */ unconfirmedFunds.Sub(unconfirmedFunds, tx.Value) } else if bytes.Compare(tx.Recipient, gui.addr) == 0 { diff --git a/ethereal/ui/html_container.go b/ethereal/ui/html_container.go index 4f12aaaf6..3867c0353 100644 --- a/ethereal/ui/html_container.go +++ b/ethereal/ui/html_container.go @@ -6,6 +6,12 @@ import ( "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethutil" "github.com/go-qml/qml" + "github.com/howeyc/fsnotify" + "io/ioutil" + "log" + "net/url" + "os" + "path" "path/filepath" ) @@ -15,6 +21,7 @@ type HtmlApplication struct { engine *qml.Engine lib *UiLib path string + watcher *fsnotify.Watcher } func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication { @@ -47,6 +54,59 @@ func (app *HtmlApplication) Create() error { return nil } +func (app *HtmlApplication) RootFolder() string { + folder, err := url.Parse(app.path) + if err != nil { + return "" + } + return path.Dir(folder.RequestURI()) +} +func (app *HtmlApplication) RecursiveFolders() []os.FileInfo { + files, _ := ioutil.ReadDir(app.RootFolder()) + var folders []os.FileInfo + for _, file := range files { + if file.IsDir() { + folders = append(folders, file) + } + } + return folders +} + +func (app *HtmlApplication) NewWatcher(quitChan chan bool) { + var err error + + app.watcher, err = fsnotify.NewWatcher() + if err != nil { + return + } + err = app.watcher.Watch(app.RootFolder()) + if err != nil { + log.Fatal(err) + } + for _, folder := range app.RecursiveFolders() { + fullPath := app.RootFolder() + "/" + folder.Name() + app.watcher.Watch(fullPath) + } + + go func() { + out: + for { + select { + case <-quitChan: + app.watcher.Close() + break out + case <-app.watcher.Event: + //ethutil.Config.Log.Debugln("Got event:", ev) + app.webView.Call("reload") + case err := <-app.watcher.Error: + // TODO: Do something here + ethutil.Config.Log.Infoln("Watcher error:", err) + } + } + }() + +} + func (app *HtmlApplication) Engine() *qml.Engine { return app.engine } diff --git a/ethereum/config.go b/ethereum/config.go index 7ca1a9801..97e8687d8 100644 --- a/ethereum/config.go +++ b/ethereum/config.go @@ -4,7 +4,6 @@ import ( "flag" ) -var StartConsole bool var StartMining bool var StartRpc bool var RpcPort int @@ -20,12 +19,12 @@ var ExportKey bool var LogFile string var DataDir string var NonInteractive bool +var StartJsConsole bool +var InputFile string func Init() { - flag.BoolVar(&StartConsole, "c", false, "debug and testing console") flag.BoolVar(&StartMining, "m", false, "start dagger mining") flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") - //flag.BoolVar(&UseGui, "gui", true, "use the gui") flag.BoolVar(&StartRpc, "r", false, "start rpc server") flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") @@ -37,7 +36,9 @@ func Init() { flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") flag.StringVar(&DataDir, "dir", ".ethereum", "ethereum data directory") flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") - flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") + flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers") + flag.BoolVar(&StartJsConsole, "js", false, "exp") + flag.StringVar(&InputFile, "e", "", "Run javascript file") flag.Parse() } diff --git a/ethereum/dev_console.go b/ethereum/dev_console.go deleted file mode 100644 index 5941c03ab..000000000 --- a/ethereum/dev_console.go +++ /dev/null @@ -1,259 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "encoding/hex" - "errors" - "fmt" - "github.com/ethereum/eth-go" - "github.com/ethereum/eth-go/ethchain" - "github.com/ethereum/eth-go/ethdb" - "github.com/ethereum/eth-go/ethutil" - "github.com/ethereum/eth-go/ethwire" - "github.com/ethereum/go-ethereum/utils" - "github.com/obscuren/mutan" - "os" - "strings" -) - -type Console struct { - db *ethdb.MemDatabase - trie *ethutil.Trie - ethereum *eth.Ethereum -} - -func NewConsole(s *eth.Ethereum) *Console { - db, _ := ethdb.NewMemDatabase() - trie := ethutil.NewTrie(db, "") - - return &Console{db: db, trie: trie, ethereum: s} -} - -func (i *Console) ValidateInput(action string, argumentLength int) error { - 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 - case action == "decode" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "encode" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "gettx" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "tx" && argumentLength != 4: - err = true - expArgCount = 4 - case action == "getaddr" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "contract" && argumentLength != 2: - err = true - expArgCount = 2 - case action == "say" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "addp" && argumentLength != 1: - err = true - expArgCount = 1 - case action == "block" && argumentLength != 1: - err = true - expArgCount = 1 - } - - if err { - return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength)) - } else { - return nil - } -} - -func (i *Console) Editor() string { - var buff bytes.Buffer - for { - reader := bufio.NewReader(os.Stdin) - str, _, err := reader.ReadLine() - if len(str) > 0 { - buff.Write(str) - buff.WriteString("\n") - } - - if err != nil && err.Error() == "EOF" { - break - } - } - - return buff.String() -} - -func (i *Console) PrintRoot() { - root := ethutil.NewValue(i.trie.Root) - if len(root.Bytes()) != 0 { - fmt.Println(hex.EncodeToString(root.Bytes())) - } else { - fmt.Println(i.trie.Root) - } -} - -func (i *Console) ParseInput(input string) bool { - 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) - } - - 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]) - - i.PrintRoot() - case "get": - fmt.Println(i.trie.Get(tokens[1])) - case "root": - i.PrintRoot() - case "rawroot": - fmt.Println(i.trie.Root) - case "print": - i.db.Print() - case "dag": - fmt.Println(ethchain.DaggerVerify(ethutil.Big(tokens[1]), // hash - ethutil.BigPow(2, 36), // diff - ethutil.Big(tokens[2]))) // nonce - case "decode": - value := ethutil.NewValueFromBytes([]byte(tokens[1])) - fmt.Println(value) - case "getaddr": - encoded, _ := hex.DecodeString(tokens[1]) - addr := i.ethereum.BlockChain().CurrentBlock.State().GetAccount(encoded) - fmt.Println("addr:", addr) - case "block": - encoded, _ := hex.DecodeString(tokens[1]) - block := i.ethereum.BlockChain().GetBlock(encoded) - info := block.BlockInfo() - fmt.Printf("++++++++++ #%d ++++++++++\n%v\n", info.Number, block) - case "say": - i.ethereum.Broadcast(ethwire.MsgTalkTy, []interface{}{tokens[1]}) - case "addp": - i.ethereum.ConnectToPeer(tokens[1]) - case "pcount": - fmt.Println("peers:", i.ethereum.Peers().Len()) - case "encode": - fmt.Printf("%q\n", ethutil.Encode(tokens[1])) - case "tx": - recipient, err := hex.DecodeString(tokens[1]) - if err != nil { - fmt.Println("recipient err:", err) - } else { - tx := ethchain.NewTransactionMessage(recipient, ethutil.Big(tokens[2]), ethutil.Big(tokens[3]), ethutil.Big(tokens[4]), nil) - - keyPair := ethutil.GetKeyRing().Get(0) - tx.Sign(keyPair.PrivateKey) - i.ethereum.TxPool().QueueTransaction(tx) - - fmt.Printf("%x\n", tx.Hash()) - } - case "gettx": - addr, _ := hex.DecodeString(tokens[1]) - data, _ := ethutil.Config.Db.Get(addr) - if len(data) != 0 { - decoder := ethutil.NewValueFromBytes(data) - fmt.Println(decoder) - } else { - fmt.Println("gettx: tx not found") - } - case "contract": - fmt.Println("Contract editor (Ctrl-D = done)") - - mainInput, initInput := mutan.PreParse(i.Editor()) - mainScript, err := utils.Compile(mainInput) - if err != nil { - fmt.Println(err) - - break - } - initScript, err := utils.Compile(initInput) - if err != nil { - fmt.Println(err) - - break - } - - contract := ethchain.NewContractCreationTx(ethutil.Big(tokens[0]), ethutil.Big(tokens[1]), ethutil.Big(tokens[1]), mainScript, initScript) - - keyPair := ethutil.GetKeyRing().Get(0) - contract.Sign(keyPair.PrivateKey) - - i.ethereum.TxPool().QueueTransaction(contract) - - fmt.Printf("%x\n", contract.Hash()[12:]) - 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" + - "block HASH - Prints the block\n" + - "getaddr ADDR - Prints the account associated with the address\n" + - "\033[1m= Dagger =\033[0m\n" + - "dag HASH NONCE - Verifies a nonce with the given hash with dagger\n" + - "\033[1m= Encoding =\033[0m\n" + - "decode STR\n" + - "encode STR\n" + - "\033[1m= Other =\033[0m\n" + - "addp HOST:PORT\n" + - "tx TO AMOUNT\n" + - "contract AMOUNT\n") - - default: - fmt.Println("Unknown command:", tokens[0]) - } - } - - 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 - } - } - } -} diff --git a/ethereum/ethereum.go b/ethereum/ethereum.go index 2abf6da42..2fdfd5caf 100644 --- a/ethereum/ethereum.go +++ b/ethereum/ethereum.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethutil" "github.com/ethereum/go-ethereum/utils" + "io/ioutil" "log" "os" "os/signal" @@ -15,16 +16,15 @@ import ( const Debug = true -// Register interrupt handlers so we can stop the ethereum -func RegisterInterrupts(s *eth.Ethereum) { - // Buffered chan of one is enough - c := make(chan os.Signal, 1) - // Notify about interrupts for now - signal.Notify(c, os.Interrupt) +func RegisterInterrupt(cb func(os.Signal)) { go func() { + // Buffered chan of one is enough + c := make(chan os.Signal, 1) + // Notify about interrupts for now + signal.Notify(c, os.Interrupt) + for sig := range c { - fmt.Printf("Shutting down (%v) ... \n", sig) - s.Stop() + cb(sig) } }() } @@ -52,7 +52,12 @@ func main() { var logSys *log.Logger flags := log.LstdFlags - ethutil.ReadConfig(DataDir) + if StartJsConsole || len(InputFile) > 0 { + ethutil.ReadConfig(DataDir, ethutil.LogFile) + } else { + ethutil.ReadConfig(DataDir, ethutil.LogFile|ethutil.LogStd) + } + logger := ethutil.Config.Log if LogFile != "" { @@ -136,21 +141,40 @@ save these words so you can restore your account later: %s utils.DoMining(ethereum) } - if StartConsole { - err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm) - // Error is OK if the error is ErrExist - if err != nil && !os.IsExist(err) { - log.Panic("Unable to create EXECPATH:", err) + if StartJsConsole { + repl := NewJSRepl(ethereum) + + go repl.Start() + + RegisterInterrupt(func(os.Signal) { + repl.Stop() + }) + } else if len(InputFile) > 0 { + file, err := os.Open(InputFile) + if err != nil { + ethutil.Config.Log.Fatal(err) } - console := NewConsole(ethereum) - go console.Start() + content, err := ioutil.ReadAll(file) + if err != nil { + ethutil.Config.Log.Fatal(err) + } + + re := NewJSRE(ethereum) + RegisterInterrupt(func(os.Signal) { + re.Stop() + }) + re.Run(string(content)) } + if StartRpc { utils.DoRpc(ethereum, RpcPort) } - RegisterInterrupts(ethereum) + RegisterInterrupt(func(sig os.Signal) { + fmt.Printf("Shutting down (%v) ... \n", sig) + ethereum.Stop() + }) ethereum.Start(UseSeed) diff --git a/ethereum/javascript_runtime.go b/ethereum/javascript_runtime.go new file mode 100644 index 000000000..b06fb9460 --- /dev/null +++ b/ethereum/javascript_runtime.go @@ -0,0 +1,114 @@ +package main + +import ( + "fmt" + "github.com/ethereum/eth-go" + "github.com/ethereum/eth-go/ethchain" + "github.com/ethereum/eth-go/ethpub" + "github.com/ethereum/eth-go/ethutil" + "github.com/robertkrimen/otto" +) + +type JSRE struct { + ethereum *eth.Ethereum + vm *otto.Otto + lib *ethpub.PEthereum + + blockChan chan ethutil.React + changeChan chan ethutil.React + quitChan chan bool + + objectCb map[string][]otto.Value +} + +func NewJSRE(ethereum *eth.Ethereum) *JSRE { + re := &JSRE{ + ethereum, + otto.New(), + ethpub.NewPEthereum(ethereum), + make(chan ethutil.React, 1), + make(chan ethutil.React, 1), + make(chan bool), + make(map[string][]otto.Value), + } + + // Init the JS lib + re.vm.Run(jsLib) + + // We have to make sure that, whoever calls this, calls "Stop" + go re.mainLoop() + + re.Bind("eth", &JSEthereum{re.lib, re.vm}) + + re.initStdFuncs() + + return re +} + +func (self *JSRE) Bind(name string, v interface{}) { + self.vm.Set(name, v) +} + +func (self *JSRE) Run(code string) (otto.Value, error) { + return self.vm.Run(code) +} + +func (self *JSRE) Stop() { + // Kill the main loop + self.quitChan <- true + + close(self.blockChan) + close(self.quitChan) + close(self.changeChan) +} + +func (self *JSRE) mainLoop() { + // Subscribe to events + reactor := self.ethereum.Reactor() + reactor.Subscribe("newBlock", self.blockChan) + +out: + for { + select { + case <-self.quitChan: + break out + case block := <-self.blockChan: + if _, ok := block.Resource.(*ethchain.Block); ok { + } + case object := <-self.changeChan: + if stateObject, ok := object.Resource.(*ethchain.StateObject); ok { + for _, cb := range self.objectCb[ethutil.Hex(stateObject.Address())] { + val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject)) + cb.Call(cb, val) + } + } else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok { + fmt.Println(storageObject) + } + } + } +} + +func (self *JSRE) initStdFuncs() { + t, _ := self.vm.Get("eth") + eth := t.Object() + eth.Set("watch", func(call otto.FunctionCall) otto.Value { + addr, _ := call.Argument(0).ToString() + cb := call.Argument(1) + + self.objectCb[addr] = append(self.objectCb[addr], cb) + + event := "object:" + string(ethutil.FromHex(addr)) + self.ethereum.Reactor().Subscribe(event, self.changeChan) + + return otto.UndefinedValue() + }) + eth.Set("addPeer", func(call otto.FunctionCall) otto.Value { + host, err := call.Argument(0).ToString() + if err != nil { + return otto.FalseValue() + } + self.ethereum.ConnectToPeer(host) + + return otto.TrueValue() + }) +} diff --git a/ethereum/js_lib.go b/ethereum/js_lib.go new file mode 100644 index 000000000..189dcc3a0 --- /dev/null +++ b/ethereum/js_lib.go @@ -0,0 +1,53 @@ +package main + +const jsLib = ` +function pp(object) { + var str = ""; + + if(object instanceof Array) { + str += "[ "; + for(var i = 0, l = object.length; i < l; i++) { + str += pp(object[i]); + + if(i < l-1) { + str += ", "; + } + } + str += " ]"; + } else if(typeof(object) === "object") { + str += "{ "; + var last = Object.keys(object).sort().pop() + for(var k in object) { + str += k + ": " + pp(object[k]); + + if(k !== last) { + str += ", "; + } + } + str += " }"; + } else if(typeof(object) === "string") { + str += "\033[32m'" + object + "'"; + } else if(typeof(object) === "undefined") { + str += "\033[1m\033[30m" + object; + } else if(typeof(object) === "number") { + str += "\033[31m" + object; + } else if(typeof(object) === "function") { + str += "\033[35m[Function]"; + } else { + str += object; + } + + str += "\033[0m"; + + return str; +} + +function prettyPrint(/* */) { + var args = arguments; + for(var i = 0, l = args.length; i < l; i++) { + console.log(pp(args[i])) + } +} + +var print = prettyPrint; +` diff --git a/ethereum/repl.go b/ethereum/repl.go new file mode 100644 index 000000000..c0b63c0a5 --- /dev/null +++ b/ethereum/repl.go @@ -0,0 +1,97 @@ +package main + +import ( + "fmt" + "github.com/ethereum/eth-go" + "github.com/ethereum/eth-go/ethpub" + "github.com/robertkrimen/otto" +) + +type Repl interface { + Start() + Stop() +} + +type JSRepl struct { + re *JSRE + + prompt string +} + +func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { + return &JSRepl{re: NewJSRE(ethereum), prompt: "> "} +} + +func (self *JSRepl) Start() { + self.read() +} + +func (self *JSRepl) Stop() { + self.re.Stop() +} + +func (self *JSRepl) parseInput(code string) { + defer func() { + if r := recover(); r != nil { + fmt.Println("[native] error", r) + } + }() + + value, err := self.re.Run(code) + if err != nil { + fmt.Println(err) + return + } + + self.PrintValue(value) +} + +// The JSEthereum object attempts to wrap the PEthereum object and returns +// meaningful javascript objects +type JSEthereum struct { + *ethpub.PEthereum + vm *otto.Otto +} + +func (self *JSEthereum) GetKey() otto.Value { + return self.toVal(self.PEthereum.GetKey()) +} + +func (self *JSEthereum) GetStateObject(addr string) otto.Value { + return self.toVal(self.PEthereum.GetStateObject(addr)) +} + +func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value { + r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr) + if err != nil { + fmt.Println(err) + + return otto.UndefinedValue() + } + + return self.toVal(r) +} + +func (self *JSEthereum) Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr string) otto.Value { + r, err := self.PEthereum.Create(key, valueStr, gasStr, gasPriceStr, initStr, bodyStr) + + if err != nil { + fmt.Println(err) + + return otto.UndefinedValue() + } + + return self.toVal(r) +} + +func (self *JSEthereum) toVal(v interface{}) otto.Value { + result, err := self.vm.ToValue(v) + + if err != nil { + fmt.Println(err) + + return otto.UndefinedValue() + } + + return result +} diff --git a/ethereum/repl_darwin.go b/ethereum/repl_darwin.go new file mode 100644 index 000000000..87da3df1d --- /dev/null +++ b/ethereum/repl_darwin.go @@ -0,0 +1,93 @@ +package main + +// #cgo LDFLAGS: -lreadline +// #include <stdio.h> +// #include <stdlib.h> +// #include <readline/readline.h> +// #include <readline/history.h> +import "C" + +import ( + "github.com/robertkrimen/otto" + "strings" + "unsafe" +) + +func readLine(prompt *string) *string { + var p *C.char + + //readline allows an empty prompt(NULL) + if prompt != nil { + p = C.CString(*prompt) + } + + ret := C.readline(p) + + if p != nil { + C.free(unsafe.Pointer(p)) + } + + if ret == nil { + return nil + } //EOF + + s := C.GoString(ret) + C.free(unsafe.Pointer(ret)) + return &s +} + +func addHistory(s string) { + p := C.CString(s) + C.add_history(p) + C.free(unsafe.Pointer(p)) +} + +var indentCount = 0 +var str = "" + +func (self *JSRepl) setIndent() { + open := strings.Count(str, "{") + open += strings.Count(str, "(") + closed := strings.Count(str, "}") + closed += strings.Count(str, ")") + indentCount = open - closed + if indentCount <= 0 { + self.prompt = "> " + } else { + self.prompt = strings.Join(make([]string, indentCount*2), "..") + self.prompt += " " + } +} + +func (self *JSRepl) read() { +L: + for { + switch result := readLine(&self.prompt); true { + case result == nil: + break L + + case *result != "": + str += *result + "\n" + + self.setIndent() + + if indentCount <= 0 { + if *result == "exit" { + self.Stop() + break L + } + + addHistory(str) //allow user to recall this line + + self.parseInput(str) + + str = "" + } + } + } +} + +func (self *JSRepl) PrintValue(value otto.Value) { + method, _ := self.re.vm.Get("prettyPrint") + method.Call(method, value) +} diff --git a/ethereum/repl_linux.go b/ethereum/repl_linux.go new file mode 120000 index 000000000..276f135d7 --- /dev/null +++ b/ethereum/repl_linux.go @@ -0,0 +1 @@ +repl_darwin.go
\ No newline at end of file diff --git a/ethereum/repl_windows.go b/ethereum/repl_windows.go new file mode 100644 index 000000000..9d4787772 --- /dev/null +++ b/ethereum/repl_windows.go @@ -0,0 +1,24 @@ +package main + +import ( + "bufio" + "fmt" + "os" +) + +func (self *JSRepl) read() { + reader := bufio.NewReader(os.Stdin) + for { + fmt.Printf(self.prompt) + str, _, err := reader.ReadLine() + if err != nil { + fmt.Println("Error reading input", err) + } else { + self.parseInput(string(str)) + } + } +} + +func (self *JSRepl) PrintValue(value otto.Value) { + fmt.Println(value) +} diff --git a/utils/cmd.go b/utils/cmd.go index 8395ac8fc..f163575da 100644 --- a/utils/cmd.go +++ b/utils/cmd.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethrpc" "github.com/ethereum/eth-go/ethutil" - "log" "time" ) @@ -14,7 +13,7 @@ func DoRpc(ethereum *eth.Ethereum, RpcPort int) { var err error ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort) if err != nil { - log.Println("Could not start RPC interface:", err) + ethutil.Config.Log.Infoln("Could not start RPC interface:", err) } else { go ethereum.RpcServer.Start() } @@ -25,7 +24,7 @@ func DoMining(ethereum *eth.Ethereum) { ethereum.Mining = true if ethutil.GetKeyRing().Len() == 0 { - log.Println("No address found, can't start mining") + ethutil.Config.Log.Infoln("No address found, can't start mining") return } keyPair := ethutil.GetKeyRing().Get(0) @@ -35,10 +34,12 @@ func DoMining(ethereum *eth.Ethereum) { // Give it some time to connect with peers time.Sleep(3 * time.Second) - for ethereum.IsUpToDate() == false { - time.Sleep(5 * time.Second) - } - log.Println("Miner started") + /* + for ethereum.IsUpToDate() == false { + time.Sleep(5 * time.Second) + } + */ + ethutil.Config.Log.Infoln("Miner started") miner := ethminer.NewDefaultMiner(addr, ethereum) miner.Start() |