admin.go 6.0 KB

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