diff options
author | Bas van Kervel <bas@ethdev.com> | 2015-10-15 22:07:19 +0800 |
---|---|---|
committer | Bas van Kervel <bas@ethdev.com> | 2015-12-14 23:34:05 +0800 |
commit | eae81465c1c815c317cd30e4de6bdf4d59df2340 (patch) | |
tree | b6f4b7787967a58416171adb79fd12ac29d89577 /cmd | |
parent | 8db9d44ca9fb6baf406256cae491c475de2f4989 (diff) | |
download | dexon-eae81465c1c815c317cd30e4de6bdf4d59df2340.tar.gz dexon-eae81465c1c815c317cd30e4de6bdf4d59df2340.tar.zst dexon-eae81465c1c815c317cd30e4de6bdf4d59df2340.zip |
rpc: new RPC implementation with pub/sub support
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/geth/js.go | 22 | ||||
-rw-r--r-- | cmd/geth/js_test.go | 2 | ||||
-rw-r--r-- | cmd/geth/main.go | 1 | ||||
-rw-r--r-- | cmd/geth/usage.go | 1 | ||||
-rw-r--r-- | cmd/gethrpctest/main.go | 65 | ||||
-rw-r--r-- | cmd/utils/api.go | 74 | ||||
-rw-r--r-- | cmd/utils/flags.go | 52 |
7 files changed, 207 insertions, 10 deletions
diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 843c9a5b5..56b7a8b00 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -246,10 +246,10 @@ func (self *jsre) welcome() { self.re.Run(` (function () { console.log('instance: ' + web3.version.node); - console.log(' datadir: ' + admin.datadir); console.log("coinbase: " + eth.coinbase); var ts = 1000 * eth.getBlock(eth.blockNumber).timestamp; console.log("at block: " + eth.blockNumber + " (" + new Date(ts) + ")"); + console.log(' datadir: ' + admin.datadir); })(); `) if modules, err := self.supportedApis(); err == nil { @@ -258,7 +258,7 @@ func (self *jsre) welcome() { loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version)) } sort.Strings(loadedModules) - fmt.Println("modules:", strings.Join(loadedModules, " ")) + } } @@ -325,12 +325,28 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { } _, err = js.re.Run(shortcuts) - if err != nil { utils.Fatalf("Error setting namespaces: %v", err) } js.re.Run(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`) + + // overrule some of the methods that require password as input and ask for it interactively + p, err := js.re.Get("personal") + if err != nil { + fmt.Println("Unable to overrule sensitive methods in personal module") + return nil + } + + // Override the unlockAccount and newAccount methods on the personal object since these require user interaction. + // Assign the jeth.unlockAccount and jeth.newAccount in the jsre the original web3 callbacks. These will be called + // by the jeth.* methods after they got the password from the user and send the original web3 request to the backend. + persObj := p.Object() + js.re.Run(`jeth.unlockAccount = personal.unlockAccount;`) + persObj.Set("unlockAccount", jeth.UnlockAccount) + js.re.Run(`jeth.newAccount = personal.newAccount;`) + persObj.Set("newAccount", jeth.NewAccount) + return nil } diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index a0f3f2fb7..ca636188f 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -168,7 +168,7 @@ func TestAccounts(t *testing.T) { checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`) - val, err := repl.re.Run(`personal.newAccount("password")`) + val, err := repl.re.Run(`jeth.newAccount("password")`) if err != nil { t.Errorf("expected no error, got %v", err) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6ec30cebc..bb291ccde 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -313,6 +313,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.IPCDisabledFlag, utils.IPCApiFlag, utils.IPCPathFlag, + utils.IPCExperimental, utils.ExecFlag, utils.WhisperEnabledFlag, utils.DevModeFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 5c09e29ce..7a6ff704c 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -158,6 +158,7 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.WhisperEnabledFlag, utils.NatspecEnabledFlag, + utils.IPCExperimental, }, }, { diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go index 7130980ac..636d329e4 100644 --- a/cmd/gethrpctest/main.go +++ b/cmd/gethrpctest/main.go @@ -23,15 +23,22 @@ import ( "log" "os" "os/signal" + "path/filepath" + "runtime" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/comms" + rpc "github.com/ethereum/go-ethereum/rpc/v2" "github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/whisper" "github.com/ethereum/go-ethereum/xeth" @@ -81,9 +88,14 @@ func main() { } log.Println("Initial test suite passed...") + if err := StartIPC(stack); err != nil { + log.Fatalf("Failed to start IPC interface: %v\n", err) + } + log.Println("IPC Interface started, accepting requests...") + // Start the RPC interface and wait until terminated if err := StartRPC(stack); err != nil { - log.Fatalf("Failed to start RPC instarface: %v", err) + log.Fatalf("Failed to start RPC interface: %v", err) } log.Println("RPC Interface started, accepting requests...") @@ -177,3 +189,54 @@ func StartRPC(stack *node.Node) error { } return comms.StartHttp(config, codec, api.Merge(apis...)) } + +// StartRPC initializes an IPC interface to the given protocol stack. +func StartIPC(stack *node.Node) error { + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + return err + } + + endpoint := `\\.\pipe\geth.ipc` + if runtime.GOOS != "windows" { + endpoint = filepath.Join(common.DefaultDataDir(), "geth.ipc") + } + + config := comms.IpcConfig{ + Endpoint: endpoint, + } + + listener, err := comms.CreateListener(config) + if err != nil { + return err + } + + server := rpc.NewServer() + + // register package API's this node provides + offered := stack.RPCAPIs() + for _, api := range offered { + server.RegisterName(api.Namespace, api.Service) + glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace) + } + + web3 := utils.NewPublicWeb3API(stack) + server.RegisterName("web3", web3) + net := utils.NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) + server.RegisterName("net", net) + + go func() { + glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint) + for { + conn, err := listener.Accept() + if err != nil { + glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err) + } + + codec := rpc.NewJSONCodec(conn) + go server.ServeCodec(codec) + } + }() + + return nil +} diff --git a/cmd/utils/api.go b/cmd/utils/api.go new file mode 100644 index 000000000..59f0dab74 --- /dev/null +++ b/cmd/utils/api.go @@ -0,0 +1,74 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package utils + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +// PublicWeb3API offers helper utils +type PublicWeb3API struct { + stack *node.Node +} + +// NewPublicWeb3API creates a new Web3Service instance +func NewPublicWeb3API(stack *node.Node) *PublicWeb3API { + return &PublicWeb3API{stack} +} + +// ClientVersion returns the node name +func (s *PublicWeb3API) ClientVersion() string { + return s.stack.Server().Name +} + +// Sha3 applies the ethereum sha3 implementation on the input. +// It assumes the input is hex encoded. +func (s *PublicWeb3API) Sha3(input string) string { + return common.ToHex(crypto.Sha3(common.FromHex(input))) +} + +// PublicNetAPI offers network related RPC methods +type PublicNetAPI struct { + net *p2p.Server + networkVersion int +} + +// NewPublicNetAPI creates a new net api instance. +func NewPublicNetAPI(net *p2p.Server, networkVersion int) *PublicNetAPI { + return &PublicNetAPI{net, networkVersion} +} + +// Listening returns an indication if the node is listening for network connections. +func (s *PublicNetAPI) Listening() bool { + return true // always listening +} + +// Peercount returns the number of connected peers +func (s *PublicNetAPI) PeerCount() *rpc.HexNumber { + return rpc.NewHexNumber(s.net.PeerCount()) +} + +// ProtocolVersion returns the current ethereum protocol version. +func (s *PublicNetAPI) Version() string { + return fmt.Sprintf("%d", s.networkVersion) +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 839ec3f02..1aa8f4e89 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -54,6 +54,7 @@ import ( "github.com/ethereum/go-ethereum/rpc/comms" "github.com/ethereum/go-ethereum/rpc/shared" "github.com/ethereum/go-ethereum/rpc/useragent" + rpc "github.com/ethereum/go-ethereum/rpc/v2" "github.com/ethereum/go-ethereum/whisper" "github.com/ethereum/go-ethereum/xeth" ) @@ -300,6 +301,10 @@ var ( Usage: "Filename for IPC socket/pipe", Value: DirectoryString{common.DefaultIpcPath()}, } + IPCExperimental = cli.BoolFlag{ + Name: "ipcexp", + Usage: "Enable the new RPC implementation", + } ExecFlag = cli.StringFlag{ Name: "exec", Usage: "Execute JavaScript statement (only in combination with console/attach)", @@ -690,6 +695,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. Fatalf("Failed to register the Whisper service: %v", err) } } + return stack } @@ -773,17 +779,53 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) { return } -// StartIPC starts a IPC JSON-RPC API server. func StartIPC(stack *node.Node, ctx *cli.Context) error { config := comms.IpcConfig{ Endpoint: IpcSocketPath(ctx), } - initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { - var ethereum *eth.Ethereum - if err := stack.Service(ðereum); err != nil { - return nil, nil, err + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + return err + } + + if ctx.GlobalIsSet(IPCExperimental.Name) { + listener, err := comms.CreateListener(config) + if err != nil { + return err + } + + server := rpc.NewServer() + + // register package API's this node provides + offered := stack.RPCAPIs() + for _, api := range offered { + server.RegisterName(api.Namespace, api.Service) + glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) } + + web3 := NewPublicWeb3API(stack) + server.RegisterName("web3", web3) + net := NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) + server.RegisterName("net", net) + + go func() { + glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint) + for { + conn, err := listener.Accept() + if err != nil { + glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err) + } + + codec := rpc.NewJSONCodec(conn) + go server.ServeCodec(codec) + } + }() + + return nil + } + + initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { fe := useragent.NewRemoteFrontend(conn, ethereum.AccountManager()) xeth := xeth.New(stack, fe) apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec.JSON, xeth, stack) |