diff --git a/eth/api.go b/eth/api.go index 508070646..105886752 100644 --- a/eth/api.go +++ b/eth/api.go @@ -26,6 +26,7 @@ import ( "math/big" "os" "runtime" + "strings" "sync" "time" @@ -46,6 +47,7 @@ import ( "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "github.com/syndtr/goleveldb/leveldb" "golang.org/x/net/context" ) @@ -1566,6 +1568,22 @@ func NewPrivateDebugAPI(config *core.ChainConfig, eth *Ethereum) *PrivateDebugAP return &PrivateDebugAPI{config: config, eth: eth} } +// ChaindbProperty returns leveldb properties of the chain database. +func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) { + ldb, ok := api.eth.chainDb.(interface { + LDB() *leveldb.DB + }) + if !ok { + return "", fmt.Errorf("chaindbProperty does not work for memory databases") + } + if property == "" { + property = "leveldb.stats" + } else if !strings.HasPrefix(property, "leveldb.") { + property = "leveldb." + property + } + return ldb.LDB().GetProperty(property) +} + // BlockTraceResults is the returned value when replaying a block to check for // consensus results and full VM trace logs for all included transactions. type BlockTraceResult struct { diff --git a/internal/debug/api.go b/internal/debug/api.go index 83857eb2e..2cb264040 100644 --- a/internal/debug/api.go +++ b/internal/debug/api.go @@ -27,6 +27,7 @@ import ( "os/user" "path/filepath" "runtime" + "runtime/debug" "runtime/pprof" "strings" "sync" @@ -69,6 +70,20 @@ func (*HandlerT) BacktraceAt(location string) error { return glog.GetTraceLocation().Set(location) } +// MemStats returns detailed runtime memory statistics. +func (*HandlerT) MemStats() *runtime.MemStats { + s := new(runtime.MemStats) + runtime.ReadMemStats(s) + return s +} + +// GcStats returns GC statistics. +func (*HandlerT) GcStats() *debug.GCStats { + s := new(debug.GCStats) + debug.ReadGCStats(s) + return s +} + // CpuProfile turns on CPU profiling for nsec seconds and writes // profile data to file. func (h *HandlerT) CpuProfile(file string, nsec uint) error { diff --git a/jsre/completion.go b/jsre/completion.go index e84a5b75c..7f94dabfc 100644 --- a/jsre/completion.go +++ b/jsre/completion.go @@ -27,7 +27,9 @@ import ( // evaluated, callers need to make sure that evaluating line does not have side effects. func (jsre *JSRE) CompleteKeywords(line string) []string { var results []string - jsre.do(func(vm *otto.Otto) { results = getCompletions(vm, line) }) + jsre.Do(func(vm *otto.Otto) { + results = getCompletions(vm, line) + }) return results } @@ -53,9 +55,18 @@ func getCompletions(vm *otto.Otto, line string) (results []string) { } } }) - // e.g. web3 append dot since its an object - if obj, _ = vm.Object(line); obj != nil { - results = append(results, line+".") + + // Append opening parenthesis (for functions) or dot (for objects) + // if the line itself is the only completion. + if len(results) == 1 && results[0] == line { + obj, _ := vm.Object(line) + if obj != nil { + if obj.Class() == "Function" { + results[0] += "(" + } else { + results[0] += "." + } + } } sort.Strings(results) diff --git a/jsre/completion_test.go b/jsre/completion_test.go index 6d42b2bd1..8765281e5 100644 --- a/jsre/completion_test.go +++ b/jsre/completion_test.go @@ -40,7 +40,11 @@ func TestCompleteKeywords(t *testing.T) { }{ { input: "x", - want: []string{"x", "x."}, + want: []string{"x."}, + }, + { + input: "x.someMethod", + want: []string{"x.someMethod("}, }, { input: "x.", diff --git a/jsre/jsre.go b/jsre/jsre.go index f4464910d..7df022cb1 100644 --- a/jsre/jsre.go +++ b/jsre/jsre.go @@ -214,8 +214,8 @@ loop: self.loopWg.Done() } -// do schedules the given function on the event loop. -func (self *JSRE) do(fn func(*otto.Otto)) { +// Do executes the given function on the JS event loop. +func (self *JSRE) Do(fn func(*otto.Otto)) { done := make(chan bool) req := &evalReq{fn, done} self.evalQueue <- req @@ -235,7 +235,7 @@ func (self *JSRE) Exec(file string) error { if err != nil { return err } - self.do(func(vm *otto.Otto) { _, err = vm.Run(code) }) + self.Do(func(vm *otto.Otto) { _, err = vm.Run(code) }) return err } @@ -247,19 +247,19 @@ func (self *JSRE) Bind(name string, v interface{}) error { // Run runs a piece of JS code. func (self *JSRE) Run(code string) (v otto.Value, err error) { - self.do(func(vm *otto.Otto) { v, err = vm.Run(code) }) + self.Do(func(vm *otto.Otto) { v, err = vm.Run(code) }) return v, err } // Get returns the value of a variable in the JS environment. func (self *JSRE) Get(ns string) (v otto.Value, err error) { - self.do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) + self.Do(func(vm *otto.Otto) { v, err = vm.Get(ns) }) return v, err } // Set assigns value v to a variable in the JS environment. func (self *JSRE) Set(ns string, v interface{}) (err error) { - self.do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) + self.Do(func(vm *otto.Otto) { err = vm.Set(ns, v) }) return err } @@ -288,7 +288,7 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value { // EvalAndPrettyPrint evaluates code and pretty prints the result to // standard output. func (self *JSRE) EvalAndPrettyPrint(code string) (err error) { - self.do(func(vm *otto.Otto) { + self.Do(func(vm *otto.Otto) { var val otto.Value val, err = vm.Run(code) if err != nil { @@ -302,7 +302,7 @@ func (self *JSRE) EvalAndPrettyPrint(code string) (err error) { // Compile compiles and then runs a piece of JS code. func (self *JSRE) Compile(filename string, src interface{}) (err error) { - self.do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) + self.Do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) }) return err } diff --git a/jsre/pretty.go b/jsre/pretty.go index 8b2b35e8e..cd7fa5232 100644 --- a/jsre/pretty.go +++ b/jsre/pretty.go @@ -177,7 +177,7 @@ func (ctx ppctx) fields(obj *otto.Object) []string { seen = make(map[string]bool) ) add := func(k string) { - if seen[k] || boringKeys[k] { + if seen[k] || boringKeys[k] || strings.HasPrefix(k, "_") { return } seen[k] = true diff --git a/rpc/javascript.go b/rpc/javascript.go index d6ffcdf22..475691a87 100644 --- a/rpc/javascript.go +++ b/rpc/javascript.go @@ -295,6 +295,12 @@ web3._extend({ call: 'debug_dumpBlock', params: 1 }), + new web3._extend.Method({ + name: 'chaindbProperty', + call: 'debug_chaindbProperty', + params: 1, + outputFormatter: console.log + }), new web3._extend.Method({ name: 'metrics', call: 'debug_metrics', @@ -321,6 +327,16 @@ web3._extend({ params: 0, outputFormatter: console.log }), + new web3._extend.Method({ + name: 'memStats', + call: 'debug_memStats', + params: 0, + }), + new web3._extend.Method({ + name: 'gcStats', + call: 'debug_gcStats', + params: 0, + }), new web3._extend.Method({ name: 'cpuProfile', call: 'debug_cpuProfile',