2015-06-09 17:06:51 +03:00
|
|
|
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 (
|
2015-06-10 10:42:14 +03:00
|
|
|
AdminApiversion = "1.0"
|
2015-06-09 17:06:51 +03:00
|
|
|
importBatchSize = 2500
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// mapping between methods and handlers
|
|
|
|
AdminMapping = map[string]adminhandler{
|
2015-06-10 12:29:52 +03:00
|
|
|
"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_chainSyncStatus": (*adminApi).ChainSyncStatus,
|
|
|
|
"admin_setSolc": (*adminApi).SetSolc,
|
|
|
|
"admin_datadir": (*adminApi).DataDir,
|
2015-06-09 17:06:51 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2015-06-10 10:42:14 +03:00
|
|
|
func (self *adminApi) ApiVersion() string {
|
|
|
|
return AdminApiversion
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:06:51 +03:00
|
|
|
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) NodeInfo(req *shared.Request) (interface{}, error) {
|
|
|
|
return self.ethereum.NodeInfo(), nil
|
|
|
|
}
|
|
|
|
|
2015-06-10 12:29:52 +03:00
|
|
|
func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
|
|
|
|
return self.ethereum.DataDir, nil
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:06:51 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-06-10 12:29:52 +03:00
|
|
|
func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) {
|
2015-06-10 10:42:14 +03:00
|
|
|
pending, cached, importing, estimate := self.ethereum.Downloader().Stats()
|
|
|
|
|
|
|
|
return map[string]interface{}{
|
2015-06-16 15:59:39 +03:00
|
|
|
"blocksAvailable": pending,
|
2015-06-10 10:42:14 +03:00
|
|
|
"blocksWaitingForImport": cached,
|
2015-06-16 15:59:39 +03:00
|
|
|
"importing": importing,
|
|
|
|
"estimate": estimate.String(),
|
2015-06-10 10:42:14 +03:00
|
|
|
}, nil
|
2015-06-09 17:06:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|