added debug API
This commit is contained in:
		
				
					committed by
					
						
						Bas van Kervel
					
				
			
			
				
	
			
			
			
						parent
						
							faab931ce1
						
					
				
				
					commit
					09d0d55fc5
				
			@@ -4,9 +4,10 @@ import "github.com/ethereum/go-ethereum/rpc/shared"
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// List with all API's which are offered over the IPC interface by default
 | 
			
		||||
	DefaultIpcApis = "eth,miner,net,web3"
 | 
			
		||||
	DefaultIpcApis = "debug,eth,miner,net,web3"
 | 
			
		||||
 | 
			
		||||
	EthApiName    = "eth"
 | 
			
		||||
	DebugApiName  = "debug"
 | 
			
		||||
	MergedApiName = "merged"
 | 
			
		||||
	MinerApiName  = "miner"
 | 
			
		||||
	NetApiName    = "net"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										169
									
								
								rpc/api/debug.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								rpc/api/debug.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/ethash"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/core/state"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/core/vm"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/eth"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rlp"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/codec"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/shared"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/xeth"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	DebugVersion = "1.0.0"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// mapping between methods and handlers
 | 
			
		||||
	DebugMapping = map[string]debughandler{
 | 
			
		||||
		"debug_dumpBlock":    (*DebugApi).DumpBlock,
 | 
			
		||||
		"debug_getBlockRlp":  (*DebugApi).GetBlockRlp,
 | 
			
		||||
		"debug_printBlock":   (*DebugApi).PrintBlock,
 | 
			
		||||
		"debug_processBlock": (*DebugApi).ProcessBlock,
 | 
			
		||||
		"debug_seedHash":     (*DebugApi).SeedHash,
 | 
			
		||||
		"debug_setHead":      (*DebugApi).SetHead,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// debug callback handler
 | 
			
		||||
type debughandler func(*DebugApi, *shared.Request) (interface{}, error)
 | 
			
		||||
 | 
			
		||||
// admin api provider
 | 
			
		||||
type DebugApi struct {
 | 
			
		||||
	xeth     *xeth.XEth
 | 
			
		||||
	ethereum *eth.Ethereum
 | 
			
		||||
	methods  map[string]debughandler
 | 
			
		||||
	codec    codec.ApiCoder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a new debug api instance
 | 
			
		||||
func NewDebugApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *DebugApi {
 | 
			
		||||
	return &DebugApi{
 | 
			
		||||
		xeth:     xeth,
 | 
			
		||||
		ethereum: ethereum,
 | 
			
		||||
		methods:  DebugMapping,
 | 
			
		||||
		codec:    coder.New(nil),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// collection with supported methods
 | 
			
		||||
func (self *DebugApi) Methods() []string {
 | 
			
		||||
	methods := make([]string, len(self.methods))
 | 
			
		||||
	i := 0
 | 
			
		||||
	for k := range self.methods {
 | 
			
		||||
		methods[i] = k
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
	return methods
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Execute given request
 | 
			
		||||
func (self *DebugApi) Execute(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	if callback, ok := self.methods[req.Method]; ok {
 | 
			
		||||
		return callback(self, req)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, &shared.NotImplementedError{req.Method}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) Name() string {
 | 
			
		||||
	return DebugApiName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) PrintBlock(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.xeth.EthBlockByNumber(args.BlockNumber)
 | 
			
		||||
	return fmt.Sprintf("%s", block), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) DumpBlock(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.xeth.EthBlockByNumber(args.BlockNumber)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stateDb := state.New(block.Root(), self.ethereum.StateDb())
 | 
			
		||||
	if stateDb == nil {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return stateDb.Dump(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) GetBlockRlp(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.xeth.EthBlockByNumber(args.BlockNumber)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
			
		||||
	}
 | 
			
		||||
	encoded, err := rlp.EncodeToBytes(block)
 | 
			
		||||
	return fmt.Sprintf("%x", encoded), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) SetHead(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.xeth.EthBlockByNumber(args.BlockNumber)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self.ethereum.ChainManager().SetHead(block)
 | 
			
		||||
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) ProcessBlock(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.xeth.EthBlockByNumber(args.BlockNumber)
 | 
			
		||||
	if block == nil {
 | 
			
		||||
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	old := vm.Debug
 | 
			
		||||
	defer func() { vm.Debug = old }()
 | 
			
		||||
	vm.Debug = true
 | 
			
		||||
 | 
			
		||||
	_, err := self.ethereum.BlockProcessor().RetryProcess(block)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	return false, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *DebugApi) SeedHash(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	args := new(BlockNumArg)
 | 
			
		||||
	if err := self.codec.Decode(req.Params, &args); err != nil {
 | 
			
		||||
		return nil, shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil {
 | 
			
		||||
		return fmt.Sprintf("0x%x", hash), nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								rpc/api/debug_args.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								rpc/api/debug_args.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/big"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/shared"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type WaitForBlockArgs struct {
 | 
			
		||||
	MinHeight int
 | 
			
		||||
	Timeout   int // in seconds
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (args *WaitForBlockArgs) UnmarshalJSON(b []byte) (err error) {
 | 
			
		||||
	var obj []interface{}
 | 
			
		||||
	if err := json.Unmarshal(b, &obj); err != nil {
 | 
			
		||||
		return shared.NewDecodeParamError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(obj) > 2 {
 | 
			
		||||
		return fmt.Errorf("waitForArgs needs 0, 1, 2 arguments")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// default values when not provided
 | 
			
		||||
	args.MinHeight = -1
 | 
			
		||||
	args.Timeout = -1
 | 
			
		||||
 | 
			
		||||
	if len(obj) >= 1 {
 | 
			
		||||
		var minHeight *big.Int
 | 
			
		||||
		if minHeight, err = numString(obj[0]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		args.MinHeight = int(minHeight.Int64())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(obj) >= 2 {
 | 
			
		||||
		timeout, err := numString(obj[1])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		args.Timeout = int(timeout.Int64())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								rpc/api/debug_js.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								rpc/api/debug_js.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
package api
 | 
			
		||||
 | 
			
		||||
const Debug_JS = `
 | 
			
		||||
web3.extend({
 | 
			
		||||
	property: 'debug',
 | 
			
		||||
	methods:
 | 
			
		||||
	[
 | 
			
		||||
		new web3.extend.Method({
 | 
			
		||||
			name: 'printBlock',
 | 
			
		||||
			call: 'debug_printBlock',
 | 
			
		||||
			params: 1,
 | 
			
		||||
			inputFormatter: [web3.extend.formatters.formatInputInt],
 | 
			
		||||
			outputFormatter: web3.extend.formatters.formatOutputString
 | 
			
		||||
		}),
 | 
			
		||||
		new web3.extend.Method({
 | 
			
		||||
			name: 'getBlockRlp',
 | 
			
		||||
			call: 'debug_getBlockRlp',
 | 
			
		||||
			params: 1,
 | 
			
		||||
			inputFormatter: [web3.extend.formatters.formatInputInt],
 | 
			
		||||
			outputFormatter: web3.extend.formatters.formatOutputString
 | 
			
		||||
		}),
 | 
			
		||||
		new web3.extend.Method({
 | 
			
		||||
			name: 'setHead',
 | 
			
		||||
			call: 'debug_setHead',
 | 
			
		||||
			params: 1,
 | 
			
		||||
			inputFormatter: [web3.extend.formatters.formatInputInt],
 | 
			
		||||
			outputFormatter: web3.extend.formatters.formatOutputBool
 | 
			
		||||
		}),
 | 
			
		||||
		new web3.extend.Method({
 | 
			
		||||
			name: 'processBlock',
 | 
			
		||||
			call: 'debug_processBlock',
 | 
			
		||||
			params: 1,
 | 
			
		||||
			inputFormatter: [web3.extend.formatters.formatInputInt],
 | 
			
		||||
			outputFormatter: function(obj) { return obj; }
 | 
			
		||||
		}),
 | 
			
		||||
		new web3.extend.Method({
 | 
			
		||||
			name: 'seedHash',
 | 
			
		||||
			call: 'debug_seedHash',
 | 
			
		||||
			params: 1,
 | 
			
		||||
			inputFormatter: [web3.extend.formatters.formatInputInt],
 | 
			
		||||
			outputFormatter: web3.extend.formatters.formatOutputString
 | 
			
		||||
		})
 | 
			
		||||
	],
 | 
			
		||||
	properties:
 | 
			
		||||
	[
 | 
			
		||||
	]
 | 
			
		||||
});
 | 
			
		||||
`
 | 
			
		||||
@@ -21,6 +21,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
 | 
			
		||||
 | 
			
		||||
	for i, name := range names {
 | 
			
		||||
		switch strings.ToLower(strings.TrimSpace(name)) {
 | 
			
		||||
		case DebugApiName:
 | 
			
		||||
			apis[i] = NewDebugApi(xeth, eth, codec)
 | 
			
		||||
		case EthApiName:
 | 
			
		||||
			apis[i] = NewEthApi(xeth, codec)
 | 
			
		||||
		case MinerApiName:
 | 
			
		||||
@@ -39,6 +41,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
 | 
			
		||||
 | 
			
		||||
func Javascript(name string) string {
 | 
			
		||||
	switch strings.ToLower(strings.TrimSpace(name)) {
 | 
			
		||||
	case DebugApiName:
 | 
			
		||||
		return Debug_JS
 | 
			
		||||
	case MinerApiName:
 | 
			
		||||
		return Miner_JS
 | 
			
		||||
	case NetApiName:
 | 
			
		||||
 
 | 
			
		||||
@@ -135,7 +135,6 @@ func getOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped,
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// openMode
 | 
			
		||||
	pipe_access_duplex   = 0x3
 | 
			
		||||
@@ -636,8 +635,6 @@ func timeout(addr string) PipeError {
 | 
			
		||||
	return PipeError{fmt.Sprintf("Pipe IO timed out waiting for '%s'", addr), true}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
 | 
			
		||||
	c, err := Dial(cfg.Endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								rpc/jeth.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								rpc/jeth.go
									
									
									
									
									
								
							@@ -4,12 +4,13 @@ import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/go-ethereum/jsre"
 | 
			
		||||
	"github.com/robertkrimen/otto"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/comms"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/codec"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/shared"
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/go-ethereum/jsre"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/codec"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/comms"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/shared"
 | 
			
		||||
	"github.com/robertkrimen/otto"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Jeth struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package shared
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
 | 
			
		||||
	"github.com/ethereum/go-ethereum/logger"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/logger/glog"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user