aboutsummaryrefslogblamecommitdiffstats
path: root/rpc/api/admin.go
blob: b27482cfea5166e7d81e086942b67c526ad9aec7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                     
                                                   




                                                    
                               





                                               








                                                                     

                                                              









                                                                       

                               


                                  
                                                                                        


                                   

                                         




                                          
                                                    
              
                                     







                                                                         
                                                         






                                                           
                                  

 



                                           

                                                                         
                                                                    













                                                                       



                                                                          



                                                                         










                                                                             
                                                                    









































                                                                                               
                                                                    
















                                                                                              
                                                                    






                                                                   
                                                                                 


                                                                                  
                                                  
                                                 

                                                            
              



                                                                         
                                                                    








                                                                   

                                                                          










                                                                    


                                                                                    

         
                                                              


                                






                                                                         
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/comms"
    "github.com/ethereum/go-ethereum/rpc/shared"
    "github.com/ethereum/go-ethereum/xeth"
)

const (
    AdminApiversion = "1.0"
    importBatchSize = 2500
)

var (
    // mapping between methods and handlers
    AdminMapping = map[string]adminhandler{
        "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,
        "admin_startRPC":        (*adminApi).StartRPC,
        "admin_stopRPC":         (*adminApi).StopRPC,
    }
)

// admin callback handler
type adminhandler func(*adminApi, *shared.Request) (interface{}, error)

// admin api provider
type adminApi struct {
    xeth     *xeth.XEth
    ethereum *eth.Ethereum
    codec    codec.Codec
    coder    codec.ApiCoder
}

// create a new admin api instance
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi {
    return &adminApi{
        xeth:     xeth,
        ethereum: ethereum,
        codec:    codec,
        coder:    codec.New(nil),
    }
}

// collection with supported methods
func (self *adminApi) Methods() []string {
    methods := make([]string, len(AdminMapping))
    i := 0
    for k := range AdminMapping {
        methods[i] = k
        i++
    }
    return methods
}

// Execute given request
func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
    if callback, ok := AdminMapping[req.Method]; ok {
        return callback(self, req)
    }

    return nil, &shared.NotImplementedError{req.Method}
}

func (self *adminApi) Name() string {
    return shared.AdminApiName
}

func (self *adminApi) ApiVersion() string {
    return AdminApiversion
}

func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
    args := new(AddPeerArgs)
    if err := self.coder.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
}

func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
    return self.ethereum.DataDir, 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.coder.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.coder.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.coder.Decode(req.Params, &args); err != nil {
        return nil, shared.NewDecodeParamError(err.Error())
    }

    glog.SetV(args.Level)
    return true, nil
}

func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) {
    pending, cached, importing, estimate := self.ethereum.Downloader().Stats()

    return map[string]interface{}{
        "blocksAvailable":        pending,
        "blocksWaitingForImport": cached,
        "importing":              importing,
        "estimate":               estimate.String(),
    }, nil
}

func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
    args := new(SetSolcArgs)
    if err := self.coder.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
}

func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
    args := new(StartRPCArgs)
    if err := self.coder.Decode(req.Params, &args); err != nil {
        return nil, shared.NewDecodeParamError(err.Error())
    }

    cfg := comms.HttpConfig{
        ListenAddress: args.ListenAddress,
        ListenPort:    args.ListenPort,
        CorsDomain:    args.CorsDomain,
    }

    apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum)
    if err != nil {
        return false, err
    }

    err = comms.StartHttp(cfg, self.codec, Merge(apis...))
    if err == nil {
        return true, nil
    }
    return false, err
}

func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
    comms.StopHttp()
    return true, nil
}