core, eth, node, rpc: port the admin and debug API
This commit is contained in:
		
							parent
							
								
									fa187a366d
								
							
						
					
					
						commit
						d8370a4e15
					
				| @ -214,7 +214,7 @@ func StartIPC(stack *node.Node) error { | |||||||
| 	server := rpc.NewServer() | 	server := rpc.NewServer() | ||||||
| 
 | 
 | ||||||
| 	// register package API's this node provides
 | 	// register package API's this node provides
 | ||||||
| 	offered := stack.RPCAPIs() | 	offered := stack.APIs() | ||||||
| 	for _, api := range offered { | 	for _, api := range offered { | ||||||
| 		server.RegisterName(api.Namespace, api.Service) | 		server.RegisterName(api.Namespace, api.Service) | ||||||
| 		glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace) | 		glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace) | ||||||
|  | |||||||
| @ -798,7 +798,7 @@ func StartIPC(stack *node.Node, ctx *cli.Context) error { | |||||||
| 		server := rpc.NewServer() | 		server := rpc.NewServer() | ||||||
| 
 | 
 | ||||||
| 		// register package API's this node provides
 | 		// register package API's this node provides
 | ||||||
| 		offered := stack.RPCAPIs() | 		offered := stack.APIs() | ||||||
| 		for _, api := range offered { | 		for _, api := range offered { | ||||||
| 			server.RegisterName(api.Namespace, api.Service) | 			server.RegisterName(api.Namespace, api.Service) | ||||||
| 			glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) | 			glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) | ||||||
|  | |||||||
							
								
								
									
										217
									
								
								eth/api.go
									
									
									
									
									
								
							
							
						
						
									
										217
									
								
								eth/api.go
									
									
									
									
									
								
							| @ -21,7 +21,9 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"math/big" | 	"math/big" | ||||||
|  | 	"os" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| @ -46,7 +48,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	defaultGasPrice = uint64(10000000000000) | 	defaultGasPrice = uint64(10000000000000) | ||||||
| 	defaultGas = uint64(90000) | 	defaultGas      = uint64(90000) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // PublicEthereumAPI provides an API to access Ethereum related information.
 | // PublicEthereumAPI provides an API to access Ethereum related information.
 | ||||||
| @ -471,12 +473,12 @@ type callmsg struct { | |||||||
| 
 | 
 | ||||||
| // accessor boilerplate to implement core.Message
 | // accessor boilerplate to implement core.Message
 | ||||||
| func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } | func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } | ||||||
| func (m callmsg) Nonce() uint64 { return m.from.Nonce() } | func (m callmsg) Nonce() uint64                 { return m.from.Nonce() } | ||||||
| func (m callmsg) To() *common.Address { return m.to } | func (m callmsg) To() *common.Address           { return m.to } | ||||||
| func (m callmsg) GasPrice() *big.Int { return m.gasPrice } | func (m callmsg) GasPrice() *big.Int            { return m.gasPrice } | ||||||
| func (m callmsg) Gas() *big.Int { return m.gas } | func (m callmsg) Gas() *big.Int                 { return m.gas } | ||||||
| func (m callmsg) Value() *big.Int { return m.value } | func (m callmsg) Value() *big.Int               { return m.value } | ||||||
| func (m callmsg) Data() []byte { return m.data } | func (m callmsg) Data() []byte                  { return m.data } | ||||||
| 
 | 
 | ||||||
| type CallArgs struct { | type CallArgs struct { | ||||||
| 	From     common.Address `json:"from"` | 	From     common.Address `json:"from"` | ||||||
| @ -972,20 +974,20 @@ func (s *PublicTransactionPoolAPI) Sign(address common.Address, data string) (st | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type SignTransactionArgs struct { | type SignTransactionArgs struct { | ||||||
| 	From        common.Address | 	From     common.Address | ||||||
| 	To          common.Address | 	To       common.Address | ||||||
| 	Nonce       *rpc.HexNumber | 	Nonce    *rpc.HexNumber | ||||||
| 	Value       *rpc.HexNumber | 	Value    *rpc.HexNumber | ||||||
| 	Gas         *rpc.HexNumber | 	Gas      *rpc.HexNumber | ||||||
| 	GasPrice    *rpc.HexNumber | 	GasPrice *rpc.HexNumber | ||||||
| 	Data        string | 	Data     string | ||||||
| 
 | 
 | ||||||
| 	BlockNumber int64 | 	BlockNumber int64 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Tx is a helper object for argument and return values
 | // Tx is a helper object for argument and return values
 | ||||||
| type Tx struct { | type Tx struct { | ||||||
| 	tx       *types.Transaction | 	tx *types.Transaction | ||||||
| 
 | 
 | ||||||
| 	To       *common.Address `json:"to"` | 	To       *common.Address `json:"to"` | ||||||
| 	From     common.Address  `json:"from"` | 	From     common.Address  `json:"from"` | ||||||
| @ -1214,3 +1216,188 @@ func (s *PublicTransactionPoolAPI) Resend(tx *Tx, gasPrice, gasLimit *rpc.HexNum | |||||||
| 
 | 
 | ||||||
| 	return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) | 	return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // PrivateAdminAPI is the collection of Etheruem APIs exposed over the private
 | ||||||
|  | // admin endpoint.
 | ||||||
|  | type PrivateAdminAPI struct { | ||||||
|  | 	eth *Ethereum | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPrivateAdminAPI creates a new API definition for the private admin methods
 | ||||||
|  | // of the Ethereum service.
 | ||||||
|  | func NewPrivateAdminAPI(eth *Ethereum) *PrivateAdminAPI { | ||||||
|  | 	return &PrivateAdminAPI{eth: eth} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetSolc sets the Solidity compiler path to be used by the node.
 | ||||||
|  | func (api *PrivateAdminAPI) SetSolc(path string) (string, error) { | ||||||
|  | 	solc, err := api.eth.SetSolc(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	return solc.Info(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ExportChain exports the current blockchain into a local file.
 | ||||||
|  | func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) { | ||||||
|  | 	// Make sure we can create the file to export into
 | ||||||
|  | 	out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	defer out.Close() | ||||||
|  | 
 | ||||||
|  | 	// Export the blockchain
 | ||||||
|  | 	if err := api.eth.BlockChain().Export(out); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ImportChain imports a blockchain from a local file.
 | ||||||
|  | func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { | ||||||
|  | 	// Make sure the can access the file to import
 | ||||||
|  | 	in, err := os.Open(file) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	defer in.Close() | ||||||
|  | 
 | ||||||
|  | 	// Run actual the import in pre-configured batches
 | ||||||
|  | 	stream := rlp.NewStream(in, 0) | ||||||
|  | 
 | ||||||
|  | 	blocks, index := make([]*types.Block, 0, 2500), 0 | ||||||
|  | 	for batch := 0; ; batch++ { | ||||||
|  | 		// Load a batch of blocks from the input file
 | ||||||
|  | 		for len(blocks) < cap(blocks) { | ||||||
|  | 			block := new(types.Block) | ||||||
|  | 			if err := stream.Decode(block); err == io.EOF { | ||||||
|  | 				break | ||||||
|  | 			} else if err != nil { | ||||||
|  | 				return false, fmt.Errorf("block %d: failed to parse: %v", index, err) | ||||||
|  | 			} | ||||||
|  | 			blocks = append(blocks, block) | ||||||
|  | 			index++ | ||||||
|  | 		} | ||||||
|  | 		if len(blocks) == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		// Import the batch and reset the buffer
 | ||||||
|  | 		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { | ||||||
|  | 			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) | ||||||
|  | 		} | ||||||
|  | 		blocks = blocks[:0] | ||||||
|  | 	} | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PublicDebugAPI is the collection of Etheruem APIs exposed over the public
 | ||||||
|  | // debugging endpoint.
 | ||||||
|  | type PublicDebugAPI struct { | ||||||
|  | 	eth *Ethereum | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPublicDebugAPI creates a new API definition for the public debug methods
 | ||||||
|  | // of the Ethereum service.
 | ||||||
|  | func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI { | ||||||
|  | 	return &PublicDebugAPI{eth: eth} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DumpBlock retrieves the entire state of the database at a given block.
 | ||||||
|  | func (api *PublicDebugAPI) DumpBlock(number uint64) (state.World, error) { | ||||||
|  | 	block := api.eth.BlockChain().GetBlockByNumber(number) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return state.World{}, fmt.Errorf("block #%d not found", number) | ||||||
|  | 	} | ||||||
|  | 	stateDb, err := state.New(block.Root(), api.eth.ChainDb()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return state.World{}, err | ||||||
|  | 	} | ||||||
|  | 	return stateDb.RawDump(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetBlockRlp retrieves the RLP encoded for of a single block.
 | ||||||
|  | func (api *PublicDebugAPI) GetBlockRlp(number uint64) (string, error) { | ||||||
|  | 	block := api.eth.BlockChain().GetBlockByNumber(number) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return "", fmt.Errorf("block #%d not found", number) | ||||||
|  | 	} | ||||||
|  | 	encoded, err := rlp.EncodeToBytes(block) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%x", encoded), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PrintBlock retrieves a block and returns its pretty printed form.
 | ||||||
|  | func (api *PublicDebugAPI) PrintBlock(number uint64) (string, error) { | ||||||
|  | 	block := api.eth.BlockChain().GetBlockByNumber(number) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return "", fmt.Errorf("block #%d not found", number) | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("%s", block), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SeedHash retrieves the seed hash of a block.
 | ||||||
|  | func (api *PublicDebugAPI) SeedHash(number uint64) (string, error) { | ||||||
|  | 	block := api.eth.BlockChain().GetBlockByNumber(number) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return "", fmt.Errorf("block #%d not found", number) | ||||||
|  | 	} | ||||||
|  | 	hash, err := ethash.GetSeedHash(number) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("0x%x", hash), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PrivateDebugAPI is the collection of Etheruem APIs exposed over the private
 | ||||||
|  | // debugging endpoint.
 | ||||||
|  | type PrivateDebugAPI struct { | ||||||
|  | 	eth *Ethereum | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPrivateDebugAPI creates a new API definition for the private debug methods
 | ||||||
|  | // of the Ethereum service.
 | ||||||
|  | func NewPrivateDebugAPI(eth *Ethereum) *PrivateDebugAPI { | ||||||
|  | 	return &PrivateDebugAPI{eth: eth} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ProcessBlock reprocesses an already owned block.
 | ||||||
|  | func (api *PrivateDebugAPI) ProcessBlock(number uint64) (bool, error) { | ||||||
|  | 	// Fetch the block that we aim to reprocess
 | ||||||
|  | 	block := api.eth.BlockChain().GetBlockByNumber(number) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return false, fmt.Errorf("block #%d not found", number) | ||||||
|  | 	} | ||||||
|  | 	// Temporarily enable debugging
 | ||||||
|  | 	defer func(old bool) { vm.Debug = old }(vm.Debug) | ||||||
|  | 	vm.Debug = true | ||||||
|  | 
 | ||||||
|  | 	// Validate and reprocess the block
 | ||||||
|  | 	var ( | ||||||
|  | 		blockchain = api.eth.BlockChain() | ||||||
|  | 		validator  = blockchain.Validator() | ||||||
|  | 		processor  = blockchain.Processor() | ||||||
|  | 	) | ||||||
|  | 	if err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), api.eth.ChainDb()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	receipts, _, usedGas, err := processor.Process(block, statedb) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	if err := validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetHead rewinds the head of the blockchain to a previous block.
 | ||||||
|  | func (api *PrivateDebugAPI) SetHead(number uint64) { | ||||||
|  | 	api.eth.BlockChain().SetHead(number) | ||||||
|  | } | ||||||
|  | |||||||
| @ -295,6 +295,19 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   filters.NewPublicFilterAPI(s.ChainDb(), s.EventMux()), | 			Service:   filters.NewPublicFilterAPI(s.ChainDb(), s.EventMux()), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "admin", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPrivateAdminAPI(s), | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "debug", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPublicDebugAPI(s), | ||||||
|  | 			Public:    true, | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "debug", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPrivateDebugAPI(s), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										244
									
								
								node/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								node/api.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,244 @@ | |||||||
|  | // Copyright 2015 The go-ethereum Authors
 | ||||||
|  | // This file is part of the go-ethereum library.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU Lesser General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License
 | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package node | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p/discover" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rpc/comms" | ||||||
|  | 	"github.com/rcrowley/go-metrics" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // PrivateAdminAPI is the collection of administrative API methods exposed only
 | ||||||
|  | // over a secure RPC channel.
 | ||||||
|  | type PrivateAdminAPI struct { | ||||||
|  | 	node *Node // Node interfaced by this API
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPrivateAdminAPI creates a new API definition for the private admin methods
 | ||||||
|  | // of the node itself.
 | ||||||
|  | func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI { | ||||||
|  | 	return &PrivateAdminAPI{node: node} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // AddPeer requests connecting to a remote node, and also maintaining the new
 | ||||||
|  | // connection at all times, even reconnecting if it is lost.
 | ||||||
|  | func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { | ||||||
|  | 	// Make sure the server is running, fail otherwise
 | ||||||
|  | 	server := api.node.Server() | ||||||
|  | 	if server == nil { | ||||||
|  | 		return false, ErrNodeStopped | ||||||
|  | 	} | ||||||
|  | 	// Try to add the url as a static peer and return
 | ||||||
|  | 	node, err := discover.ParseNode(url) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, fmt.Errorf("invalid enode: %v", err) | ||||||
|  | 	} | ||||||
|  | 	server.AddPeer(node) | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // StartRPC starts the HTTP RPC API server.
 | ||||||
|  | func (api *PrivateAdminAPI) StartRPC(address string, port int, cors string, apis string) (bool, error) { | ||||||
|  | 	/*// Parse the list of API modules to make available
 | ||||||
|  | 	apis, err := api.ParseApiString(apis, codec.JSON, xeth.New(api.node, nil), api.node) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	// Configure and start the HTTP RPC server
 | ||||||
|  | 	config := comms.HttpConfig{ | ||||||
|  | 		ListenAddress: address, | ||||||
|  | 		ListenPort:    port, | ||||||
|  | 		CorsDomain:    cors, | ||||||
|  | 	} | ||||||
|  | 	if err := comms.StartHttp(config, self.codec, api.Merge(apis...)); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  | 	return true, nil*/ | ||||||
|  | 	return false, fmt.Errorf("needs new RPC implementation to resolve circular dependency") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // StopRPC terminates an already running HTTP RPC API endpoint.
 | ||||||
|  | func (api *PrivateAdminAPI) StopRPC() { | ||||||
|  | 	comms.StopHttp() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PublicAdminAPI is the collection of administrative API methods exposed over
 | ||||||
|  | // both secure and unsecure RPC channels.
 | ||||||
|  | type PublicAdminAPI struct { | ||||||
|  | 	node *Node // Node interfaced by this API
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPublicAdminAPI creates a new API definition for the public admin methods
 | ||||||
|  | // of the node itself.
 | ||||||
|  | func NewPublicAdminAPI(node *Node) *PublicAdminAPI { | ||||||
|  | 	return &PublicAdminAPI{node: node} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Peers retrieves all the information we know about each individual peer at the
 | ||||||
|  | // protocol granularity.
 | ||||||
|  | func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { | ||||||
|  | 	server := api.node.Server() | ||||||
|  | 	if server == nil { | ||||||
|  | 		return nil, ErrNodeStopped | ||||||
|  | 	} | ||||||
|  | 	return server.PeersInfo(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NodeInfo retrieves all the information we know about the host node at the
 | ||||||
|  | // protocol granularity.
 | ||||||
|  | func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { | ||||||
|  | 	server := api.node.Server() | ||||||
|  | 	if server == nil { | ||||||
|  | 		return nil, ErrNodeStopped | ||||||
|  | 	} | ||||||
|  | 	return server.NodeInfo(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Datadir retrieves the current data directory the node is using.
 | ||||||
|  | func (api *PublicAdminAPI) Datadir() string { | ||||||
|  | 	return api.node.DataDir() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PrivateDebugAPI is the collection of debugging related API methods exposed
 | ||||||
|  | // only over a secure RPC channel.
 | ||||||
|  | type PrivateDebugAPI struct { | ||||||
|  | 	node *Node // Node interfaced by this API
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPrivateDebugAPI creates a new API definition for the private debug methods
 | ||||||
|  | // of the node itself.
 | ||||||
|  | func NewPrivateDebugAPI(node *Node) *PrivateDebugAPI { | ||||||
|  | 	return &PrivateDebugAPI{node: node} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Verbosity updates the node's logging verbosity. Note, due to the lack of fine
 | ||||||
|  | // grained contextual loggers, this will update the verbosity level for the entire
 | ||||||
|  | // process, not just this node instance.
 | ||||||
|  | func (api *PrivateDebugAPI) Verbosity(level int) { | ||||||
|  | 	glog.SetV(level) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PublicDebugAPI is the collection of debugging related API methods exposed over
 | ||||||
|  | // both secure and unsecure RPC channels.
 | ||||||
|  | type PublicDebugAPI struct { | ||||||
|  | 	node *Node // Node interfaced by this API
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewPublicDebugAPI creates a new API definition for the public debug methods
 | ||||||
|  | // of the node itself.
 | ||||||
|  | func NewPublicDebugAPI(node *Node) *PublicDebugAPI { | ||||||
|  | 	return &PublicDebugAPI{node: node} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Metrics retrieves all the known system metric collected by the node.
 | ||||||
|  | func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { | ||||||
|  | 	// Create a rate formatter
 | ||||||
|  | 	units := []string{"", "K", "M", "G", "T", "E", "P"} | ||||||
|  | 	round := func(value float64, prec int) string { | ||||||
|  | 		unit := 0 | ||||||
|  | 		for value >= 1000 { | ||||||
|  | 			unit, value, prec = unit+1, value/1000, 2 | ||||||
|  | 		} | ||||||
|  | 		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) | ||||||
|  | 	} | ||||||
|  | 	format := func(total float64, rate float64) string { | ||||||
|  | 		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) | ||||||
|  | 	} | ||||||
|  | 	// Iterate over all the metrics, and just dump for now
 | ||||||
|  | 	counters := make(map[string]interface{}) | ||||||
|  | 	metrics.DefaultRegistry.Each(func(name string, metric interface{}) { | ||||||
|  | 		// Create or retrieve the counter hierarchy for this metric
 | ||||||
|  | 		root, parts := counters, strings.Split(name, "/") | ||||||
|  | 		for _, part := range parts[:len(parts)-1] { | ||||||
|  | 			if _, ok := root[part]; !ok { | ||||||
|  | 				root[part] = make(map[string]interface{}) | ||||||
|  | 			} | ||||||
|  | 			root = root[part].(map[string]interface{}) | ||||||
|  | 		} | ||||||
|  | 		name = parts[len(parts)-1] | ||||||
|  | 
 | ||||||
|  | 		// Fill the counter with the metric details, formatting if requested
 | ||||||
|  | 		if raw { | ||||||
|  | 			switch metric := metric.(type) { | ||||||
|  | 			case metrics.Meter: | ||||||
|  | 				root[name] = map[string]interface{}{ | ||||||
|  | 					"AvgRate01Min": metric.Rate1(), | ||||||
|  | 					"AvgRate05Min": metric.Rate5(), | ||||||
|  | 					"AvgRate15Min": metric.Rate15(), | ||||||
|  | 					"MeanRate":     metric.RateMean(), | ||||||
|  | 					"Overall":      float64(metric.Count()), | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			case metrics.Timer: | ||||||
|  | 				root[name] = map[string]interface{}{ | ||||||
|  | 					"AvgRate01Min": metric.Rate1(), | ||||||
|  | 					"AvgRate05Min": metric.Rate5(), | ||||||
|  | 					"AvgRate15Min": metric.Rate15(), | ||||||
|  | 					"MeanRate":     metric.RateMean(), | ||||||
|  | 					"Overall":      float64(metric.Count()), | ||||||
|  | 					"Percentiles": map[string]interface{}{ | ||||||
|  | 						"5":  metric.Percentile(0.05), | ||||||
|  | 						"20": metric.Percentile(0.2), | ||||||
|  | 						"50": metric.Percentile(0.5), | ||||||
|  | 						"80": metric.Percentile(0.8), | ||||||
|  | 						"95": metric.Percentile(0.95), | ||||||
|  | 					}, | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			default: | ||||||
|  | 				root[name] = "Unknown metric type" | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			switch metric := metric.(type) { | ||||||
|  | 			case metrics.Meter: | ||||||
|  | 				root[name] = map[string]interface{}{ | ||||||
|  | 					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()), | ||||||
|  | 					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()), | ||||||
|  | 					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()), | ||||||
|  | 					"Overall":  format(float64(metric.Count()), metric.RateMean()), | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			case metrics.Timer: | ||||||
|  | 				root[name] = map[string]interface{}{ | ||||||
|  | 					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()), | ||||||
|  | 					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()), | ||||||
|  | 					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()), | ||||||
|  | 					"Overall":  format(float64(metric.Count()), metric.RateMean()), | ||||||
|  | 					"Maximum":  time.Duration(metric.Max()).String(), | ||||||
|  | 					"Minimum":  time.Duration(metric.Min()).String(), | ||||||
|  | 					"Percentiles": map[string]interface{}{ | ||||||
|  | 						"5":  time.Duration(metric.Percentile(0.05)).String(), | ||||||
|  | 						"20": time.Duration(metric.Percentile(0.2)).String(), | ||||||
|  | 						"50": time.Duration(metric.Percentile(0.5)).String(), | ||||||
|  | 						"80": time.Duration(metric.Percentile(0.8)).String(), | ||||||
|  | 						"95": time.Duration(metric.Percentile(0.95)).String(), | ||||||
|  | 					}, | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			default: | ||||||
|  | 				root[name] = "Unknown metric type" | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	return counters, nil | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								node/node.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								node/node.go
									
									
									
									
									
								
							| @ -266,9 +266,33 @@ func (n *Node) EventMux() *event.TypeMux { | |||||||
| 	return n.eventmux | 	return n.eventmux | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RPCAPIs returns the collection of RPC descriptor this node offers
 | // APIs returns the collection of RPC descriptor this node offers. This method
 | ||||||
| func (n *Node) RPCAPIs() []rpc.API { | // is just a quick placeholder passthrough for the RPC update, which in the next
 | ||||||
| 	var apis []rpc.API | // step will be fully integrated into the node itself.
 | ||||||
|  | func (n *Node) APIs() []rpc.API { | ||||||
|  | 	// Define all the APIs owned by the node itself
 | ||||||
|  | 	apis := []rpc.API{ | ||||||
|  | 		{ | ||||||
|  | 			Namespace: "admin", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPrivateAdminAPI(n), | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "admin", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPublicAdminAPI(n), | ||||||
|  | 			Public:    true, | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "debug", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPrivateDebugAPI(n), | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "debug", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPublicDebugAPI(n), | ||||||
|  | 			Public:    true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	// Inject all the APIs owned by various services
 | ||||||
| 	for _, api := range n.services { | 	for _, api := range n.services { | ||||||
| 		apis = append(apis, api.APIs()...) | 		apis = append(apis, api.APIs()...) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -25,37 +25,37 @@ web3._extend({ | |||||||
| 			name: 'printBlock', | 			name: 'printBlock', | ||||||
| 			call: 'debug_printBlock', | 			call: 'debug_printBlock', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'getBlockRlp', | 			name: 'getBlockRlp', | ||||||
| 			call: 'debug_getBlockRlp', | 			call: 'debug_getBlockRlp', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'setHead', | 			name: 'setHead', | ||||||
| 			call: 'debug_setHead', | 			call: 'debug_setHead', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'processBlock', | 			name: 'processBlock', | ||||||
| 			call: 'debug_processBlock', | 			call: 'debug_processBlock', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'seedHash', | 			name: 'seedHash', | ||||||
| 			call: 'debug_seedHash', | 			call: 'debug_seedHash', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'dumpBlock', | 			name: 'dumpBlock', | ||||||
| 			call: 'debug_dumpBlock', | 			call: 'debug_dumpBlock', | ||||||
| 			params: 1, | 			params: 1, | ||||||
| 			inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] | 			inputFormatter: [null] | ||||||
| 		}), | 		}), | ||||||
| 		new web3._extend.Method({ | 		new web3._extend.Method({ | ||||||
| 			name: 'metrics', | 			name: 'metrics', | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user