debug.go 7.8 KB

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