Skip to content

Commit

Permalink
core, eth, node, rpc: port the admin and debug API
Browse files Browse the repository at this point in the history
  • Loading branch information
karalabe committed Dec 14, 2015
1 parent fa187a3 commit d8370a4
Show file tree
Hide file tree
Showing 7 changed files with 494 additions and 26 deletions.
2 changes: 1 addition & 1 deletion cmd/gethrpctest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func StartIPC(stack *node.Node) error {
server := rpc.NewServer()

// register package API's this node provides
offered := stack.RPCAPIs()
offered := stack.APIs()
for _, api := range offered {
server.RegisterName(api.Namespace, api.Service)
glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace)
Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ func StartIPC(stack *node.Node, ctx *cli.Context) error {
server := rpc.NewServer()

// register package API's this node provides
offered := stack.RPCAPIs()
offered := stack.APIs()
for _, api := range offered {
server.RegisterName(api.Namespace, api.Service)
glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace)
Expand Down
217 changes: 202 additions & 15 deletions eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
"os"
"sync"
"time"

Expand All @@ -46,7 +48,7 @@ import (

const (
defaultGasPrice = uint64(10000000000000)
defaultGas = uint64(90000)
defaultGas = uint64(90000)
)

// PublicEthereumAPI provides an API to access Ethereum related information.
Expand Down Expand Up @@ -471,12 +473,12 @@ type callmsg struct {

// accessor boilerplate to implement core.Message
func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil }
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
func (m callmsg) To() *common.Address { return m.to }
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
func (m callmsg) Gas() *big.Int { return m.gas }
func (m callmsg) Value() *big.Int { return m.value }
func (m callmsg) Data() []byte { return m.data }
func (m callmsg) Nonce() uint64 { return m.from.Nonce() }
func (m callmsg) To() *common.Address { return m.to }
func (m callmsg) GasPrice() *big.Int { return m.gasPrice }
func (m callmsg) Gas() *big.Int { return m.gas }
func (m callmsg) Value() *big.Int { return m.value }
func (m callmsg) Data() []byte { return m.data }

type CallArgs struct {
From common.Address `json:"from"`
Expand Down Expand Up @@ -972,20 +974,20 @@ func (s *PublicTransactionPoolAPI) Sign(address common.Address, data string) (st
}

type SignTransactionArgs struct {
From common.Address
To common.Address
Nonce *rpc.HexNumber
Value *rpc.HexNumber
Gas *rpc.HexNumber
GasPrice *rpc.HexNumber
Data string
From common.Address
To common.Address
Nonce *rpc.HexNumber
Value *rpc.HexNumber
Gas *rpc.HexNumber
GasPrice *rpc.HexNumber
Data string

BlockNumber int64
}

// Tx is a helper object for argument and return values
type Tx struct {
tx *types.Transaction
tx *types.Transaction

To *common.Address `json:"to"`
From common.Address `json:"from"`
Expand Down Expand Up @@ -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)
}

// 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)
}
13 changes: 13 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,19 @@ func (s *Ethereum) APIs() []rpc.API {
Version: "1.0",
Service: filters.NewPublicFilterAPI(s.ChainDb(), s.EventMux()),
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),
},
}
}
Expand Down
Loading

0 comments on commit d8370a4

Please sign in to comment.