admin.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package api
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "github.com/ethereum/go-ethereum/core"
  7. "github.com/ethereum/go-ethereum/core/types"
  8. "github.com/ethereum/go-ethereum/eth"
  9. "github.com/ethereum/go-ethereum/logger/glog"
  10. "github.com/ethereum/go-ethereum/rlp"
  11. "github.com/ethereum/go-ethereum/rpc/codec"
  12. "github.com/ethereum/go-ethereum/rpc/shared"
  13. "github.com/ethereum/go-ethereum/xeth"
  14. )
  15. const (
  16. AdminVersion = "1.0.0"
  17. importBatchSize = 2500
  18. )
  19. var (
  20. // mapping between methods and handlers
  21. AdminMapping = map[string]adminhandler{
  22. // "admin_startRPC": (*adminApi).StartRPC,
  23. // "admin_stopRPC": (*adminApi).StopRPC,
  24. "admin_addPeer": (*adminApi).AddPeer,
  25. "admin_peers": (*adminApi).Peers,
  26. "admin_nodeInfo": (*adminApi).NodeInfo,
  27. "admin_exportChain": (*adminApi).ExportChain,
  28. "admin_importChain": (*adminApi).ImportChain,
  29. "admin_verbosity": (*adminApi).Verbosity,
  30. "admin_chainSyncStatus": (*adminApi).ChainSyncStatus,
  31. "admin_setSolc": (*adminApi).SetSolc,
  32. "admin_datadir": (*adminApi).DataDir,
  33. }
  34. )
  35. // admin callback handler
  36. type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
  37. // admin api provider
  38. type adminApi struct {
  39. xeth *xeth.XEth
  40. ethereum *eth.Ethereum
  41. methods map[string]adminhandler
  42. codec codec.ApiCoder
  43. }
  44. // create a new admin api instance
  45. func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *adminApi {
  46. return &adminApi{
  47. xeth: xeth,
  48. ethereum: ethereum,
  49. methods: AdminMapping,
  50. codec: coder.New(nil),
  51. }
  52. }
  53. // collection with supported methods
  54. func (self *adminApi) Methods() []string {
  55. methods := make([]string, len(self.methods))
  56. i := 0
  57. for k := range self.methods {
  58. methods[i] = k
  59. i++
  60. }
  61. return methods
  62. }
  63. // Execute given request
  64. func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
  65. if callback, ok := self.methods[req.Method]; ok {
  66. return callback(self, req)
  67. }
  68. return nil, &shared.NotImplementedError{req.Method}
  69. }
  70. func (self *adminApi) Name() string {
  71. return AdminApiName
  72. }
  73. func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
  74. args := new(AddPeerArgs)
  75. if err := self.codec.Decode(req.Params, &args); err != nil {
  76. return nil, shared.NewDecodeParamError(err.Error())
  77. }
  78. err := self.ethereum.AddPeer(args.Url)
  79. if err == nil {
  80. return true, nil
  81. }
  82. return false, err
  83. }
  84. func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
  85. return self.ethereum.PeersInfo(), nil
  86. }
  87. func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
  88. return false, nil
  89. // Enable when http rpc interface is refactored to prevent import cycles
  90. // args := new(StartRpcArgs)
  91. // if err := self.codec.Decode(req.Params, &args); err != nil {
  92. // return nil, shared.NewDecodeParamError(err.Error())
  93. // }
  94. //
  95. // cfg := rpc.RpcConfig{
  96. // ListenAddress: args.Address,
  97. // ListenPort: args.Port,
  98. // }
  99. //
  100. // err := rpc.Start(self.xeth, cfg)
  101. // if err == nil {
  102. // return true, nil
  103. // }
  104. // return false, err
  105. }
  106. func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
  107. return false, nil
  108. // Enable when http rpc interface is refactored to prevent import cycles
  109. // rpc.Stop()
  110. // return true, nil
  111. }
  112. func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
  113. return self.ethereum.NodeInfo(), nil
  114. }
  115. func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
  116. return self.ethereum.DataDir, nil
  117. }
  118. func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
  119. for _, b := range bs {
  120. if !chain.HasBlock(b.Hash()) {
  121. return false
  122. }
  123. }
  124. return true
  125. }
  126. func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
  127. args := new(ImportExportChainArgs)
  128. if err := self.codec.Decode(req.Params, &args); err != nil {
  129. return nil, shared.NewDecodeParamError(err.Error())
  130. }
  131. fh, err := os.Open(args.Filename)
  132. if err != nil {
  133. return false, err
  134. }
  135. defer fh.Close()
  136. stream := rlp.NewStream(fh, 0)
  137. // Run actual the import.
  138. blocks := make(types.Blocks, importBatchSize)
  139. n := 0
  140. for batch := 0; ; batch++ {
  141. i := 0
  142. for ; i < importBatchSize; i++ {
  143. var b types.Block
  144. if err := stream.Decode(&b); err == io.EOF {
  145. break
  146. } else if err != nil {
  147. return false, fmt.Errorf("at block %d: %v", n, err)
  148. }
  149. blocks[i] = &b
  150. n++
  151. }
  152. if i == 0 {
  153. break
  154. }
  155. // Import the batch.
  156. if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) {
  157. continue
  158. }
  159. if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil {
  160. return false, fmt.Errorf("invalid block %d: %v", n, err)
  161. }
  162. }
  163. return true, nil
  164. }
  165. func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
  166. args := new(ImportExportChainArgs)
  167. if err := self.codec.Decode(req.Params, &args); err != nil {
  168. return nil, shared.NewDecodeParamError(err.Error())
  169. }
  170. fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
  171. if err != nil {
  172. return false, err
  173. }
  174. defer fh.Close()
  175. if err := self.ethereum.ChainManager().Export(fh); err != nil {
  176. return false, err
  177. }
  178. return true, nil
  179. }
  180. func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
  181. args := new(VerbosityArgs)
  182. if err := self.codec.Decode(req.Params, &args); err != nil {
  183. return nil, shared.NewDecodeParamError(err.Error())
  184. }
  185. glog.SetV(args.Level)
  186. return true, nil
  187. }
  188. func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) {
  189. pending, cached := self.ethereum.Downloader().Stats()
  190. return map[string]interface{}{"blocksAvailable": pending, "blocksWaitingForImport": cached}, nil
  191. }
  192. func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
  193. args := new(SetSolcArgs)
  194. if err := self.codec.Decode(req.Params, &args); err != nil {
  195. return nil, shared.NewDecodeParamError(err.Error())
  196. }
  197. solc, err := self.xeth.SetSolc(args.Path)
  198. if err != nil {
  199. return nil, err
  200. }
  201. return solc.Info(), nil
  202. }