repl.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
  2. //
  3. // This library is free software; you can redistribute it and/or
  4. // modify it under the terms of the GNU General Public
  5. // License as published by the Free Software Foundation; either
  6. // version 2.1 of the License, or (at your option) any later version.
  7. //
  8. // This library is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. // General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this library; if not, write to the Free Software
  15. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  16. // MA 02110-1301 USA
  17. package ethrepl
  18. import (
  19. "bufio"
  20. "fmt"
  21. "io"
  22. "os"
  23. "path"
  24. "github.com/ethereum/go-ethereum/core/types"
  25. "github.com/ethereum/go-ethereum/eth"
  26. "github.com/ethereum/go-ethereum/ethutil"
  27. "github.com/ethereum/go-ethereum/javascript"
  28. "github.com/ethereum/go-ethereum/logger"
  29. "github.com/ethereum/go-ethereum/state"
  30. "github.com/ethereum/go-ethereum/xeth"
  31. "github.com/obscuren/otto"
  32. )
  33. var repllogger = logger.NewLogger("REPL")
  34. type Repl interface {
  35. Start()
  36. Stop()
  37. }
  38. type JSRepl struct {
  39. re *javascript.JSRE
  40. ethereum *eth.Ethereum
  41. xeth *xeth.XEth
  42. prompt string
  43. history *os.File
  44. running bool
  45. }
  46. func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
  47. hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
  48. if err != nil {
  49. panic(err)
  50. }
  51. xeth := xeth.New(ethereum)
  52. repl := &JSRepl{re: javascript.NewJSRE(xeth), xeth: xeth, ethereum: ethereum, prompt: "> ", history: hist}
  53. repl.initStdFuncs()
  54. return repl
  55. }
  56. func (self *JSRepl) Start() {
  57. if !self.running {
  58. self.running = true
  59. repllogger.Infoln("init JS Console")
  60. reader := bufio.NewReader(self.history)
  61. for {
  62. line, err := reader.ReadString('\n')
  63. if err != nil && err == io.EOF {
  64. break
  65. } else if err != nil {
  66. fmt.Println("error reading history", err)
  67. break
  68. }
  69. addHistory(line[:len(line)-1])
  70. }
  71. self.read()
  72. }
  73. }
  74. func (self *JSRepl) Stop() {
  75. if self.running {
  76. self.running = false
  77. repllogger.Infoln("exit JS Console")
  78. self.history.Close()
  79. }
  80. }
  81. func (self *JSRepl) parseInput(code string) {
  82. defer func() {
  83. if r := recover(); r != nil {
  84. fmt.Println("[native] error", r)
  85. }
  86. }()
  87. value, err := self.re.Run(code)
  88. if err != nil {
  89. fmt.Println(err)
  90. return
  91. }
  92. self.PrintValue(value)
  93. }
  94. func (self *JSRepl) initStdFuncs() {
  95. t, _ := self.re.Vm.Get("eth")
  96. eth := t.Object()
  97. eth.Set("connect", self.connect)
  98. eth.Set("stopMining", self.stopMining)
  99. eth.Set("startMining", self.startMining)
  100. eth.Set("dump", self.dump)
  101. eth.Set("export", self.export)
  102. }
  103. /*
  104. * The following methods are natively implemented javascript functions
  105. */
  106. func (self *JSRepl) dump(call otto.FunctionCall) otto.Value {
  107. var block *types.Block
  108. if len(call.ArgumentList) > 0 {
  109. if call.Argument(0).IsNumber() {
  110. num, _ := call.Argument(0).ToInteger()
  111. block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num))
  112. } else if call.Argument(0).IsString() {
  113. hash, _ := call.Argument(0).ToString()
  114. block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash))
  115. } else {
  116. fmt.Println("invalid argument for dump. Either hex string or number")
  117. }
  118. if block == nil {
  119. fmt.Println("block not found")
  120. return otto.UndefinedValue()
  121. }
  122. } else {
  123. block = self.ethereum.ChainManager().CurrentBlock()
  124. }
  125. statedb := state.New(block.Root(), self.ethereum.Db())
  126. v, _ := self.re.Vm.ToValue(statedb.RawDump())
  127. return v
  128. }
  129. func (self *JSRepl) stopMining(call otto.FunctionCall) otto.Value {
  130. self.xeth.Miner().Stop()
  131. return otto.TrueValue()
  132. }
  133. func (self *JSRepl) startMining(call otto.FunctionCall) otto.Value {
  134. self.xeth.Miner().Start()
  135. return otto.TrueValue()
  136. }
  137. func (self *JSRepl) connect(call otto.FunctionCall) otto.Value {
  138. nodeURL, err := call.Argument(0).ToString()
  139. if err != nil {
  140. return otto.FalseValue()
  141. }
  142. if err := self.ethereum.SuggestPeer(nodeURL); err != nil {
  143. return otto.FalseValue()
  144. }
  145. return otto.TrueValue()
  146. }
  147. func (self *JSRepl) export(call otto.FunctionCall) otto.Value {
  148. if len(call.ArgumentList) == 0 {
  149. fmt.Println("err: require file name")
  150. return otto.FalseValue()
  151. }
  152. fn, err := call.Argument(0).ToString()
  153. if err != nil {
  154. fmt.Println(err)
  155. return otto.FalseValue()
  156. }
  157. data := self.ethereum.ChainManager().Export()
  158. if err := ethutil.WriteFile(fn, data); err != nil {
  159. fmt.Println(err)
  160. return otto.FalseValue()
  161. }
  162. return otto.TrueValue()
  163. }