| 
									
										
										
										
											2015-06-09 16:06:51 +02: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" | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc/comms" | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rpc/shared" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/xeth" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-06-10 09:42:14 +02:00
										 |  |  | 	AdminApiversion = "1.0" | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	importBatchSize = 2500 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	// mapping between methods and handlers | 
					
						
							|  |  |  | 	AdminMapping = map[string]adminhandler{ | 
					
						
							| 
									
										
										
										
											2015-06-10 11:29:52 +02: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-22 12:47:32 +02:00
										 |  |  | 		"admin_startRPC":        (*adminApi).StartRPC, | 
					
						
							|  |  |  | 		"admin_stopRPC":         (*adminApi).StopRPC, | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // admin callback handler | 
					
						
							|  |  |  | type adminhandler func(*adminApi, *shared.Request) (interface{}, error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // admin api provider | 
					
						
							|  |  |  | type adminApi struct { | 
					
						
							|  |  |  | 	xeth     *xeth.XEth | 
					
						
							|  |  |  | 	ethereum *eth.Ethereum | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	codec    codec.Codec | 
					
						
							|  |  |  | 	coder    codec.ApiCoder | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // create a new admin api instance | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	return &adminApi{ | 
					
						
							|  |  |  | 		xeth:     xeth, | 
					
						
							|  |  |  | 		ethereum: ethereum, | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 		codec:    codec, | 
					
						
							|  |  |  | 		coder:    codec.New(nil), | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // collection with supported methods | 
					
						
							|  |  |  | func (self *adminApi) Methods() []string { | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	methods := make([]string, len(AdminMapping)) | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 	i := 0 | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	for k := range AdminMapping { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		methods[i] = k | 
					
						
							|  |  |  | 		i++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return methods | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Execute given request | 
					
						
							|  |  |  | func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if callback, ok := AdminMapping[req.Method]; ok { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		return callback(self, req) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, &shared.NotImplementedError{req.Method} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *adminApi) Name() string { | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	return shared.AdminApiName | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 09:42:14 +02:00
										 |  |  | func (self *adminApi) ApiVersion() string { | 
					
						
							|  |  |  | 	return AdminApiversion | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { | 
					
						
							|  |  |  | 	args := new(AddPeerArgs) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err := self.coder.Decode(req.Params, &args); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		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 11:29:52 +02:00
										 |  |  | func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { | 
					
						
							|  |  |  | 	return self.ethereum.DataDir, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02: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) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err := self.coder.Decode(req.Params, &args); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err := self.coder.Decode(req.Params, &args); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err := self.coder.Decode(req.Params, &args); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		return nil, shared.NewDecodeParamError(err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	glog.SetV(args.Level) | 
					
						
							|  |  |  | 	return true, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 11:29:52 +02:00
										 |  |  | func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2015-06-10 09:42:14 +02:00
										 |  |  | 	pending, cached, importing, estimate := self.ethereum.Downloader().Stats() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2015-06-16 14:59:39 +02:00
										 |  |  | 		"blocksAvailable":        pending, | 
					
						
							| 
									
										
										
										
											2015-06-10 09:42:14 +02:00
										 |  |  | 		"blocksWaitingForImport": cached, | 
					
						
							| 
									
										
										
										
											2015-06-16 14:59:39 +02:00
										 |  |  | 		"importing":              importing, | 
					
						
							|  |  |  | 		"estimate":               estimate.String(), | 
					
						
							| 
									
										
										
										
											2015-06-10 09:42:14 +02:00
										 |  |  | 	}, nil | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { | 
					
						
							|  |  |  | 	args := new(SetSolcArgs) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err := self.coder.Decode(req.Params, &args); err != nil { | 
					
						
							| 
									
										
										
										
											2015-06-09 16:06:51 +02:00
										 |  |  | 		return nil, shared.NewDecodeParamError(err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	solc, err := self.xeth.SetSolc(args.Path) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return solc.Info(), nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 08:26:17 +02:00
										 |  |  | 	apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return false, err | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 08:26:17 +02:00
										 |  |  | 	err = comms.StartHttp(cfg, self.codec, Merge(apis...)) | 
					
						
							| 
									
										
										
										
											2015-06-22 12:47:32 +02:00
										 |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		return true, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) { | 
					
						
							|  |  |  | 	comms.StopHttp() | 
					
						
							|  |  |  | 	return true, nil | 
					
						
							|  |  |  | } |