github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/api/debug.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  	"strings"
    22  	"time"
    23  
    24  	"github.com/ethereum/ethash"
    25  	"github.com/ethereum/go-ethereum/core/state"
    26  	"github.com/ethereum/go-ethereum/core/vm"
    27  	"github.com/ethereum/go-ethereum/eth"
    28  	"github.com/ethereum/go-ethereum/rlp"
    29  	"github.com/ethereum/go-ethereum/rpc/codec"
    30  	"github.com/ethereum/go-ethereum/rpc/shared"
    31  	"github.com/ethereum/go-ethereum/xeth"
    32  	"github.com/rcrowley/go-metrics"
    33  )
    34  
    35  const (
    36  	DebugApiVersion = "1.0"
    37  )
    38  
    39  var (
    40  	// mapping between methods and handlers
    41  	DebugMapping = map[string]debughandler{
    42  		"debug_dumpBlock":    (*debugApi).DumpBlock,
    43  		"debug_getBlockRlp":  (*debugApi).GetBlockRlp,
    44  		"debug_printBlock":   (*debugApi).PrintBlock,
    45  		"debug_processBlock": (*debugApi).ProcessBlock,
    46  		"debug_seedHash":     (*debugApi).SeedHash,
    47  		"debug_setHead":      (*debugApi).SetHead,
    48  		"debug_metrics":      (*debugApi).Metrics,
    49  	}
    50  )
    51  
    52  // debug callback handler
    53  type debughandler func(*debugApi, *shared.Request) (interface{}, error)
    54  
    55  // admin api provider
    56  type debugApi struct {
    57  	xeth     *xeth.XEth
    58  	ethereum *eth.Ethereum
    59  	methods  map[string]debughandler
    60  	codec    codec.ApiCoder
    61  }
    62  
    63  // create a new debug api instance
    64  func NewDebugApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *debugApi {
    65  	return &debugApi{
    66  		xeth:     xeth,
    67  		ethereum: ethereum,
    68  		methods:  DebugMapping,
    69  		codec:    coder.New(nil),
    70  	}
    71  }
    72  
    73  // collection with supported methods
    74  func (self *debugApi) Methods() []string {
    75  	methods := make([]string, len(self.methods))
    76  	i := 0
    77  	for k := range self.methods {
    78  		methods[i] = k
    79  		i++
    80  	}
    81  	return methods
    82  }
    83  
    84  // Execute given request
    85  func (self *debugApi) Execute(req *shared.Request) (interface{}, error) {
    86  	if callback, ok := self.methods[req.Method]; ok {
    87  		return callback(self, req)
    88  	}
    89  
    90  	return nil, &shared.NotImplementedError{req.Method}
    91  }
    92  
    93  func (self *debugApi) Name() string {
    94  	return shared.DebugApiName
    95  }
    96  
    97  func (self *debugApi) ApiVersion() string {
    98  	return DebugApiVersion
    99  }
   100  
   101  func (self *debugApi) PrintBlock(req *shared.Request) (interface{}, error) {
   102  	args := new(BlockNumArg)
   103  	if err := self.codec.Decode(req.Params, &args); err != nil {
   104  		return nil, shared.NewDecodeParamError(err.Error())
   105  	}
   106  
   107  	block := self.xeth.EthBlockByNumber(args.BlockNumber)
   108  	return fmt.Sprintf("%s", block), nil
   109  }
   110  
   111  func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) {
   112  	args := new(BlockNumArg)
   113  	if err := self.codec.Decode(req.Params, &args); err != nil {
   114  		return nil, shared.NewDecodeParamError(err.Error())
   115  	}
   116  
   117  	block := self.xeth.EthBlockByNumber(args.BlockNumber)
   118  	if block == nil {
   119  		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
   120  	}
   121  
   122  	stateDb := state.New(block.Root(), self.ethereum.ChainDb())
   123  	if stateDb == nil {
   124  		return nil, nil
   125  	}
   126  
   127  	return stateDb.RawDump(), nil
   128  }
   129  
   130  func (self *debugApi) GetBlockRlp(req *shared.Request) (interface{}, error) {
   131  	args := new(BlockNumArg)
   132  	if err := self.codec.Decode(req.Params, &args); err != nil {
   133  		return nil, shared.NewDecodeParamError(err.Error())
   134  	}
   135  
   136  	block := self.xeth.EthBlockByNumber(args.BlockNumber)
   137  	if block == nil {
   138  		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
   139  	}
   140  	encoded, err := rlp.EncodeToBytes(block)
   141  	return fmt.Sprintf("%x", encoded), err
   142  }
   143  
   144  func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) {
   145  	args := new(BlockNumArg)
   146  	if err := self.codec.Decode(req.Params, &args); err != nil {
   147  		return nil, shared.NewDecodeParamError(err.Error())
   148  	}
   149  
   150  	block := self.xeth.EthBlockByNumber(args.BlockNumber)
   151  	if block == nil {
   152  		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
   153  	}
   154  
   155  	self.ethereum.ChainManager().SetHead(block)
   156  
   157  	return nil, nil
   158  }
   159  
   160  func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) {
   161  	args := new(BlockNumArg)
   162  	if err := self.codec.Decode(req.Params, &args); err != nil {
   163  		return nil, shared.NewDecodeParamError(err.Error())
   164  	}
   165  
   166  	block := self.xeth.EthBlockByNumber(args.BlockNumber)
   167  	if block == nil {
   168  		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
   169  	}
   170  
   171  	old := vm.Debug
   172  	defer func() { vm.Debug = old }()
   173  	vm.Debug = true
   174  
   175  	_, err := self.ethereum.BlockProcessor().RetryProcess(block)
   176  	if err == nil {
   177  		return true, nil
   178  	}
   179  	return false, err
   180  }
   181  
   182  func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) {
   183  	args := new(BlockNumArg)
   184  	if err := self.codec.Decode(req.Params, &args); err != nil {
   185  		return nil, shared.NewDecodeParamError(err.Error())
   186  	}
   187  
   188  	if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil {
   189  		return fmt.Sprintf("0x%x", hash), nil
   190  	} else {
   191  		return nil, err
   192  	}
   193  }
   194  
   195  func (self *debugApi) Metrics(req *shared.Request) (interface{}, error) {
   196  	args := new(MetricsArgs)
   197  	if err := self.codec.Decode(req.Params, &args); err != nil {
   198  		return nil, shared.NewDecodeParamError(err.Error())
   199  	}
   200  	// Create a rate formatter
   201  	units := []string{"", "K", "M", "G", "T", "E", "P"}
   202  	round := func(value float64, prec int) string {
   203  		unit := 0
   204  		for value >= 1000 {
   205  			unit, value, prec = unit+1, value/1000, 2
   206  		}
   207  		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
   208  	}
   209  	format := func(total float64, rate float64) string {
   210  		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
   211  	}
   212  	// Iterate over all the metrics, and just dump for now
   213  	counters := make(map[string]interface{})
   214  	metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
   215  		// Create or retrieve the counter hierarchy for this metric
   216  		root, parts := counters, strings.Split(name, "/")
   217  		for _, part := range parts[:len(parts)-1] {
   218  			if _, ok := root[part]; !ok {
   219  				root[part] = make(map[string]interface{})
   220  			}
   221  			root = root[part].(map[string]interface{})
   222  		}
   223  		name = parts[len(parts)-1]
   224  
   225  		// Fill the counter with the metric details, formatting if requested
   226  		if args.Raw {
   227  			switch metric := metric.(type) {
   228  			case metrics.Meter:
   229  				root[name] = map[string]interface{}{
   230  					"AvgRate01Min": metric.Rate1(),
   231  					"AvgRate05Min": metric.Rate5(),
   232  					"AvgRate15Min": metric.Rate15(),
   233  					"MeanRate":     metric.RateMean(),
   234  					"Overall":      float64(metric.Count()),
   235  				}
   236  
   237  			case metrics.Timer:
   238  				root[name] = map[string]interface{}{
   239  					"AvgRate01Min": metric.Rate1(),
   240  					"AvgRate05Min": metric.Rate5(),
   241  					"AvgRate15Min": metric.Rate15(),
   242  					"MeanRate":     metric.RateMean(),
   243  					"Overall":      float64(metric.Count()),
   244  					"Percentiles": map[string]interface{}{
   245  						"5":  metric.Percentile(0.05),
   246  						"20": metric.Percentile(0.2),
   247  						"50": metric.Percentile(0.5),
   248  						"80": metric.Percentile(0.8),
   249  						"95": metric.Percentile(0.95),
   250  					},
   251  				}
   252  
   253  			default:
   254  				root[name] = "Unknown metric type"
   255  			}
   256  		} else {
   257  			switch metric := metric.(type) {
   258  			case metrics.Meter:
   259  				root[name] = map[string]interface{}{
   260  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   261  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   262  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   263  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   264  				}
   265  
   266  			case metrics.Timer:
   267  				root[name] = map[string]interface{}{
   268  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   269  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   270  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   271  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   272  					"Maximum":  time.Duration(metric.Max()).String(),
   273  					"Minimum":  time.Duration(metric.Min()).String(),
   274  					"Percentiles": map[string]interface{}{
   275  						"5":  time.Duration(metric.Percentile(0.05)).String(),
   276  						"20": time.Duration(metric.Percentile(0.2)).String(),
   277  						"50": time.Duration(metric.Percentile(0.5)).String(),
   278  						"80": time.Duration(metric.Percentile(0.8)).String(),
   279  						"95": time.Duration(metric.Percentile(0.95)).String(),
   280  					},
   281  				}
   282  
   283  			default:
   284  				root[name] = "Unknown metric type"
   285  			}
   286  		}
   287  	})
   288  	return counters, nil
   289  }