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 }