From cc9ae399338557b6671e8fc83bb696c5ddb068fe Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Tue, 9 Jun 2015 16:06:51 +0200 Subject: added admin API --- rpc/api/admin.go | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 rpc/api/admin.go (limited to 'rpc/api/admin.go') diff --git a/rpc/api/admin.go b/rpc/api/admin.go new file mode 100644 index 000000000..c37463604 --- /dev/null +++ b/rpc/api/admin.go @@ -0,0 +1,228 @@ +package api + +import ( + "fmt" + "io" + "os" + + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc/codec" + "github.com/ethereum/go-ethereum/rpc/shared" + "github.com/ethereum/go-ethereum/xeth" +) + +const ( + AdminVersion = "1.0.0" + importBatchSize = 2500 +) + +var ( + // mapping between methods and handlers + AdminMapping = map[string]adminhandler{ + // "admin_startRPC": (*adminApi).StartRPC, + // "admin_stopRPC": (*adminApi).StopRPC, + "admin_addPeer": (*adminApi).AddPeer, + "admin_peers": (*adminApi).Peers, + "admin_nodeInfo": (*adminApi).NodeInfo, + "admin_exportChain": (*adminApi).ExportChain, + "admin_importChain": (*adminApi).ImportChain, + "admin_verbosity": (*adminApi).Verbosity, + "admin_syncStatus": (*adminApi).SyncStatus, + "admin_setSolc": (*adminApi).SetSolc, + } +) + +// admin callback handler +type adminhandler func(*adminApi, *shared.Request) (interface{}, error) + +// admin api provider +type adminApi struct { + xeth *xeth.XEth + ethereum *eth.Ethereum + methods map[string]adminhandler + codec codec.ApiCoder +} + +// create a new admin api instance +func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *adminApi { + return &adminApi{ + xeth: xeth, + ethereum: ethereum, + methods: AdminMapping, + codec: coder.New(nil), + } +} + +// collection with supported methods +func (self *adminApi) Methods() []string { + methods := make([]string, len(self.methods)) + i := 0 + for k := range self.methods { + methods[i] = k + i++ + } + return methods +} + +// Execute given request +func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { + if callback, ok := self.methods[req.Method]; ok { + return callback(self, req) + } + + return nil, &shared.NotImplementedError{req.Method} +} + +func (self *adminApi) Name() string { + return AdminApiName +} + +func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { + args := new(AddPeerArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + err := self.ethereum.AddPeer(args.Url) + if err == nil { + return true, nil + } + return false, err +} + +func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { + return self.ethereum.PeersInfo(), nil +} + +func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { + return false, nil + // Enable when http rpc interface is refactored to prevent import cycles + // args := new(StartRpcArgs) + // if err := self.codec.Decode(req.Params, &args); err != nil { + // return nil, shared.NewDecodeParamError(err.Error()) + // } + // + // cfg := rpc.RpcConfig{ + // ListenAddress: args.Address, + // ListenPort: args.Port, + // } + // + // err := rpc.Start(self.xeth, cfg) + // if err == nil { + // return true, nil + // } + // return false, err +} + +func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) { + return false, nil + // Enable when http rpc interface is refactored to prevent import cycles + // rpc.Stop() + // return true, nil +} + +func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { + return self.ethereum.NodeInfo(), nil +} + +func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool { + for _, b := range bs { + if !chain.HasBlock(b.Hash()) { + return false + } + } + return true +} + +func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) { + args := new(ImportExportChainArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + fh, err := os.Open(args.Filename) + if err != nil { + return false, err + } + defer fh.Close() + stream := rlp.NewStream(fh, 0) + + // Run actual the import. + blocks := make(types.Blocks, importBatchSize) + n := 0 + for batch := 0; ; batch++ { + + i := 0 + for ; i < importBatchSize; i++ { + var b types.Block + if err := stream.Decode(&b); err == io.EOF { + break + } else if err != nil { + return false, fmt.Errorf("at block %d: %v", n, err) + } + blocks[i] = &b + n++ + } + if i == 0 { + break + } + // Import the batch. + if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) { + continue + } + if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil { + return false, fmt.Errorf("invalid block %d: %v", n, err) + } + } + return true, nil +} + +func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) { + args := new(ImportExportChainArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) + if err != nil { + return false, err + } + defer fh.Close() + if err := self.ethereum.ChainManager().Export(fh); err != nil { + return false, err + } + + return true, nil +} + +func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) { + args := new(VerbosityArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + glog.SetV(args.Level) + return true, nil +} + +func (self *adminApi) SyncStatus(req *shared.Request) (interface{}, error) { + pending, cached := self.ethereum.Downloader().Stats() + return map[string]interface{}{"available": pending, "waitingForImport": cached}, nil +} + +func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { + args := new(SetSolcArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + solc, err := self.xeth.SetSolc(args.Path) + if err != nil { + return nil, err + } + return solc.Info(), nil +} -- cgit v1.2.3