admin.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package api
  2. import (
  3. "fmt"
  4. "io"
  5. "math/big"
  6. "os"
  7. "time"
  8. "github.com/ethereum/go-ethereum/core"
  9. "github.com/ethereum/go-ethereum/core/types"
  10. "github.com/ethereum/go-ethereum/eth"
  11. "github.com/ethereum/go-ethereum/logger/glog"
  12. "github.com/ethereum/go-ethereum/rlp"
  13. "github.com/ethereum/go-ethereum/rpc/codec"
  14. "github.com/ethereum/go-ethereum/rpc/comms"
  15. "github.com/ethereum/go-ethereum/rpc/shared"
  16. "github.com/ethereum/go-ethereum/xeth"
  17. )
  18. const (
  19. AdminApiversion = "1.0"
  20. importBatchSize = 2500
  21. )
  22. var (
  23. // mapping between methods and handlers
  24. AdminMapping = map[string]adminhandler{
  25. "admin_addPeer": (*adminApi).AddPeer,
  26. "admin_peers": (*adminApi).Peers,
  27. "admin_nodeInfo": (*adminApi).NodeInfo,
  28. "admin_exportChain": (*adminApi).ExportChain,
  29. "admin_importChain": (*adminApi).ImportChain,
  30. "admin_verbosity": (*adminApi).Verbosity,
  31. "admin_chainSyncStatus": (*adminApi).ChainSyncStatus,
  32. "admin_setSolc": (*adminApi).SetSolc,
  33. "admin_datadir": (*adminApi).DataDir,
  34. "admin_startRPC": (*adminApi).StartRPC,
  35. "admin_stopRPC": (*adminApi).StopRPC,
  36. }
  37. )
  38. // admin callback handler
  39. type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
  40. // admin api provider
  41. type adminApi struct {
  42. xeth *xeth.XEth
  43. ethereum *eth.Ethereum
  44. codec codec.Codec
  45. coder codec.ApiCoder
  46. }
  47. // create a new admin api instance
  48. func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi {
  49. return &adminApi{
  50. xeth: xeth,
  51. ethereum: ethereum,
  52. codec: codec,
  53. coder: codec.New(nil),
  54. }
  55. }
  56. // collection with supported methods
  57. func (self *adminApi) Methods() []string {
  58. methods := make([]string, len(AdminMapping))
  59. i := 0
  60. for k := range AdminMapping {
  61. methods[i] = k
  62. i++
  63. }
  64. return methods
  65. }
  66. // Execute given request
  67. func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
  68. if callback, ok := AdminMapping[req.Method]; ok {
  69. return callback(self, req)
  70. }
  71. return nil, &shared.NotImplementedError{req.Method}
  72. }
  73. func (self *adminApi) Name() string {
  74. return shared.AdminApiName
  75. }
  76. func (self *adminApi) ApiVersion() string {
  77. return AdminApiversion
  78. }
  79. func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
  80. args := new(AddPeerArgs)
  81. if err := self.coder.Decode(req.Params, &args); err != nil {
  82. return nil, shared.NewDecodeParamError(err.Error())
  83. }
  84. err := self.ethereum.AddPeer(args.Url)
  85. if err == nil {
  86. return true, nil
  87. }
  88. return false, err
  89. }
  90. func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
  91. return self.ethereum.PeersInfo(), nil
  92. }
  93. func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
  94. return self.ethereum.NodeInfo(), nil
  95. }
  96. func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
  97. return self.ethereum.DataDir, nil
  98. }
  99. func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
  100. for _, b := range bs {
  101. if !chain.HasBlock(b.Hash()) {
  102. return false
  103. }
  104. }
  105. return true
  106. }
  107. func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
  108. args := new(ImportExportChainArgs)
  109. if err := self.coder.Decode(req.Params, &args); err != nil {
  110. return nil, shared.NewDecodeParamError(err.Error())
  111. }
  112. fh, err := os.Open(args.Filename)
  113. if err != nil {
  114. return false, err
  115. }
  116. defer fh.Close()
  117. stream := rlp.NewStream(fh, 0)
  118. // Run actual the import.
  119. blocks := make(types.Blocks, importBatchSize)
  120. n := 0
  121. for batch := 0; ; batch++ {
  122. i := 0
  123. for ; i < importBatchSize; i++ {
  124. var b types.Block
  125. if err := stream.Decode(&b); err == io.EOF {
  126. break
  127. } else if err != nil {
  128. return false, fmt.Errorf("at block %d: %v", n, err)
  129. }
  130. blocks[i] = &b
  131. n++
  132. }
  133. if i == 0 {
  134. break
  135. }
  136. // Import the batch.
  137. if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) {
  138. continue
  139. }
  140. if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil {
  141. return false, fmt.Errorf("invalid block %d: %v", n, err)
  142. }
  143. }
  144. return true, nil
  145. }
  146. func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
  147. args := new(ImportExportChainArgs)
  148. if err := self.coder.Decode(req.Params, &args); err != nil {
  149. return nil, shared.NewDecodeParamError(err.Error())
  150. }
  151. fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
  152. if err != nil {
  153. return false, err
  154. }
  155. defer fh.Close()
  156. if err := self.ethereum.ChainManager().Export(fh); err != nil {
  157. return false, err
  158. }
  159. return true, nil
  160. }
  161. func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
  162. args := new(VerbosityArgs)
  163. if err := self.coder.Decode(req.Params, &args); err != nil {
  164. return nil, shared.NewDecodeParamError(err.Error())
  165. }
  166. glog.SetV(args.Level)
  167. return true, nil
  168. }
  169. func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) {
  170. pending, cached, importing, estimate := self.ethereum.Downloader().Stats()
  171. return map[string]interface{}{
  172. "blocksAvailable": pending,
  173. "blocksWaitingForImport": cached,
  174. "importing": importing,
  175. "estimate": estimate.String(),
  176. }, nil
  177. }
  178. func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
  179. args := new(SetSolcArgs)
  180. if err := self.coder.Decode(req.Params, &args); err != nil {
  181. return nil, shared.NewDecodeParamError(err.Error())
  182. }
  183. solc, err := self.xeth.SetSolc(args.Path)
  184. if err != nil {
  185. return nil, err
  186. }
  187. return solc.Info(), nil
  188. }
  189. func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
  190. args := new(StartRPCArgs)
  191. if err := self.coder.Decode(req.Params, &args); err != nil {
  192. return nil, shared.NewDecodeParamError(err.Error())
  193. }
  194. cfg := comms.HttpConfig{
  195. ListenAddress: args.ListenAddress,
  196. ListenPort: args.ListenPort,
  197. CorsDomain: args.CorsDomain,
  198. }
  199. apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum)
  200. if err != nil {
  201. return false, err
  202. }
  203. err = comms.StartHttp(cfg, self.codec, Merge(apis...))
  204. if err == nil {
  205. return true, nil
  206. }
  207. return false, err
  208. }
  209. func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
  210. comms.StopHttp()
  211. return true, nil
  212. }
  213. func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) {
  214. args := new(SleepBlocksArgs)
  215. if err := self.coder.Decode(req.Params, &args); err != nil {
  216. return nil, shared.NewDecodeParamError(err.Error())
  217. }
  218. var timer <-chan time.Time
  219. var height *big.Int
  220. var err error
  221. if args.Timeout > 0 {
  222. timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C
  223. }
  224. height = new(big.Int).Add(self.xeth.CurrentBlock().Number(), big.NewInt(args.N))
  225. height, err = sleepBlocks(self.xeth.UpdateState(), height, timer)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return height.Uint64(), nil
  230. }
  231. func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) {
  232. wait <- height
  233. select {
  234. case <-timer:
  235. // if times out make sure the xeth loop does not block
  236. go func() {
  237. select {
  238. case wait <- nil:
  239. case <-wait:
  240. }
  241. }()
  242. return nil, fmt.Errorf("timeout")
  243. case newHeight = <-wait:
  244. }
  245. return
  246. }
  247. // sec, err := call.Argument(0).ToInteger()
  248. // if err != nil {
  249. // fmt.Println(err)
  250. // return otto.FalseValue()
  251. // }
  252. // time.Sleep(time.Duration(sec) * time.Second)
  253. // return otto.UndefinedValue()
  254. // }