added RPC start/stop support

This commit is contained in:
Bas van Kervel 2015-06-22 12:47:32 +02:00
parent 2737baa657
commit 2e0b56a72b
31 changed files with 224 additions and 130 deletions

View File

@ -41,6 +41,7 @@ import (
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
"github.com/peterh/liner" "github.com/peterh/liner"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
"github.com/ethereum/go-ethereum/rpc/shared"
) )
type prompter interface { type prompter interface {
@ -183,7 +184,9 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.Et
js.wait = js.xeth.UpdateState() js.wait = js.xeth.UpdateState()
js.client = client js.client = client
if clt, ok := js.client.(*comms.InProcClient); ok { if clt, ok := js.client.(*comms.InProcClient); ok {
clt.Initialize(js.xeth, ethereum) if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil {
clt.Initialize(api.Merge(offeredApis...))
}
} }
// update state in separare forever blocks // update state in separare forever blocks
@ -311,7 +314,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error {
// load only supported API's in javascript runtime // load only supported API's in javascript runtime
shortcuts := "var eth = web3.eth; " shortcuts := "var eth = web3.eth; "
for _, apiName := range apiNames { for _, apiName := range apiNames {
if apiName == api.Web3ApiName || apiName == api.EthApiName { if apiName == shared.Web3ApiName || apiName == shared.EthApiName {
continue // manually mapped continue // manually mapped
} }

View File

@ -210,7 +210,7 @@ func TestRPC(t *testing.T) {
defer ethereum.Stop() defer ethereum.Stop()
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004)`, `true`) checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004, "*", "web3,eth,net")`, `true`)
} }
func TestCheckTestAccountBalance(t *testing.T) { func TestCheckTestAccountBalance(t *testing.T) {

View File

@ -461,7 +461,7 @@ func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error {
return err return err
} }
return comms.StartIpc(config, codec, apis...) return comms.StartIpc(config, codec, api.Merge(apis...))
} }
func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error { func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
@ -479,7 +479,7 @@ func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error {
return err return err
} }
return comms.StartHttp(config, codec, apis...) return comms.StartHttp(config, codec, api.Merge(apis...))
} }
func StartPProf(ctx *cli.Context) { func StartPProf(ctx *cli.Context) {

View File

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
) )
@ -32,6 +33,8 @@ var (
"admin_chainSyncStatus": (*adminApi).ChainSyncStatus, "admin_chainSyncStatus": (*adminApi).ChainSyncStatus,
"admin_setSolc": (*adminApi).SetSolc, "admin_setSolc": (*adminApi).SetSolc,
"admin_datadir": (*adminApi).DataDir, "admin_datadir": (*adminApi).DataDir,
"admin_startRPC": (*adminApi).StartRPC,
"admin_stopRPC": (*adminApi).StopRPC,
} }
) )
@ -42,25 +45,25 @@ type adminhandler func(*adminApi, *shared.Request) (interface{}, error)
type adminApi struct { type adminApi struct {
xeth *xeth.XEth xeth *xeth.XEth
ethereum *eth.Ethereum ethereum *eth.Ethereum
methods map[string]adminhandler codec codec.Codec
codec codec.ApiCoder coder codec.ApiCoder
} }
// create a new admin api instance // create a new admin api instance
func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *adminApi { func NewAdminApi(xeth *xeth.XEth, ethereum *eth.Ethereum, codec codec.Codec) *adminApi {
return &adminApi{ return &adminApi{
xeth: xeth, xeth: xeth,
ethereum: ethereum, ethereum: ethereum,
methods: AdminMapping, codec: codec,
codec: coder.New(nil), coder: codec.New(nil),
} }
} }
// collection with supported methods // collection with supported methods
func (self *adminApi) Methods() []string { func (self *adminApi) Methods() []string {
methods := make([]string, len(self.methods)) methods := make([]string, len(AdminMapping))
i := 0 i := 0
for k := range self.methods { for k := range AdminMapping {
methods[i] = k methods[i] = k
i++ i++
} }
@ -69,7 +72,7 @@ func (self *adminApi) Methods() []string {
// Execute given request // Execute given request
func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
if callback, ok := self.methods[req.Method]; ok { if callback, ok := AdminMapping[req.Method]; ok {
return callback(self, req) return callback(self, req)
} }
@ -77,7 +80,7 @@ func (self *adminApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *adminApi) Name() string { func (self *adminApi) Name() string {
return AdminApiName return shared.AdminApiName
} }
func (self *adminApi) ApiVersion() string { func (self *adminApi) ApiVersion() string {
@ -86,7 +89,7 @@ func (self *adminApi) ApiVersion() string {
func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) {
args := new(AddPeerArgs) args := new(AddPeerArgs)
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
@ -120,7 +123,7 @@ func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool {
func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) { func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
args := new(ImportExportChainArgs) args := new(ImportExportChainArgs)
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
@ -163,7 +166,7 @@ func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) {
func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) { func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
args := new(ImportExportChainArgs) args := new(ImportExportChainArgs)
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
@ -181,7 +184,7 @@ func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) {
func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) { func (self *adminApi) Verbosity(req *shared.Request) (interface{}, error) {
args := new(VerbosityArgs) args := new(VerbosityArgs)
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
@ -202,7 +205,7 @@ func (self *adminApi) ChainSyncStatus(req *shared.Request) (interface{}, error)
func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
args := new(SetSolcArgs) args := new(SetSolcArgs)
if err := self.codec.Decode(req.Params, &args); err != nil { if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error()) return nil, shared.NewDecodeParamError(err.Error())
} }
@ -212,3 +215,32 @@ func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) {
} }
return solc.Info(), nil return solc.Info(), nil
} }
func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) {
var err error
args := new(StartRPCArgs)
if err := self.coder.Decode(req.Params, &args); err != nil {
return nil, shared.NewDecodeParamError(err.Error())
}
cfg := comms.HttpConfig{
ListenAddress: args.ListenAddress,
ListenPort: args.ListenPort,
CorsDomain: args.CorsDomain,
}
if apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum); err == nil {
err = comms.StartHttp(cfg, self.codec, Merge(apis...))
}
if err == nil {
return true, nil
}
return false, err
}
func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) {
comms.StopHttp()
return true, nil
}

View File

@ -95,3 +95,55 @@ func (args *SetSolcArgs) UnmarshalJSON(b []byte) (err error) {
return shared.NewInvalidTypeError("path", "not a string") return shared.NewInvalidTypeError("path", "not a string")
} }
type StartRPCArgs struct {
ListenAddress string
ListenPort uint
CorsDomain string
Apis string
}
func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
if err := json.Unmarshal(b, &obj); err != nil {
return shared.NewDecodeParamError(err.Error())
}
args.ListenAddress = "127.0.0.1"
args.ListenPort = 8545
args.Apis = "net,eth,web3"
if len(obj) >= 1 {
if addr, ok := obj[0].(string); ok {
args.ListenAddress = addr
} else {
return shared.NewInvalidTypeError("listenAddress", "not a string")
}
}
if len(obj) >= 2 {
if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 {
args.ListenPort = uint(port)
} else {
return shared.NewInvalidTypeError("listenPort", "not a valid port number")
}
}
if len(obj) >= 3 {
if corsDomain, ok := obj[2].(string); ok {
args.CorsDomain = corsDomain
} else {
return shared.NewInvalidTypeError("corsDomain", "not a string")
}
}
if len(obj) >= 4 {
if apis, ok := obj[3].(string); ok {
args.Apis = apis
} else {
return shared.NewInvalidTypeError("apis", "not a string")
}
}
return nil
}

View File

@ -39,6 +39,20 @@ web3._extend({
params: 1, params: 1,
inputFormatter: [web3._extend.utils.formatInputString], inputFormatter: [web3._extend.utils.formatInputString],
outputFormatter: web3._extend.formatters.formatOutputString outputFormatter: web3._extend.formatters.formatOutputString
}),
new web3._extend.Method({
name: 'startRPC',
call: 'admin_startRPC',
params: 4,
inputFormatter: [web3._extend.utils.formatInputString,web3._extend.utils.formatInputInteger,web3._extend.utils.formatInputString,web3._extend.utils.formatInputString],
outputFormatter: web3._extend.formatters.formatOutputBool
}),
new web3._extend.Method({
name: 'stopRPC',
call: 'admin_stopRPC',
params: 0,
inputFormatter: [],
outputFormatter: web3._extend.formatters.formatOutputBool
}) })
], ],
properties: properties:

View File

@ -1,51 +1,10 @@
package api package api
import ( import (
"strings"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
const (
AdminApiName = "admin"
EthApiName = "eth"
DbApiName = "db"
DebugApiName = "debug"
MergedApiName = "merged"
MinerApiName = "miner"
NetApiName = "net"
ShhApiName = "shh"
TxPoolApiName = "txpool"
PersonalApiName = "personal"
Web3ApiName = "web3"
JsonRpcVersion = "2.0"
)
var (
// All API's
AllApis = strings.Join([]string{
AdminApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName,
ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName,
}, ",")
)
// Ethereum RPC API interface
type EthereumApi interface {
// API identifier
Name() string
// API version
ApiVersion() string
// Execute the given request and returns the response or an error
Execute(*shared.Request) (interface{}, error)
// List of supported RCP methods this API provides
Methods() []string
}
// Merge multiple API's to a single API instance // Merge multiple API's to a single API instance
func Merge(apis ...EthereumApi) EthereumApi { func Merge(apis ...shared.EthereumApi) shared.EthereumApi {
return newMergedApi(apis...) return newMergedApi(apis...)
} }

View File

@ -2,6 +2,7 @@ package api
import ( import (
"encoding/json" "encoding/json"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
@ -54,4 +55,4 @@ func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
} }
args.Word = argstr args.Word = argstr
return nil return nil
} }

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )

View File

@ -63,7 +63,7 @@ func (self *dbApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *dbApi) Name() string { func (self *dbApi) Name() string {
return DbApiName return shared.DbApiName
} }
func (self *dbApi) ApiVersion() string { func (self *dbApi) ApiVersion() string {

View File

@ -71,7 +71,7 @@ func (self *debugApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *debugApi) Name() string { func (self *debugApi) Name() string {
return DebugApiName return shared.DebugApiName
} }
func (self *debugApi) ApiVersion() string { func (self *debugApi) ApiVersion() string {

View File

@ -100,7 +100,7 @@ func (self *ethApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *ethApi) Name() string { func (self *ethApi) Name() string {
return EthApiName return shared.EthApiName
} }
func (self *ethApi) ApiVersion() string { func (self *ethApi) ApiVersion() string {

View File

@ -13,14 +13,14 @@ const (
// combines multiple API's // combines multiple API's
type MergedApi struct { type MergedApi struct {
apis map[string]string apis map[string]string
methods map[string]EthereumApi methods map[string]shared.EthereumApi
} }
// create new merged api instance // create new merged api instance
func newMergedApi(apis ...EthereumApi) *MergedApi { func newMergedApi(apis ...shared.EthereumApi) *MergedApi {
mergedApi := new(MergedApi) mergedApi := new(MergedApi)
mergedApi.apis = make(map[string]string, len(apis)) mergedApi.apis = make(map[string]string, len(apis))
mergedApi.methods = make(map[string]EthereumApi) mergedApi.methods = make(map[string]shared.EthereumApi)
for _, api := range apis { for _, api := range apis {
mergedApi.apis[api.Name()] = api.ApiVersion() mergedApi.apis[api.Name()] = api.ApiVersion()
@ -54,7 +54,7 @@ func (self *MergedApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *MergedApi) Name() string { func (self *MergedApi) Name() string {
return MergedApiName return shared.MergedApiName
} }
func (self *MergedApi) ApiVersion() string { func (self *MergedApi) ApiVersion() string {

View File

@ -1 +0,0 @@
package api

View File

@ -66,7 +66,7 @@ func (self *minerApi) Methods() []string {
} }
func (self *minerApi) Name() string { func (self *minerApi) Name() string {
return MinerApiName return shared.MinerApiName
} }
func (self *minerApi) ApiVersion() string { func (self *minerApi) ApiVersion() string {

View File

@ -63,7 +63,7 @@ func (self *netApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *netApi) Name() string { func (self *netApi) Name() string {
return NetApiName return shared.NetApiName
} }
func (self *netApi) ApiVersion() string { func (self *netApi) ApiVersion() string {

View File

@ -66,7 +66,7 @@ func (self *personalApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *personalApi) Name() string { func (self *personalApi) Name() string {
return PersonalApiName return shared.PersonalApiName
} }
func (self *personalApi) ApiVersion() string { func (self *personalApi) ApiVersion() string {

View File

@ -72,7 +72,7 @@ func (self *shhApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *shhApi) Name() string { func (self *shhApi) Name() string {
return ShhApiName return shared.ShhApiName
} }
func (self *shhApi) ApiVersion() string { func (self *shhApi) ApiVersion() string {

View File

@ -60,7 +60,7 @@ func (self *txPoolApi) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *txPoolApi) Name() string { func (self *txPoolApi) Name() string {
return TxPoolApiName return shared.TxPoolApiName
} }
func (self *txPoolApi) ApiVersion() string { func (self *txPoolApi) ApiVersion() string {

View File

@ -7,6 +7,7 @@ import (
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth" "github.com/ethereum/go-ethereum/xeth"
) )
@ -23,6 +24,8 @@ var (
"chainSyncStatus", "chainSyncStatus",
"setSolc", "setSolc",
"datadir", "datadir",
"startRPC",
"stopRPC",
}, },
"db": []string{ "db": []string{
"getString", "getString",
@ -129,35 +132,35 @@ var (
) )
// Parse a comma separated API string to individual api's // Parse a comma separated API string to individual api's
func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum) ([]EthereumApi, error) { func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum) ([]shared.EthereumApi, error) {
if len(strings.TrimSpace(apistr)) == 0 { if len(strings.TrimSpace(apistr)) == 0 {
return nil, fmt.Errorf("Empty apistr provided") return nil, fmt.Errorf("Empty apistr provided")
} }
names := strings.Split(apistr, ",") names := strings.Split(apistr, ",")
apis := make([]EthereumApi, len(names)) apis := make([]shared.EthereumApi, len(names))
for i, name := range names { for i, name := range names {
switch strings.ToLower(strings.TrimSpace(name)) { switch strings.ToLower(strings.TrimSpace(name)) {
case AdminApiName: case shared.AdminApiName:
apis[i] = NewAdminApi(xeth, eth, codec) apis[i] = NewAdminApi(xeth, eth, codec)
case DebugApiName: case shared.DebugApiName:
apis[i] = NewDebugApi(xeth, eth, codec) apis[i] = NewDebugApi(xeth, eth, codec)
case DbApiName: case shared.DbApiName:
apis[i] = NewDbApi(xeth, eth, codec) apis[i] = NewDbApi(xeth, eth, codec)
case EthApiName: case shared.EthApiName:
apis[i] = NewEthApi(xeth, codec) apis[i] = NewEthApi(xeth, codec)
case MinerApiName: case shared.MinerApiName:
apis[i] = NewMinerApi(eth, codec) apis[i] = NewMinerApi(eth, codec)
case NetApiName: case shared.NetApiName:
apis[i] = NewNetApi(xeth, eth, codec) apis[i] = NewNetApi(xeth, eth, codec)
case ShhApiName: case shared.ShhApiName:
apis[i] = NewShhApi(xeth, eth, codec) apis[i] = NewShhApi(xeth, eth, codec)
case TxPoolApiName: case shared.TxPoolApiName:
apis[i] = NewTxPoolApi(xeth, eth, codec) apis[i] = NewTxPoolApi(xeth, eth, codec)
case PersonalApiName: case shared.PersonalApiName:
apis[i] = NewPersonalApi(xeth, eth, codec) apis[i] = NewPersonalApi(xeth, eth, codec)
case Web3ApiName: case shared.Web3ApiName:
apis[i] = NewWeb3Api(xeth, codec) apis[i] = NewWeb3Api(xeth, codec)
default: default:
return nil, fmt.Errorf("Unknown API '%s'", name) return nil, fmt.Errorf("Unknown API '%s'", name)
@ -169,21 +172,21 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
func Javascript(name string) string { func Javascript(name string) string {
switch strings.ToLower(strings.TrimSpace(name)) { switch strings.ToLower(strings.TrimSpace(name)) {
case AdminApiName: case shared.AdminApiName:
return Admin_JS return Admin_JS
case DebugApiName: case shared.DebugApiName:
return Debug_JS return Debug_JS
case DbApiName: case shared.DbApiName:
return Db_JS return Db_JS
case MinerApiName: case shared.MinerApiName:
return Miner_JS return Miner_JS
case NetApiName: case shared.NetApiName:
return Net_JS return Net_JS
case ShhApiName: case shared.ShhApiName:
return Shh_JS return Shh_JS
case TxPoolApiName: case shared.TxPoolApiName:
return TxPool_JS return TxPool_JS
case PersonalApiName: case shared.PersonalApiName:
return Personal_JS return Personal_JS
} }

View File

@ -60,7 +60,7 @@ func (self *web3Api) Execute(req *shared.Request) (interface{}, error) {
} }
func (self *web3Api) Name() string { func (self *web3Api) Name() string {
return Web3ApiName return shared.Web3ApiName
} }
func (self *web3Api) ApiVersion() string { func (self *web3Api) ApiVersion() string {

View File

@ -11,7 +11,6 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
@ -22,14 +21,14 @@ const (
var ( var (
// List with all API's which are offered over the in proc interface by default // List with all API's which are offered over the in proc interface by default
DefaultInProcApis = api.AllApis DefaultInProcApis = shared.AllApis
// List with all API's which are offered over the IPC interface by default // List with all API's which are offered over the IPC interface by default
DefaultIpcApis = api.AllApis DefaultIpcApis = shared.AllApis
// List with API's which are offered over thr HTTP/RPC interface by default // List with API's which are offered over thr HTTP/RPC interface by default
DefaultHttpRpcApis = strings.Join([]string{ DefaultHttpRpcApis = strings.Join([]string{
api.DbApiName, api.EthApiName, api.NetApiName, api.Web3ApiName, shared.DbApiName, shared.EthApiName, shared.NetApiName, shared.Web3ApiName,
}, ",") }, ",")
) )
@ -44,7 +43,7 @@ type EthereumClient interface {
SupportedModules() (map[string]string, error) SupportedModules() (map[string]string, error)
} }
func handle(conn net.Conn, api api.EthereumApi, c codec.Codec) { func handle(conn net.Conn, api shared.EthereumApi, c codec.Codec) {
codec := c.New(conn) codec := c.New(conn)
for { for {

View File

@ -10,7 +10,6 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
"github.com/rs/cors" "github.com/rs/cors"
@ -28,7 +27,7 @@ type HttpConfig struct {
CorsDomain string CorsDomain string
} }
func StartHttp(cfg HttpConfig, codec codec.Codec, apis ...api.EthereumApi) error { func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error {
if httpListener != nil { if httpListener != nil {
if fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) != httpListener.Addr().String() { if fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) != httpListener.Addr().String() {
return fmt.Errorf("RPC service already running on %s ", httpListener.Addr().String()) return fmt.Errorf("RPC service already running on %s ", httpListener.Addr().String())
@ -43,7 +42,6 @@ func StartHttp(cfg HttpConfig, codec codec.Codec, apis ...api.EthereumApi) error
} }
httpListener = l httpListener = l
api := api.Merge(apis...)
var handler http.Handler var handler http.Handler
if len(cfg.CorsDomain) > 0 { if len(cfg.CorsDomain) > 0 {
var opts cors.Options var opts cors.Options

View File

@ -11,7 +11,6 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
@ -90,7 +89,7 @@ func newStoppableHandler(h http.Handler, stop chan struct{}) http.Handler {
case <-stop: case <-stop:
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
err := fmt.Errorf("RPC service stopped") err := fmt.Errorf("RPC service stopped")
response := shared.NewRpcResponse(-1, api.JsonRpcVersion, nil, err) response := shared.NewRpcResponse(-1, shared.JsonRpcVersion, nil, err)
httpSend(w, response) httpSend(w, response)
default: default:
h.ServeHTTP(w, r) h.ServeHTTP(w, r)
@ -110,14 +109,14 @@ func httpSend(writer io.Writer, v interface{}) (n int, err error) {
return writer.Write(payload) return writer.Write(payload)
} }
func gethHttpHandler(codec codec.Codec, a api.EthereumApi) http.Handler { func gethHttpHandler(codec codec.Codec, a shared.EthereumApi) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
// Limit request size to resist DoS // Limit request size to resist DoS
if req.ContentLength > maxHttpSizeReqLength { if req.ContentLength > maxHttpSizeReqLength {
err := fmt.Errorf("Request too large") err := fmt.Errorf("Request too large")
response := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32700, err) response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
httpSend(w, &response) httpSend(w, &response)
return return
} }
@ -126,7 +125,7 @@ func gethHttpHandler(codec codec.Codec, a api.EthereumApi) http.Handler {
payload, err := ioutil.ReadAll(req.Body) payload, err := ioutil.ReadAll(req.Body)
if err != nil { if err != nil {
err := fmt.Errorf("Could not read request body") err := fmt.Errorf("Could not read request body")
response := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32700, err) response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err)
httpSend(w, &response) httpSend(w, &response)
return return
} }
@ -161,7 +160,7 @@ func gethHttpHandler(codec codec.Codec, a api.EthereumApi) http.Handler {
// invalid request // invalid request
err = fmt.Errorf("Could not decode request") err = fmt.Errorf("Could not decode request")
res := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32600, err) res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err)
httpSend(w, res) httpSend(w, res)
}) })
} }

View File

@ -3,15 +3,12 @@ package comms
import ( import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
"github.com/ethereum/go-ethereum/xeth"
) )
type InProcClient struct { type InProcClient struct {
api api.EthereumApi api shared.EthereumApi
codec codec.Codec codec codec.Codec
lastId interface{} lastId interface{}
lastJsonrpc string lastJsonrpc string
@ -31,10 +28,8 @@ func (self *InProcClient) Close() {
} }
// Need to setup api support // Need to setup api support
func (self *InProcClient) Initialize(xeth *xeth.XEth, eth *eth.Ethereum) { func (self *InProcClient) Initialize(offeredApi shared.EthereumApi) {
if apis, err := api.ParseApiString(api.AllApis, self.codec, xeth, eth); err == nil { self.api = offeredApi
self.api = api.Merge(apis...)
}
} }
func (self *InProcClient) Send(req interface{}) error { func (self *InProcClient) Send(req interface{}) error {

View File

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
@ -92,7 +91,6 @@ func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
} }
// Start IPC server // Start IPC server
func StartIpc(cfg IpcConfig, codec codec.Codec, apis ...api.EthereumApi) error { func StartIpc(cfg IpcConfig, codec codec.Codec, offeredApi shared.EthereumApi) error {
offeredApi := api.Merge(apis...)
return startIpc(cfg, codec, offeredApi) return startIpc(cfg, codec, offeredApi)
} }

View File

@ -8,8 +8,8 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
) )
func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) { func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) {
@ -31,7 +31,7 @@ func (self *ipcClient) reconnect() error {
return err return err
} }
func startIpc(cfg IpcConfig, codec codec.Codec, api api.EthereumApi) error { func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := net.ListenUnix("unix", &net.UnixAddr{Name: cfg.Endpoint, Net: "unix"}) l, err := net.ListenUnix("unix", &net.UnixAddr{Name: cfg.Endpoint, Net: "unix"})

View File

@ -14,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
) )
@ -652,7 +651,7 @@ func (self *ipcClient) reconnect() error {
return err return err
} }
func startIpc(cfg IpcConfig, codec codec.Codec, api api.EthereumApi) error { func startIpc(cfg IpcConfig, codec codec.Codec, api shared.EthereumApi) error {
os.Remove(cfg.Endpoint) // in case it still exists from a previous run os.Remove(cfg.Endpoint) // in case it still exists from a previous run
l, err := Listen(cfg.Endpoint) l, err := Listen(cfg.Endpoint)

View File

@ -4,25 +4,24 @@ import (
"encoding/json" "encoding/json"
"github.com/ethereum/go-ethereum/jsre" "github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/shared"
"github.com/robertkrimen/otto" "github.com/robertkrimen/otto"
) )
type Jeth struct { type Jeth struct {
ethApi api.EthereumApi ethApi shared.EthereumApi
re *jsre.JSRE re *jsre.JSRE
client comms.EthereumClient client comms.EthereumClient
} }
func NewJeth(ethApi api.EthereumApi, re *jsre.JSRE, client comms.EthereumClient) *Jeth { func NewJeth(ethApi shared.EthereumApi, re *jsre.JSRE, client comms.EthereumClient) *Jeth {
return &Jeth{ethApi, re, client} return &Jeth{ethApi, re, client}
} }
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) { func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
rpcerr := &shared.ErrorObject{code, msg} rpcerr := &shared.ErrorObject{code, msg}
call.Otto.Set("ret_jsonrpc", api.JsonRpcVersion) call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion)
call.Otto.Set("ret_id", id) call.Otto.Set("ret_id", id)
call.Otto.Set("ret_error", rpcerr) call.Otto.Set("ret_error", rpcerr)
response, _ = call.Otto.Run(` response, _ = call.Otto.Run(`
@ -61,7 +60,7 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
return self.err(call, -32603, err.Error(), req.Id) return self.err(call, -32603, err.Error(), req.Id)
} }
call.Otto.Set("ret_jsonrpc", api.JsonRpcVersion) call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion)
call.Otto.Set("ret_id", req.Id) call.Otto.Set("ret_id", req.Id)
res, _ := json.Marshal(respif) res, _ := json.Marshal(respif)

View File

@ -7,6 +7,21 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
) )
// Ethereum RPC API interface
type EthereumApi interface {
// API identifier
Name() string
// API version
ApiVersion() string
// Execute the given request and returns the response or an error
Execute(*Request) (interface{}, error)
// List of supported RCP methods this API provides
Methods() []string
}
// RPC request // RPC request
type Request struct { type Request struct {
Id interface{} `json:"id"` Id interface{} `json:"id"`

28
rpc/shared/utils.go Normal file
View File

@ -0,0 +1,28 @@
package shared
import "strings"
const (
AdminApiName = "admin"
EthApiName = "eth"
DbApiName = "db"
DebugApiName = "debug"
MergedApiName = "merged"
MinerApiName = "miner"
NetApiName = "net"
ShhApiName = "shh"
TxPoolApiName = "txpool"
PersonalApiName = "personal"
Web3ApiName = "web3"
JsonRpcVersion = "2.0"
)
var (
// All API's
AllApis = strings.Join([]string{
AdminApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName,
ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName,
}, ",")
)