Merge pull request #2235 from fjl/chaindb-api-and-console-fixes
eth: add chaindbProperty to debug API (+ console fixes)
This commit is contained in:
commit
e50e3bea49
18
eth/api.go
18
eth/api.go
|
@ -26,6 +26,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1566,6 +1568,22 @@ func NewPrivateDebugAPI(config *core.ChainConfig, eth *Ethereum) *PrivateDebugAP
|
||||||
return &PrivateDebugAPI{config: config, eth: eth}
|
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
|
// BlockTraceResults is the returned value when replaying a block to check for
|
||||||
// consensus results and full VM trace logs for all included transactions.
|
// consensus results and full VM trace logs for all included transactions.
|
||||||
type BlockTraceResult struct {
|
type BlockTraceResult struct {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -69,6 +70,20 @@ func (*HandlerT) BacktraceAt(location string) error {
|
||||||
return glog.GetTraceLocation().Set(location)
|
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
|
// CpuProfile turns on CPU profiling for nsec seconds and writes
|
||||||
// profile data to file.
|
// profile data to file.
|
||||||
func (h *HandlerT) CpuProfile(file string, nsec uint) error {
|
func (h *HandlerT) CpuProfile(file string, nsec uint) error {
|
||||||
|
|
|
@ -27,7 +27,9 @@ import (
|
||||||
// evaluated, callers need to make sure that evaluating line does not have side effects.
|
// evaluated, callers need to make sure that evaluating line does not have side effects.
|
||||||
func (jsre *JSRE) CompleteKeywords(line string) []string {
|
func (jsre *JSRE) CompleteKeywords(line string) []string {
|
||||||
var results []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
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +55,18 @@ func getCompletions(vm *otto.Otto, line string) (results []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// e.g. web3<tab><tab> append dot since its an object
|
|
||||||
if obj, _ = vm.Object(line); obj != nil {
|
// Append opening parenthesis (for functions) or dot (for objects)
|
||||||
results = append(results, line+".")
|
// 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)
|
sort.Strings(results)
|
||||||
|
|
|
@ -40,7 +40,11 @@ func TestCompleteKeywords(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: "x",
|
input: "x",
|
||||||
want: []string{"x", "x."},
|
want: []string{"x."},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "x.someMethod",
|
||||||
|
want: []string{"x.someMethod("},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "x.",
|
input: "x.",
|
||||||
|
|
16
jsre/jsre.go
16
jsre/jsre.go
|
@ -214,8 +214,8 @@ loop:
|
||||||
self.loopWg.Done()
|
self.loopWg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// do schedules the given function on the event loop.
|
// Do executes the given function on the JS event loop.
|
||||||
func (self *JSRE) do(fn func(*otto.Otto)) {
|
func (self *JSRE) Do(fn func(*otto.Otto)) {
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
req := &evalReq{fn, done}
|
req := &evalReq{fn, done}
|
||||||
self.evalQueue <- req
|
self.evalQueue <- req
|
||||||
|
@ -235,7 +235,7 @@ func (self *JSRE) Exec(file string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.do(func(vm *otto.Otto) { _, err = vm.Run(code) })
|
self.Do(func(vm *otto.Otto) { _, err = vm.Run(code) })
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,19 +247,19 @@ func (self *JSRE) Bind(name string, v interface{}) error {
|
||||||
|
|
||||||
// Run runs a piece of JS code.
|
// Run runs a piece of JS code.
|
||||||
func (self *JSRE) Run(code string) (v otto.Value, err error) {
|
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
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value of a variable in the JS environment.
|
// Get returns the value of a variable in the JS environment.
|
||||||
func (self *JSRE) Get(ns string) (v otto.Value, err error) {
|
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
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set assigns value v to a variable in the JS environment.
|
// Set assigns value v to a variable in the JS environment.
|
||||||
func (self *JSRE) Set(ns string, v interface{}) (err error) {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
|
||||||
// EvalAndPrettyPrint evaluates code and pretty prints the result to
|
// EvalAndPrettyPrint evaluates code and pretty prints the result to
|
||||||
// standard output.
|
// standard output.
|
||||||
func (self *JSRE) EvalAndPrettyPrint(code string) (err error) {
|
func (self *JSRE) EvalAndPrettyPrint(code string) (err error) {
|
||||||
self.do(func(vm *otto.Otto) {
|
self.Do(func(vm *otto.Otto) {
|
||||||
var val otto.Value
|
var val otto.Value
|
||||||
val, err = vm.Run(code)
|
val, err = vm.Run(code)
|
||||||
if err != nil {
|
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.
|
// Compile compiles and then runs a piece of JS code.
|
||||||
func (self *JSRE) Compile(filename string, src interface{}) (err error) {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ func (ctx ppctx) fields(obj *otto.Object) []string {
|
||||||
seen = make(map[string]bool)
|
seen = make(map[string]bool)
|
||||||
)
|
)
|
||||||
add := func(k string) {
|
add := func(k string) {
|
||||||
if seen[k] || boringKeys[k] {
|
if seen[k] || boringKeys[k] || strings.HasPrefix(k, "_") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
seen[k] = true
|
seen[k] = true
|
||||||
|
|
|
@ -295,6 +295,12 @@ web3._extend({
|
||||||
call: 'debug_dumpBlock',
|
call: 'debug_dumpBlock',
|
||||||
params: 1
|
params: 1
|
||||||
}),
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'chaindbProperty',
|
||||||
|
call: 'debug_chaindbProperty',
|
||||||
|
params: 1,
|
||||||
|
outputFormatter: console.log
|
||||||
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'metrics',
|
name: 'metrics',
|
||||||
call: 'debug_metrics',
|
call: 'debug_metrics',
|
||||||
|
@ -321,6 +327,16 @@ web3._extend({
|
||||||
params: 0,
|
params: 0,
|
||||||
outputFormatter: console.log
|
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({
|
new web3._extend.Method({
|
||||||
name: 'cpuProfile',
|
name: 'cpuProfile',
|
||||||
call: 'debug_cpuProfile',
|
call: 'debug_cpuProfile',
|
||||||
|
|
Loading…
Reference in New Issue