aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2015-06-24 00:12:48 +0800
committerPéter Szilágyi <peterke@gmail.com>2015-06-24 23:34:05 +0800
commitbde2ff034317db977354e0855e6406f9428899ea (patch)
treecc6983f45719968ff883dc9246fec81f5a17bec1
parent803b3c4a825ed0ac5d22c93fc3159651b8c590b2 (diff)
downloaddexon-bde2ff034317db977354e0855e6406f9428899ea.tar.gz
dexon-bde2ff034317db977354e0855e6406f9428899ea.tar.zst
dexon-bde2ff034317db977354e0855e6406f9428899ea.zip
cmd/geth, rpc/api: move the metrics into the new console
-rw-r--r--cmd/geth/admin.go1003
-rw-r--r--rpc/api/debug.go64
-rw-r--r--rpc/api/debug_js.go5
3 files changed, 69 insertions, 1003 deletions
diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go
deleted file mode 100644
index 0c26cc97c..000000000
--- a/cmd/geth/admin.go
+++ /dev/null
@@ -1,1003 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "math/big"
- "strconv"
- "strings"
- "time"
-
- "github.com/ethereum/ethash"
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/cmd/utils"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/compiler"
- "github.com/ethereum/go-ethereum/common/natspec"
- "github.com/ethereum/go-ethereum/common/resolver"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/logger/glog"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/ethereum/go-ethereum/xeth"
- "github.com/rcrowley/go-metrics"
- "github.com/robertkrimen/otto"
- "gopkg.in/fatih/set.v0"
-)
-
-/*
-node admin bindings
-*/
-
-func (js *jsre) adminBindings() {
- ethO, _ := js.re.Get("eth")
- eth := ethO.Object()
- eth.Set("pendingTransactions", js.pendingTransactions)
- eth.Set("resend", js.resend)
- eth.Set("sign", js.sign)
-
- js.re.Set("admin", struct{}{})
- t, _ := js.re.Get("admin")
- admin := t.Object()
- admin.Set("addPeer", js.addPeer)
- admin.Set("startRPC", js.startRPC)
- admin.Set("stopRPC", js.stopRPC)
- admin.Set("nodeInfo", js.nodeInfo)
- admin.Set("peers", js.peers)
- admin.Set("newAccount", js.newAccount)
- admin.Set("unlock", js.unlock)
- admin.Set("import", js.importChain)
- admin.Set("export", js.exportChain)
- admin.Set("verbosity", js.verbosity)
- admin.Set("progress", js.syncProgress)
- admin.Set("setSolc", js.setSolc)
-
- admin.Set("contractInfo", struct{}{})
- t, _ = admin.Get("contractInfo")
- cinfo := t.Object()
- // newRegistry officially not documented temporary option
- cinfo.Set("start", js.startNatSpec)
- cinfo.Set("stop", js.stopNatSpec)
- cinfo.Set("newRegistry", js.newRegistry)
- cinfo.Set("get", js.getContractInfo)
- cinfo.Set("register", js.register)
- cinfo.Set("registerUrl", js.registerUrl)
- // cinfo.Set("verify", js.verify)
-
- admin.Set("miner", struct{}{})
- t, _ = admin.Get("miner")
- miner := t.Object()
- miner.Set("start", js.startMining)
- miner.Set("stop", js.stopMining)
- miner.Set("hashrate", js.hashrate)
- miner.Set("setExtra", js.setExtra)
- miner.Set("setGasPrice", js.setGasPrice)
- miner.Set("startAutoDAG", js.startAutoDAG)
- miner.Set("stopAutoDAG", js.stopAutoDAG)
- miner.Set("makeDAG", js.makeDAG)
-
- admin.Set("txPool", struct{}{})
- t, _ = admin.Get("txPool")
- txPool := t.Object()
- txPool.Set("pending", js.allPendingTransactions)
- txPool.Set("queued", js.allQueuedTransactions)
-
- admin.Set("debug", struct{}{})
- t, _ = admin.Get("debug")
- debug := t.Object()
- js.re.Set("sleep", js.sleep)
- debug.Set("backtrace", js.backtrace)
- debug.Set("printBlock", js.printBlock)
- debug.Set("dumpBlock", js.dumpBlock)
- debug.Set("getBlockRlp", js.getBlockRlp)
- debug.Set("setHead", js.setHead)
- debug.Set("processBlock", js.debugBlock)
- debug.Set("seedhash", js.seedHash)
- debug.Set("insertBlock", js.insertBlockRlp)
- // undocumented temporary
- debug.Set("waitForBlocks", js.waitForBlocks)
-
- admin.Set("metrics", js.metrics)
-}
-
-// generic helper to getBlock by Number/Height or Hex depending on autodetected input
-// if argument is missing the current block is returned
-// if block is not found or there is problem with decoding
-// the appropriate value is returned and block is guaranteed to be nil
-func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
- var block *types.Block
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
- } else if call.Argument(0).IsString() {
- hash, _ := call.Argument(0).ToString()
- block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
- } else {
- return nil, errors.New("invalid argument for dump. Either hex string or number")
- }
- } else {
- block = js.ethereum.ChainManager().CurrentBlock()
- }
-
- if block == nil {
- return nil, errors.New("block not found")
- }
- return block, nil
-}
-
-func (js *jsre) seedHash(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) > 0 {
- if call.Argument(0).IsNumber() {
- num, _ := call.Argument(0).ToInteger()
- hash, err := ethash.GetSeedHash(uint64(num))
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(fmt.Sprintf("0x%x", hash))
- return v
- } else {
- fmt.Println("arg not a number")
- }
- } else {
- fmt.Println("requires number argument")
- }
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) allPendingTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetTransactions()
-
- ltxs := make([]*tx, len(txs))
- for i, tx := range txs {
- // no need to check err
- ltxs[i] = newTx(tx)
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) allQueuedTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetQueuedTransactions()
-
- ltxs := make([]*tx, len(txs))
- for i, tx := range txs {
- // no need to check err
- ltxs[i] = newTx(tx)
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
- txs := js.ethereum.TxPool().GetTransactions()
-
- // grab the accounts from the account manager. This will help with determening which
- // transactions should be returned.
- accounts, err := js.ethereum.AccountManager().Accounts()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- // Add the accouns to a new set
- accountSet := set.New()
- for _, account := range accounts {
- accountSet.Add(account.Address)
- }
-
- //ltxs := make([]*tx, len(txs))
- var ltxs []*tx
- for _, tx := range txs {
- if from, _ := tx.From(); accountSet.Has(from) {
- ltxs = append(ltxs, newTx(tx))
- }
- }
-
- v, _ := call.Otto.ToValue(ltxs)
- return v
-}
-
-func (js *jsre) resend(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("first argument must be a transaction")
- return otto.FalseValue()
- }
-
- v, err := call.Argument(0).Export()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- if tx, ok := v.(*tx); ok {
- gl, gp := tx.GasLimit, tx.GasPrice
- if len(call.ArgumentList) > 1 {
- gp = call.Argument(1).String()
- }
- if len(call.ArgumentList) > 2 {
- gl = call.Argument(2).String()
- }
-
- ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- js.ethereum.TxPool().RemoveTransactions(types.Transactions{tx.tx})
-
- v, _ := call.Otto.ToValue(ret)
- return v
- }
-
- fmt.Println("first argument must be a transaction")
- return otto.FalseValue()
-}
-
-func (js *jsre) sign(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 2 {
- fmt.Println("requires 2 arguments: eth.sign(signer, data)")
- return otto.UndefinedValue()
- }
- signer, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- data, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- signed, err := js.xeth.Sign(signer, data, false)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(signed)
- return v
-}
-
-func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- tstart := time.Now()
- old := vm.Debug
-
- if len(call.ArgumentList) > 1 {
- vm.Debug, _ = call.Argument(1).ToBoolean()
- }
-
- _, err = js.ethereum.BlockProcessor().RetryProcess(block)
- if err != nil {
- fmt.Println(err)
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": false, "time": time.Since(tstart).Seconds()})
- return r
- }
- vm.Debug = old
-
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": true, "time": time.Since(tstart).Seconds()})
- return r
-}
-
-func (js *jsre) insertBlockRlp(call otto.FunctionCall) otto.Value {
- tstart := time.Now()
-
- var block types.Block
- if call.Argument(0).IsString() {
- blockRlp, _ := call.Argument(0).ToString()
- err := rlp.DecodeBytes(common.Hex2Bytes(blockRlp), &block)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- }
-
- old := vm.Debug
- vm.Debug = true
- _, err := js.ethereum.BlockProcessor().RetryProcess(&block)
- if err != nil {
- fmt.Println(err)
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": false, "time": time.Since(tstart).Seconds()})
- return r
- }
- vm.Debug = old
-
- r, _ := call.Otto.ToValue(map[string]interface{}{"success": true, "time": time.Since(tstart).Seconds()})
- return r
-}
-
-func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- js.ethereum.ChainManager().SetHead(block)
- return otto.UndefinedValue()
-}
-
-func (js *jsre) syncProgress(call otto.FunctionCall) otto.Value {
- pending, cached, importing, eta := js.ethereum.Downloader().Stats()
- v, _ := call.Otto.ToValue(map[string]interface{}{
- "pending": pending,
- "cached": cached,
- "importing": importing,
- "estimate": (eta / time.Second * time.Second).String(),
- })
- return v
-}
-
-func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- encoded, _ := rlp.EncodeToBytes(block)
- v, _ := call.Otto.ToValue(fmt.Sprintf("%x", encoded))
- return v
-}
-
-func (js *jsre) setExtra(call otto.FunctionCall) otto.Value {
- extra, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- if len(extra) > 1024 {
- fmt.Println("error: cannot exceed 1024 bytes")
- return otto.UndefinedValue()
- }
-
- js.ethereum.Miner().SetExtra([]byte(extra))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) setGasPrice(call otto.FunctionCall) otto.Value {
- gasPrice, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- js.ethereum.Miner().SetGasPrice(common.String2Big(gasPrice))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) hashrate(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.Miner().HashRate())
- return v
-}
-
-func (js *jsre) makeDAG(call otto.FunctionCall) otto.Value {
- blockNumber, err := call.Argument(1).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- err = ethash.MakeDAG(uint64(blockNumber), "")
- if err != nil {
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) startAutoDAG(otto.FunctionCall) otto.Value {
- js.ethereum.StartAutoDAG()
- return otto.TrueValue()
-}
-
-func (js *jsre) stopAutoDAG(otto.FunctionCall) otto.Value {
- js.ethereum.StopAutoDAG()
- return otto.TrueValue()
-}
-
-func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
- tracestr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- glog.GetTraceLocation().Set(tracestr)
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) verbosity(call otto.FunctionCall) otto.Value {
- v, err := call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- glog.SetV(int(v))
- return otto.UndefinedValue()
-}
-
-func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
- var (
- threads int64
- err error
- )
-
- if len(call.ArgumentList) > 0 {
- threads, err = call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- } else {
- threads = int64(js.ethereum.MinerThreads)
- }
-
- // switch on DAG autogeneration when miner starts
- js.ethereum.StartAutoDAG()
-
- err = js.ethereum.StartMining(int(threads))
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
- js.ethereum.StopMining()
- js.ethereum.StopAutoDAG()
- return otto.TrueValue()
-}
-
-func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- port, err := call.Argument(1).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- corsDomain := js.corsDomain
- if len(call.ArgumentList) > 2 {
- corsDomain, err = call.Argument(2).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- }
-
- config := rpc.RpcConfig{
- ListenAddress: addr,
- ListenPort: uint(port),
- CorsDomain: corsDomain,
- }
-
- xeth := xeth.New(js.ethereum, nil)
- err = rpc.Start(xeth, config)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) stopRPC(call otto.FunctionCall) otto.Value {
- if rpc.Stop() == nil {
- return otto.TrueValue()
- }
- return otto.FalseValue()
-}
-
-func (js *jsre) addPeer(call otto.FunctionCall) otto.Value {
- nodeURL, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- err = js.ethereum.AddPeer(nodeURL)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- seconds, err := call.Argument(2).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if seconds == 0 {
- seconds = accounts.DefaultAccountUnlockDuration
- }
-
- arg := call.Argument(1)
- var passphrase string
- if arg.IsUndefined() {
- fmt.Println("Please enter a passphrase now.")
- passphrase, err = utils.PromptPassword("Passphrase: ", true)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- } else {
- passphrase, err = arg.ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- }
- am := js.ethereum.AccountManager()
- err = am.TimedUnlock(common.HexToAddress(addr), passphrase, time.Duration(seconds)*time.Second)
- if err != nil {
- fmt.Printf("Unlock account failed '%v'\n", err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
- arg := call.Argument(0)
- var passphrase string
- if arg.IsUndefined() {
- fmt.Println("The new account will be encrypted with a passphrase.")
- fmt.Println("Please enter a passphrase now.")
- auth, err := utils.PromptPassword("Passphrase: ", true)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if auth != confirm {
- fmt.Println("Passphrases did not match.")
- return otto.FalseValue()
- }
- passphrase = auth
- } else {
- var err error
- passphrase, err = arg.ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- }
- acct, err := js.ethereum.AccountManager().NewAccount(passphrase)
- if err != nil {
- fmt.Printf("Could not create the account: %v", err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(acct.Address.Hex())
- return v
-}
-
-func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.NodeInfo())
- return v
-}
-
-func (js *jsre) peers(call otto.FunctionCall) otto.Value {
- v, _ := call.Otto.ToValue(js.ethereum.PeersInfo())
- return v
-}
-
-func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("require file name. admin.importChain(filename)")
- return otto.FalseValue()
- }
- fn, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil {
- fmt.Println("Import error: ", err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) == 0 {
- fmt.Println("require file name: admin.exportChain(filename)")
- return otto.FalseValue()
- }
-
- fn, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- return otto.TrueValue()
-}
-
-func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- fmt.Println(block)
-
- return otto.UndefinedValue()
-}
-
-func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
- block, err := js.getBlock(call)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- statedb := state.New(block.Root(), js.ethereum.StateDb())
- dump := statedb.RawDump()
- v, _ := call.Otto.ToValue(dump)
- return v
-}
-
-func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) > 2 {
- fmt.Println("requires 0, 1 or 2 arguments: admin.debug.waitForBlock(minHeight, timeout)")
- return otto.FalseValue()
- }
- var n, timeout int64
- var timer <-chan time.Time
- var height *big.Int
- var err error
- args := len(call.ArgumentList)
- if args == 2 {
- timeout, err = call.Argument(1).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- timer = time.NewTimer(time.Duration(timeout) * time.Second).C
- }
- if args >= 1 {
- n, err = call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- height = big.NewInt(n)
- }
-
- if args == 0 {
- height = js.xeth.CurrentBlock().Number()
- height.Add(height, common.Big1)
- }
-
- wait := js.wait
- js.wait <- height
- select {
- case <-timer:
- // if times out make sure the xeth loop does not block
- go func() {
- select {
- case wait <- nil:
- case <-wait:
- }
- }()
- return otto.UndefinedValue()
- case height = <-wait:
- }
- v, _ := call.Otto.ToValue(height.Uint64())
- return v
-}
-
-func (js *jsre) metrics(call otto.FunctionCall) otto.Value {
- // Create a rate formatter
- units := []string{"", "K", "M", "G", "T", "E", "P"}
- round := func(value float64, prec int) string {
- unit := 0
- for value >= 1000 {
- unit, value, prec = unit+1, value/1000, 2
- }
- return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
- }
- format := func(total float64, rate float64) string {
- return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
- }
- // Iterate over all the metrics, and just dump for now
- counters := make(map[string]interface{})
- metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
- // Create or retrieve the counter hierarchy for this metric
- root, parts := counters, strings.Split(name, "/")
- for _, part := range parts[:len(parts)-1] {
- if _, ok := root[part]; !ok {
- root[part] = make(map[string]interface{})
- }
- root = root[part].(map[string]interface{})
- }
- name = parts[len(parts)-1]
-
- // Fill the counter with the metric details
- switch metric := metric.(type) {
- case metrics.Meter:
- root[name] = map[string]interface{}{
- "Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
- "Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
- "Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
- "Total": format(float64(metric.Count()), metric.RateMean()),
- }
-
- case metrics.Timer:
- root[name] = map[string]interface{}{
- "Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
- "Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
- "Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
- "Count": format(float64(metric.Count()), metric.RateMean()),
- "Maximum": time.Duration(metric.Max()).String(),
- "Minimum": time.Duration(metric.Min()).String(),
- "Percentile": map[string]interface{}{
- "20": time.Duration(metric.Percentile(0.2)).String(),
- "50": time.Duration(metric.Percentile(0.5)).String(),
- "80": time.Duration(metric.Percentile(0.8)).String(),
- "95": time.Duration(metric.Percentile(0.95)).String(),
- "99": time.Duration(metric.Percentile(0.99)).String(),
- },
- }
-
- default:
- root[name] = "Unknown metric type"
- }
- })
- // Flatten the counters into some metrics and return
- v, _ := call.Otto.ToValue(counters)
- return v
-}
-
-func (js *jsre) sleep(call otto.FunctionCall) otto.Value {
- sec, err := call.Argument(0).ToInteger()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- time.Sleep(time.Duration(sec) * time.Second)
- return otto.UndefinedValue()
-}
-
-func (js *jsre) setSolc(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 1 {
- fmt.Println("needs 1 argument: admin.contractInfo.setSolc(solcPath)")
- return otto.FalseValue()
- }
- solcPath, err := call.Argument(0).ToString()
- if err != nil {
- return otto.FalseValue()
- }
- solc, err := js.xeth.SetSolc(solcPath)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
- fmt.Println(solc.Info())
- return otto.TrueValue()
-}
-
-func (js *jsre) register(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 4 {
- fmt.Println("requires 4 arguments: admin.contractInfo.register(fromaddress, contractaddress, contract, filename)")
- return otto.UndefinedValue()
- }
- sender, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- address, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- raw, err := call.Argument(2).Export()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- jsonraw, err := json.Marshal(raw)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- var contract compiler.Contract
- err = json.Unmarshal(jsonraw, &contract)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- filename, err := call.Argument(3).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- contenthash, err := compiler.ExtractInfo(&contract, filename)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- // sender and contract address are passed as hex strings
- codeb := js.xeth.CodeAtBytes(address)
- codehash := common.BytesToHash(crypto.Sha3(codeb))
-
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- registry := resolver.New(js.xeth)
-
- _, err = registry.RegisterContentHash(common.HexToAddress(sender), codehash, contenthash)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
-
- v, _ := call.Otto.ToValue(contenthash.Hex())
- return v
-}
-
-func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 3 {
- fmt.Println("requires 3 arguments: admin.contractInfo.register(fromaddress, contenthash, filename)")
- return otto.FalseValue()
- }
- sender, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- contenthash, err := call.Argument(1).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- url, err := call.Argument(2).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- registry := resolver.New(js.xeth)
-
- _, err = registry.RegisterUrl(common.HexToAddress(sender), common.HexToHash(contenthash), url)
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-func (js *jsre) getContractInfo(call otto.FunctionCall) otto.Value {
- if len(call.ArgumentList) != 1 {
- fmt.Println("requires 1 argument: admin.contractInfo.register(contractaddress)")
- return otto.FalseValue()
- }
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- infoDoc, err := natspec.FetchDocsForContract(addr, js.xeth, ds)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- var info compiler.ContractInfo
- err = json.Unmarshal(infoDoc, &info)
- if err != nil {
- fmt.Println(err)
- return otto.UndefinedValue()
- }
- v, _ := call.Otto.ToValue(info)
- return v
-}
-
-func (js *jsre) startNatSpec(call otto.FunctionCall) otto.Value {
- js.ethereum.NatSpec = true
- return otto.TrueValue()
-}
-
-func (js *jsre) stopNatSpec(call otto.FunctionCall) otto.Value {
- js.ethereum.NatSpec = false
- return otto.TrueValue()
-}
-
-func (js *jsre) newRegistry(call otto.FunctionCall) otto.Value {
-
- if len(call.ArgumentList) != 1 {
- fmt.Println("requires 1 argument: admin.contractInfo.newRegistry(adminaddress)")
- return otto.FalseValue()
- }
- addr, err := call.Argument(0).ToString()
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- registry := resolver.New(js.xeth)
- err = registry.CreateContracts(common.HexToAddress(addr))
- if err != nil {
- fmt.Println(err)
- return otto.FalseValue()
- }
-
- return otto.TrueValue()
-}
-
-// internal transaction type which will allow us to resend transactions using `eth.resend`
-type tx struct {
- tx *types.Transaction
-
- To string
- From string
- Nonce string
- Value string
- Data string
- GasLimit string
- GasPrice string
-}
-
-func newTx(t *types.Transaction) *tx {
- from, _ := t.From()
- var to string
- if t := t.To(); t != nil {
- to = t.Hex()
- }
-
- return &tx{
- tx: t,
- To: to,
- From: from.Hex(),
- Value: t.Amount.String(),
- Nonce: strconv.Itoa(int(t.Nonce())),
- Data: "0x" + common.Bytes2Hex(t.Data()),
- GasLimit: t.GasLimit.String(),
- GasPrice: t.GasPrice().String(),
- }
-}
diff --git a/rpc/api/debug.go b/rpc/api/debug.go
index b451d8662..871786c6f 100644
--- a/rpc/api/debug.go
+++ b/rpc/api/debug.go
@@ -2,6 +2,8 @@ package api
import (
"fmt"
+ "strings"
+ "time"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/core/state"
@@ -11,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth"
+ "github.com/rcrowley/go-metrics"
)
const (
@@ -26,6 +29,7 @@ var (
"debug_processBlock": (*debugApi).ProcessBlock,
"debug_seedHash": (*debugApi).SeedHash,
"debug_setHead": (*debugApi).SetHead,
+ "debug_metrics": (*debugApi).Metrics,
}
)
@@ -171,3 +175,63 @@ func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) {
return nil, err
}
}
+
+func (self *debugApi) Metrics(req *shared.Request) (interface{}, error) {
+ // Create a rate formatter
+ units := []string{"", "K", "M", "G", "T", "E", "P"}
+ round := func(value float64, prec int) string {
+ unit := 0
+ for value >= 1000 {
+ unit, value, prec = unit+1, value/1000, 2
+ }
+ return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
+ }
+ format := func(total float64, rate float64) string {
+ return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
+ }
+ // Iterate over all the metrics, and just dump for now
+ counters := make(map[string]interface{})
+ metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
+ // Create or retrieve the counter hierarchy for this metric
+ root, parts := counters, strings.Split(name, "/")
+ for _, part := range parts[:len(parts)-1] {
+ if _, ok := root[part]; !ok {
+ root[part] = make(map[string]interface{})
+ }
+ root = root[part].(map[string]interface{})
+ }
+ name = parts[len(parts)-1]
+
+ // Fill the counter with the metric details
+ switch metric := metric.(type) {
+ case metrics.Meter:
+ root[name] = map[string]interface{}{
+ "Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
+ "Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
+ "Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
+ "Total": format(float64(metric.Count()), metric.RateMean()),
+ }
+
+ case metrics.Timer:
+ root[name] = map[string]interface{}{
+ "Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
+ "Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
+ "Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
+ "Count": format(float64(metric.Count()), metric.RateMean()),
+ "Maximum": time.Duration(metric.Max()).String(),
+ "Minimum": time.Duration(metric.Min()).String(),
+ "Percentile": map[string]interface{}{
+ "20": time.Duration(metric.Percentile(0.2)).String(),
+ "50": time.Duration(metric.Percentile(0.5)).String(),
+ "80": time.Duration(metric.Percentile(0.8)).String(),
+ "95": time.Duration(metric.Percentile(0.95)).String(),
+ "99": time.Duration(metric.Percentile(0.99)).String(),
+ },
+ }
+
+ default:
+ root[name] = "Unknown metric type"
+ }
+ })
+ return counters, nil
+}
diff --git a/rpc/api/debug_js.go b/rpc/api/debug_js.go
index 35fecb75f..e48e4df06 100644
--- a/rpc/api/debug_js.go
+++ b/rpc/api/debug_js.go
@@ -50,6 +50,11 @@ web3._extend({
],
properties:
[
+ new web3._extend.Property({
+ name: 'metrics',
+ getter: 'debug_metrics',
+ outputFormatter: function(obj) { return obj; }
+ })
]
});
`