mirror of https://github.com/ethereum/go-ethereum
parent
faab931ce1
commit
09d0d55fc5
@ -0,0 +1,169 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/ethereum/ethash" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"github.com/ethereum/go-ethereum/eth" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
"github.com/ethereum/go-ethereum/rpc/codec" |
||||
"github.com/ethereum/go-ethereum/rpc/shared" |
||||
"github.com/ethereum/go-ethereum/xeth" |
||||
) |
||||
|
||||
const ( |
||||
DebugVersion = "1.0.0" |
||||
) |
||||
|
||||
var ( |
||||
// mapping between methods and handlers
|
||||
DebugMapping = map[string]debughandler{ |
||||
"debug_dumpBlock": (*DebugApi).DumpBlock, |
||||
"debug_getBlockRlp": (*DebugApi).GetBlockRlp, |
||||
"debug_printBlock": (*DebugApi).PrintBlock, |
||||
"debug_processBlock": (*DebugApi).ProcessBlock, |
||||
"debug_seedHash": (*DebugApi).SeedHash, |
||||
"debug_setHead": (*DebugApi).SetHead, |
||||
} |
||||
) |
||||
|
||||
// debug callback handler
|
||||
type debughandler func(*DebugApi, *shared.Request) (interface{}, error) |
||||
|
||||
// admin api provider
|
||||
type DebugApi struct { |
||||
xeth *xeth.XEth |
||||
ethereum *eth.Ethereum |
||||
methods map[string]debughandler |
||||
codec codec.ApiCoder |
||||
} |
||||
|
||||
// create a new debug api instance
|
||||
func NewDebugApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *DebugApi { |
||||
return &DebugApi{ |
||||
xeth: xeth, |
||||
ethereum: ethereum, |
||||
methods: DebugMapping, |
||||
codec: coder.New(nil), |
||||
} |
||||
} |
||||
|
||||
// collection with supported methods
|
||||
func (self *DebugApi) Methods() []string { |
||||
methods := make([]string, len(self.methods)) |
||||
i := 0 |
||||
for k := range self.methods { |
||||
methods[i] = k |
||||
i++ |
||||
} |
||||
return methods |
||||
} |
||||
|
||||
// Execute given request
|
||||
func (self *DebugApi) Execute(req *shared.Request) (interface{}, error) { |
||||
if callback, ok := self.methods[req.Method]; ok { |
||||
return callback(self, req) |
||||
} |
||||
|
||||
return nil, &shared.NotImplementedError{req.Method} |
||||
} |
||||
|
||||
func (self *DebugApi) Name() string { |
||||
return DebugApiName |
||||
} |
||||
|
||||
func (self *DebugApi) PrintBlock(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
block := self.xeth.EthBlockByNumber(args.BlockNumber) |
||||
return fmt.Sprintf("%s", block), nil |
||||
} |
||||
|
||||
func (self *DebugApi) DumpBlock(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
block := self.xeth.EthBlockByNumber(args.BlockNumber) |
||||
if block == nil { |
||||
return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |
||||
} |
||||
|
||||
stateDb := state.New(block.Root(), self.ethereum.StateDb()) |
||||
if stateDb == nil { |
||||
return nil, nil |
||||
} |
||||
|
||||
return stateDb.Dump(), nil |
||||
} |
||||
|
||||
func (self *DebugApi) GetBlockRlp(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
block := self.xeth.EthBlockByNumber(args.BlockNumber) |
||||
if block == nil { |
||||
return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |
||||
} |
||||
encoded, err := rlp.EncodeToBytes(block) |
||||
return fmt.Sprintf("%x", encoded), err |
||||
} |
||||
|
||||
func (self *DebugApi) SetHead(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
block := self.xeth.EthBlockByNumber(args.BlockNumber) |
||||
if block == nil { |
||||
return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |
||||
} |
||||
|
||||
self.ethereum.ChainManager().SetHead(block) |
||||
|
||||
return nil, nil |
||||
} |
||||
|
||||
func (self *DebugApi) ProcessBlock(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
block := self.xeth.EthBlockByNumber(args.BlockNumber) |
||||
if block == nil { |
||||
return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |
||||
} |
||||
|
||||
old := vm.Debug |
||||
defer func() { vm.Debug = old }() |
||||
vm.Debug = true |
||||
|
||||
_, err := self.ethereum.BlockProcessor().RetryProcess(block) |
||||
if err == nil { |
||||
return true, nil |
||||
} |
||||
return false, err |
||||
} |
||||
|
||||
func (self *DebugApi) SeedHash(req *shared.Request) (interface{}, error) { |
||||
args := new(BlockNumArg) |
||||
if err := self.codec.Decode(req.Params, &args); err != nil { |
||||
return nil, shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil { |
||||
return fmt.Sprintf("0x%x", hash), nil |
||||
} else { |
||||
return nil, err |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/rpc/shared" |
||||
) |
||||
|
||||
type WaitForBlockArgs struct { |
||||
MinHeight int |
||||
Timeout int // in seconds
|
||||
} |
||||
|
||||
func (args *WaitForBlockArgs) UnmarshalJSON(b []byte) (err error) { |
||||
var obj []interface{} |
||||
if err := json.Unmarshal(b, &obj); err != nil { |
||||
return shared.NewDecodeParamError(err.Error()) |
||||
} |
||||
|
||||
if len(obj) > 2 { |
||||
return fmt.Errorf("waitForArgs needs 0, 1, 2 arguments") |
||||
} |
||||
|
||||
// default values when not provided
|
||||
args.MinHeight = -1 |
||||
args.Timeout = -1 |
||||
|
||||
if len(obj) >= 1 { |
||||
var minHeight *big.Int |
||||
if minHeight, err = numString(obj[0]); err != nil { |
||||
return err |
||||
} |
||||
args.MinHeight = int(minHeight.Int64()) |
||||
} |
||||
|
||||
if len(obj) >= 2 { |
||||
timeout, err := numString(obj[1]) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
args.Timeout = int(timeout.Int64()) |
||||
} |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,48 @@ |
||||
package api |
||||
|
||||
const Debug_JS = ` |
||||
web3.extend({ |
||||
property: 'debug', |
||||
methods: |
||||
[ |
||||
new web3.extend.Method({ |
||||
name: 'printBlock', |
||||
call: 'debug_printBlock', |
||||
params: 1, |
||||
inputFormatter: [web3.extend.formatters.formatInputInt], |
||||
outputFormatter: web3.extend.formatters.formatOutputString |
||||
}), |
||||
new web3.extend.Method({ |
||||
name: 'getBlockRlp', |
||||
call: 'debug_getBlockRlp', |
||||
params: 1, |
||||
inputFormatter: [web3.extend.formatters.formatInputInt], |
||||
outputFormatter: web3.extend.formatters.formatOutputString |
||||
}), |
||||
new web3.extend.Method({ |
||||
name: 'setHead', |
||||
call: 'debug_setHead', |
||||
params: 1, |
||||
inputFormatter: [web3.extend.formatters.formatInputInt], |
||||
outputFormatter: web3.extend.formatters.formatOutputBool |
||||
}), |
||||
new web3.extend.Method({ |
||||
name: 'processBlock', |
||||
call: 'debug_processBlock', |
||||
params: 1, |
||||
inputFormatter: [web3.extend.formatters.formatInputInt], |
||||
outputFormatter: function(obj) { return obj; } |
||||
}), |
||||
new web3.extend.Method({ |
||||
name: 'seedHash', |
||||
call: 'debug_seedHash', |
||||
params: 1, |
||||
inputFormatter: [web3.extend.formatters.formatInputInt], |
||||
outputFormatter: web3.extend.formatters.formatOutputString |
||||
}) |
||||
], |
||||
properties: |
||||
[ |
||||
] |
||||
}); |
||||
` |
Loading…
Reference in new issue