github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/api/admin.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"math/big"
    23  	"os"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/common/compiler"
    28  	"github.com/ethereum/go-ethereum/common/docserver"
    29  	"github.com/ethereum/go-ethereum/common/natspec"
    30  	"github.com/ethereum/go-ethereum/common/registrar"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  	"github.com/ethereum/go-ethereum/eth"
    35  	"github.com/ethereum/go-ethereum/logger/glog"
    36  	"github.com/ethereum/go-ethereum/rlp"
    37  	"github.com/ethereum/go-ethereum/rpc/codec"
    38  	"github.com/ethereum/go-ethereum/rpc/comms"
    39  	"github.com/ethereum/go-ethereum/rpc/shared"
    40  	"github.com/ethereum/go-ethereum/rpc/useragent"
    41  	"github.com/ethereum/go-ethereum/xeth"
    42  )
    43  
    44  const (
    45  	AdminApiversion = "1.0"
    46  	importBatchSize = 2500
    47  )
    48  
    49  var (
    50  	// mapping between methods and handlers
    51  	AdminMapping = map[string]adminhandler{
    52  		"admin_addPeer":            (*adminApi).AddPeer,
    53  		"admin_peers":              (*adminApi).Peers,
    54  		"admin_nodeInfo":           (*adminApi).NodeInfo,
    55  		"admin_exportChain":        (*adminApi).ExportChain,
    56  		"admin_importChain":        (*adminApi).ImportChain,
    57  		"admin_verbosity":          (*adminApi).Verbosity,
    58  		"admin_chainSyncStatus":    (*adminApi).ChainSyncStatus,
    59  		"admin_setSolc":            (*adminApi).SetSolc,
    60  		"admin_datadir":            (*adminApi).DataDir,
    61  		"admin_startRPC":           (*adminApi).StartRPC,
    62  		"admin_stopRPC":            (*adminApi).StopRPC,
    63  		"admin_setGlobalRegistrar": (*adminApi).SetGlobalRegistrar,
    64  		"admin_setHashReg":         (*adminApi).SetHashReg,
    65  		"admin_setUrlHint":         (*adminApi).SetUrlHint,
    66  		"admin_saveInfo":           (*adminApi).SaveInfo,
    67  		"admin_register":           (*adminApi).Register,
    68  		"admin_registerUrl":        (*adminApi).RegisterUrl,
    69  		"admin_startNatSpec":       (*adminApi).StartNatSpec,
    70  		"admin_stopNatSpec":        (*adminApi).StopNatSpec,
    71  		"admin_getContractInfo":    (*adminApi).GetContractInfo,
    72  		"admin_httpGet":            (*adminApi).HttpGet,
    73  		"admin_sleepBlocks":        (*adminApi).SleepBlocks,
    74  		"admin_sleep":              (*adminApi).Sleep,
    75  		"admin_enableUserAgent":    (*adminApi).EnableUserAgent,
    76  	}
    77  )
    78  
    79  // admin callback handler
    80  type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
    81  
    82  // admin api provider
    83  type adminApi struct {
    84  	xeth     *xeth.XEth
    85  	ethereum *eth.Ethereum
    86  	codec    codec.Codec
    87  	coder    codec.ApiCoder
    88  	ds       *docserver.DocServer
    89  }
    90  
    91  // create a new admin api instance
    92  func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi {
    93  	return &adminApi{
    94  		xeth:     xeth,
    95  		ethereum: ethereum,
    96  		codec:    codec,
    97  		coder:    codec.New(nil),
    98  		ds:       docserver.New("/"),
    99  	}
   100  }
   101  
   102  // collection with supported methods
   103  func (self *adminApi) Methods() []string {
   104  	methods := make([]string, len(AdminMapping))
   105  	i := 0
   106  	for k := range AdminMapping {
   107  		methods[i] = k
   108  		i++
   109  	}
   110  	return methods
   111  }
   112  
   113  // Execute given request
   114  func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
   115  	if callback, ok := AdminMapping[req.Method]; ok {
   116  		return callback(self, req)
   117  	}
   118  
   119  	return nil, &shared.NotImplementedError{req.Method}
   120  }
   121  
   122  func (self *adminApi) Name() string {
   123  	return shared.AdminApiName
   124  }
   125  
   126  func (self *adminApi) ApiVersion() string {
   127  	return AdminApiversion
   128  }
   129  
   130  func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
   131  	args := new(AddPeerArgs)
   132  	if err := self.coder.Decode(req.Params, &args); err != nil {
   133  		return nil, shared.NewDecodeParamError(err.Error())
   134  	}
   135  
   136  	err := self.ethereum.AddPeer(args.Url)
   137  	if err == nil {
   138  		return true, nil
   139  	}
   140  	return false, err
   141  }
   142  
   143  func (self *adminApi) Peers(req *shared.Request) (interface{}, error) {
   144  	return self.ethereum.PeersInfo(), nil
   145  }
   146  
   147  func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) {
   148  	return self.ethereum.NodeInfo(), nil
   149  }
   150  
   151  func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) {
   152  	return self.ethereum.DataDir, nil
   153  }
   154  
   155  func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
   156  	for _, b := range bs {
   157  		if !chain.HasBlock(b.Hash()) {
   158  			return false
   159  		}
   160  	}
   161  	return true
   162  }
   163  
   164  func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
   165  	args := new(ImportExportChainArgs)
   166  	if err := self.coder.Decode(req.Params, &args); err != nil {
   167  		return nil, shared.NewDecodeParamError(err.Error())
   168  	}
   169  
   170  	fh, err := os.Open(args.Filename)
   171  	if err != nil {
   172  		return false, err
   173  	}
   174  	defer fh.Close()
   175  	stream := rlp.NewStream(fh, 0)
   176  
   177  	// Run actual the import.
   178  	blocks := make(types.Blocks, importBatchSize)
   179  	n := 0
   180  	for batch := 0; ; batch++ {
   181  
   182  		i := 0
   183  		for ; i < importBatchSize; i++ {
   184  			var b types.Block
   185  			if err := stream.Decode(&b); err == io.EOF {
   186  				break
   187  			} else if err != nil {
   188  				return false, fmt.Errorf("at block %d: %v", n, err)
   189  			}
   190  			blocks[i] = &b
   191  			n++
   192  		}
   193  		if i == 0 {
   194  			break
   195  		}
   196  		// Import the batch.
   197  		if hasAllBlocks(self.ethereum.ChainManager(), blocks[:i]) {
   198  			continue
   199  		}
   200  		if _, err := self.ethereum.ChainManager().InsertChain(blocks[:i]); err != nil {
   201  			return false, fmt.Errorf("invalid block %d: %v", n, err)
   202  		}
   203  	}
   204  	return true, nil
   205  }
   206  
   207  func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
   208  	args := new(ImportExportChainArgs)
   209  	if err := self.coder.Decode(req.Params, &args); err != nil {
   210  		return nil, shared.NewDecodeParamError(err.Error())
   211  	}
   212  
   213  	fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   214  	if err != nil {
   215  		return false, err
   216  	}
   217  	defer fh.Close()
   218  	if err := self.ethereum.ChainManager().Export(fh); err != nil {
   219  		return false, err
   220  	}
   221  
   222  	return true, nil
   223  }
   224  
   225  func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
   226  	args := new(VerbosityArgs)
   227  	if err := self.coder.Decode(req.Params, &args); err != nil {
   228  		return nil, shared.NewDecodeParamError(err.Error())
   229  	}
   230  
   231  	glog.SetV(args.Level)
   232  	return true, nil
   233  }
   234  
   235  func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) {
   236  	pending, cached, importing, estimate := self.ethereum.Downloader().Stats()
   237  
   238  	return map[string]interface{}{
   239  		"blocksAvailable":        pending,
   240  		"blocksWaitingForImport": cached,
   241  		"importing":              importing,
   242  		"estimate":               estimate.String(),
   243  	}, nil
   244  }
   245  
   246  func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
   247  	args := new(SetSolcArgs)
   248  	if err := self.coder.Decode(req.Params, &args); err != nil {
   249  		return nil, shared.NewDecodeParamError(err.Error())
   250  	}
   251  
   252  	solc, err := self.xeth.SetSolc(args.Path)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  	return solc.Info(), nil
   257  }
   258  
   259  func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
   260  	args := new(StartRPCArgs)
   261  	if err := self.coder.Decode(req.Params, &args); err != nil {
   262  		return nil, shared.NewDecodeParamError(err.Error())
   263  	}
   264  
   265  	cfg := comms.HttpConfig{
   266  		ListenAddress: args.ListenAddress,
   267  		ListenPort:    args.ListenPort,
   268  		CorsDomain:    args.CorsDomain,
   269  	}
   270  
   271  	apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum)
   272  	if err != nil {
   273  		return false, err
   274  	}
   275  
   276  	err = comms.StartHttp(cfg, self.codec, Merge(apis...))
   277  	if err == nil {
   278  		return true, nil
   279  	}
   280  	return false, err
   281  }
   282  
   283  func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
   284  	comms.StopHttp()
   285  	return true, nil
   286  }
   287  
   288  func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) {
   289  	args := new(SleepBlocksArgs)
   290  	if err := self.coder.Decode(req.Params, &args); err != nil {
   291  		return nil, shared.NewDecodeParamError(err.Error())
   292  	}
   293  	var timer <-chan time.Time
   294  	var height *big.Int
   295  	var err error
   296  	if args.Timeout > 0 {
   297  		timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C
   298  	}
   299  
   300  	height = new(big.Int).Add(self.xeth.CurrentBlock().Number(), big.NewInt(args.N))
   301  	height, err = sleepBlocks(self.xeth.UpdateState(), height, timer)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	return height.Uint64(), nil
   306  }
   307  
   308  func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) {
   309  	wait <- height
   310  	select {
   311  	case <-timer:
   312  		// if times out make sure the xeth loop does not block
   313  		go func() {
   314  			select {
   315  			case wait <- nil:
   316  			case <-wait:
   317  			}
   318  		}()
   319  		return nil, fmt.Errorf("timeout")
   320  	case newHeight = <-wait:
   321  	}
   322  	return
   323  }
   324  
   325  func (self *adminApi) Sleep(req *shared.Request) (interface{}, error) {
   326  	args := new(SleepArgs)
   327  	if err := self.coder.Decode(req.Params, &args); err != nil {
   328  		return nil, shared.NewDecodeParamError(err.Error())
   329  	}
   330  	time.Sleep(time.Duration(args.S) * time.Second)
   331  	return nil, nil
   332  }
   333  
   334  func (self *adminApi) SetGlobalRegistrar(req *shared.Request) (interface{}, error) {
   335  	args := new(SetGlobalRegistrarArgs)
   336  	if err := self.coder.Decode(req.Params, &args); err != nil {
   337  		return nil, shared.NewDecodeParamError(err.Error())
   338  	}
   339  
   340  	sender := common.HexToAddress(args.ContractAddress)
   341  
   342  	reg := registrar.New(self.xeth)
   343  	txhash, err := reg.SetGlobalRegistrar(args.NameReg, sender)
   344  	if err != nil {
   345  		return false, err
   346  	}
   347  
   348  	return txhash, nil
   349  }
   350  
   351  func (self *adminApi) SetHashReg(req *shared.Request) (interface{}, error) {
   352  	args := new(SetHashRegArgs)
   353  	if err := self.coder.Decode(req.Params, &args); err != nil {
   354  		return nil, shared.NewDecodeParamError(err.Error())
   355  	}
   356  
   357  	reg := registrar.New(self.xeth)
   358  	sender := common.HexToAddress(args.Sender)
   359  	txhash, err := reg.SetHashReg(args.HashReg, sender)
   360  	if err != nil {
   361  		return false, err
   362  	}
   363  
   364  	return txhash, nil
   365  }
   366  
   367  func (self *adminApi) SetUrlHint(req *shared.Request) (interface{}, error) {
   368  	args := new(SetUrlHintArgs)
   369  	if err := self.coder.Decode(req.Params, &args); err != nil {
   370  		return nil, shared.NewDecodeParamError(err.Error())
   371  	}
   372  
   373  	urlHint := args.UrlHint
   374  	sender := common.HexToAddress(args.Sender)
   375  
   376  	reg := registrar.New(self.xeth)
   377  	txhash, err := reg.SetUrlHint(urlHint, sender)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  
   382  	return txhash, nil
   383  }
   384  
   385  func (self *adminApi) SaveInfo(req *shared.Request) (interface{}, error) {
   386  	args := new(SaveInfoArgs)
   387  	if err := self.coder.Decode(req.Params, &args); err != nil {
   388  		return nil, shared.NewDecodeParamError(err.Error())
   389  	}
   390  
   391  	contenthash, err := compiler.SaveInfo(&args.ContractInfo, args.Filename)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  
   396  	return contenthash.Hex(), nil
   397  }
   398  
   399  func (self *adminApi) Register(req *shared.Request) (interface{}, error) {
   400  	args := new(RegisterArgs)
   401  	if err := self.coder.Decode(req.Params, &args); err != nil {
   402  		return nil, shared.NewDecodeParamError(err.Error())
   403  	}
   404  
   405  	sender := common.HexToAddress(args.Sender)
   406  	// sender and contract address are passed as hex strings
   407  	codeb := self.xeth.CodeAtBytes(args.Address)
   408  	codeHash := common.BytesToHash(crypto.Sha3(codeb))
   409  	contentHash := common.HexToHash(args.ContentHashHex)
   410  	registry := registrar.New(self.xeth)
   411  
   412  	_, err := registry.SetHashToHash(sender, codeHash, contentHash)
   413  	if err != nil {
   414  		return false, err
   415  	}
   416  
   417  	return true, nil
   418  }
   419  
   420  func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) {
   421  	args := new(RegisterUrlArgs)
   422  	if err := self.coder.Decode(req.Params, &args); err != nil {
   423  		return nil, shared.NewDecodeParamError(err.Error())
   424  	}
   425  
   426  	sender := common.HexToAddress(args.Sender)
   427  	registry := registrar.New(self.xeth)
   428  	_, err := registry.SetUrlToHash(sender, common.HexToHash(args.ContentHash), args.Url)
   429  	if err != nil {
   430  		return false, err
   431  	}
   432  
   433  	return true, nil
   434  }
   435  
   436  func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) {
   437  	self.ethereum.NatSpec = true
   438  	return true, nil
   439  }
   440  
   441  func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) {
   442  	self.ethereum.NatSpec = false
   443  	return true, nil
   444  }
   445  
   446  func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error) {
   447  	args := new(GetContractInfoArgs)
   448  	if err := self.coder.Decode(req.Params, &args); err != nil {
   449  		return nil, shared.NewDecodeParamError(err.Error())
   450  	}
   451  
   452  	infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.ds)
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	var info interface{}
   458  	err = self.coder.Decode(infoDoc, &info)
   459  	if err != nil {
   460  		return nil, err
   461  	}
   462  
   463  	return info, nil
   464  }
   465  
   466  func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) {
   467  	args := new(HttpGetArgs)
   468  	if err := self.coder.Decode(req.Params, &args); err != nil {
   469  		return nil, shared.NewDecodeParamError(err.Error())
   470  	}
   471  
   472  	resp, err := self.ds.Get(args.Uri, args.Path)
   473  	if err != nil {
   474  		return nil, err
   475  	}
   476  
   477  	return string(resp), nil
   478  }
   479  
   480  func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) {
   481  	if fe, ok := self.xeth.Frontend().(*useragent.RemoteFrontend); ok {
   482  		fe.Enable()
   483  	}
   484  	return true, nil
   485  }