Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
188ab928
Commit
188ab928
authored
Feb 02, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd, common, node, rpc: move IPC into the node itself
parent
3274db19
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
292 additions
and
156 deletions
+292
-156
main.go
cmd/geth/main.go
+1
-6
monitorcmd.go
cmd/geth/monitorcmd.go
+2
-2
main.go
cmd/gethrpctest/main.go
+2
-59
client.go
cmd/utils/client.go
+1
-3
flags.go
cmd/utils/flags.go
+12
-59
path.go
common/path.go
+4
-5
config.go
node/config.go
+40
-0
config_test.go
node/config_test.go
+32
-0
node.go
node/node.go
+92
-8
node_example_test.go
node/node_example_test.go
+1
-0
node_test.go
node/node_test.go
+90
-11
service_test.go
node/service_test.go
+1
-1
utils_test.go
node/utils_test.go
+13
-1
json.go
rpc/json.go
+1
-1
No files found.
cmd/geth/main.go
View file @
188ab928
...
@@ -502,12 +502,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
...
@@ -502,12 +502,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
unlockAccount
(
ctx
,
accman
,
trimmed
,
i
,
passwords
)
unlockAccount
(
ctx
,
accman
,
trimmed
,
i
,
passwords
)
}
}
}
}
// Start auxiliary services if enabled.
// Start auxiliary services if enabled
if
!
ctx
.
GlobalBool
(
utils
.
IPCDisabledFlag
.
Name
)
{
if
err
:=
utils
.
StartIPC
(
stack
,
ctx
);
err
!=
nil
{
utils
.
Fatalf
(
"Failed to start IPC: %v"
,
err
)
}
}
if
ctx
.
GlobalBool
(
utils
.
RPCEnabledFlag
.
Name
)
{
if
ctx
.
GlobalBool
(
utils
.
RPCEnabledFlag
.
Name
)
{
if
err
:=
utils
.
StartRPC
(
stack
,
ctx
);
err
!=
nil
{
if
err
:=
utils
.
StartRPC
(
stack
,
ctx
);
err
!=
nil
{
utils
.
Fatalf
(
"Failed to start RPC: %v"
,
err
)
utils
.
Fatalf
(
"Failed to start RPC: %v"
,
err
)
...
...
cmd/geth/monitorcmd.go
View file @
188ab928
...
@@ -28,7 +28,7 @@ import (
...
@@ -28,7 +28,7 @@ import (
"github.com/codegangsta/cli"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/
common
"
"github.com/ethereum/go-ethereum/
node
"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gizak/termui"
"github.com/gizak/termui"
)
)
...
@@ -36,7 +36,7 @@ import (
...
@@ -36,7 +36,7 @@ import (
var
(
var
(
monitorCommandAttachFlag
=
cli
.
StringFlag
{
monitorCommandAttachFlag
=
cli
.
StringFlag
{
Name
:
"attach"
,
Name
:
"attach"
,
Value
:
"ipc:"
+
common
.
DefaultIpcPath
(),
Value
:
"ipc:"
+
node
.
DefaultIpcEndpoint
(),
Usage
:
"API endpoint to attach to"
,
Usage
:
"API endpoint to attach to"
,
}
}
monitorCommandRowsFlag
=
cli
.
IntFlag
{
monitorCommandRowsFlag
=
cli
.
IntFlag
{
...
...
cmd/gethrpctest/main.go
View file @
188ab928
...
@@ -18,25 +18,20 @@
...
@@ -18,25 +18,20 @@
package
main
package
main
import
(
import
(
"errors"
"flag"
"flag"
"io/ioutil"
"io/ioutil"
"log"
"log"
"os"
"os"
"os/signal"
"os/signal"
"path/filepath"
"runtime"
"errors"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb"
"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/node"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/tests"
"github.com/ethereum/go-ethereum/tests"
"github.com/ethereum/go-ethereum/whisper"
"github.com/ethereum/go-ethereum/whisper"
)
)
...
@@ -89,11 +84,6 @@ func main() {
...
@@ -89,11 +84,6 @@ func main() {
}
}
log
.
Println
(
"Initial test suite passed..."
)
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
// Start the RPC interface and wait until terminated
if
err
:=
StartRPC
(
stack
);
err
!=
nil
{
if
err
:=
StartRPC
(
stack
);
err
!=
nil
{
log
.
Fatalf
(
"Failed to start RPC interface: %v"
,
err
)
log
.
Fatalf
(
"Failed to start RPC interface: %v"
,
err
)
...
@@ -109,7 +99,7 @@ func main() {
...
@@ -109,7 +99,7 @@ func main() {
// keystore path and initial pre-state.
// keystore path and initial pre-state.
func
MakeSystemNode
(
keydir
string
,
privkey
string
,
test
*
tests
.
BlockTest
)
(
*
node
.
Node
,
error
)
{
func
MakeSystemNode
(
keydir
string
,
privkey
string
,
test
*
tests
.
BlockTest
)
(
*
node
.
Node
,
error
)
{
// Create a networkless protocol stack
// Create a networkless protocol stack
stack
,
err
:=
node
.
New
(
&
node
.
Config
{
NoDiscovery
:
true
})
stack
,
err
:=
node
.
New
(
&
node
.
Config
{
IpcPath
:
node
.
DefaultIpcEndpoint
(),
NoDiscovery
:
true
})
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
@@ -194,50 +184,3 @@ func StartRPC(stack *node.Node) error {
...
@@ -194,50 +184,3 @@ func StartRPC(stack *node.Node) error {
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Unable to start RPC-HTTP interface, could not find admin API"
)
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Unable to start RPC-HTTP interface, could not find admin API"
)
return
errors
.
New
(
"Unable to start RPC-HTTP interface"
)
return
errors
.
New
(
"Unable to start RPC-HTTP interface"
)
}
}
// StartIPC initializes an IPC interface to the given protocol stack.
func
StartIPC
(
stack
*
node
.
Node
)
error
{
var
ethereum
*
eth
.
Ethereum
if
err
:=
stack
.
Service
(
&
ethereum
);
err
!=
nil
{
return
err
}
endpoint
:=
`\\.\pipe\geth.ipc`
if
runtime
.
GOOS
!=
"windows"
{
endpoint
=
filepath
.
Join
(
common
.
DefaultDataDir
(),
"geth.ipc"
)
}
listener
,
err
:=
rpc
.
CreateIPCListener
(
endpoint
)
if
err
!=
nil
{
return
err
}
server
:=
rpc
.
NewServer
()
// register package API's this node provides
offered
:=
stack
.
APIs
()
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
)
}
//var ethereum *eth.Ethereum
//if err := stack.Service(ðereum); err != nil {
// return err
//}
go
func
()
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Start IPC server on %s
\n
"
,
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
}
cmd/utils/client.go
View file @
188ab928
...
@@ -150,10 +150,8 @@ func NewRemoteRPCClient(ctx *cli.Context) (rpc.Client, error) {
...
@@ -150,10 +150,8 @@ func NewRemoteRPCClient(ctx *cli.Context) (rpc.Client, error) {
endpoint
:=
ctx
.
Args
()
.
First
()
endpoint
:=
ctx
.
Args
()
.
First
()
return
NewRemoteRPCClientFromString
(
endpoint
)
return
NewRemoteRPCClientFromString
(
endpoint
)
}
}
// use IPC by default
// use IPC by default
endpoint
:=
IPCSocketPath
(
ctx
)
return
rpc
.
NewIPCClient
(
node
.
DefaultIpcEndpoint
())
return
rpc
.
NewIPCClient
(
endpoint
)
}
}
// NewRemoteRPCClientFromString returns a RPC client which connects to the given
// NewRemoteRPCClientFromString returns a RPC client which connects to the given
...
...
cmd/utils/flags.go
View file @
188ab928
...
@@ -261,8 +261,8 @@ var (
...
@@ -261,8 +261,8 @@ var (
}
}
IPCPathFlag
=
DirectoryFlag
{
IPCPathFlag
=
DirectoryFlag
{
Name
:
"ipcpath"
,
Name
:
"ipcpath"
,
Usage
:
"Filename for IPC socket/pipe"
,
Usage
:
"Filename for IPC socket/pipe
within the datadir (explicit paths escape it)
"
,
Value
:
DirectoryString
{
common
.
DefaultIpc
Path
()},
Value
:
DirectoryString
{
common
.
DefaultIpc
Socket
()},
}
}
WSEnabledFlag
=
cli
.
BoolFlag
{
WSEnabledFlag
=
cli
.
BoolFlag
{
Name
:
"ws"
,
Name
:
"ws"
,
...
@@ -394,6 +394,15 @@ func MustMakeDataDir(ctx *cli.Context) string {
...
@@ -394,6 +394,15 @@ func MustMakeDataDir(ctx *cli.Context) string {
return
""
return
""
}
}
// MakeIpcPath creates an IPC path configuration from the set command line flags,
// returning an empty string if IPC was explicitly disabled, or the set path.
func
MakeIpcPath
(
ctx
*
cli
.
Context
)
string
{
if
ctx
.
GlobalBool
(
IPCDisabledFlag
.
Name
)
{
return
""
}
return
ctx
.
GlobalString
(
IPCPathFlag
.
Name
)
}
// MakeNodeKey creates a node key from set command line flags, either loading it
// MakeNodeKey creates a node key from set command line flags, either loading it
// from a file or as a specified hex value. If neither flags were provided, this
// from a file or as a specified hex value. If neither flags were provided, this
// method returns nil and an emphemeral key is to be generated.
// method returns nil and an emphemeral key is to be generated.
...
@@ -582,6 +591,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.
...
@@ -582,6 +591,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.
// Configure the node's service container
// Configure the node's service container
stackConf
:=
&
node
.
Config
{
stackConf
:=
&
node
.
Config
{
DataDir
:
MustMakeDataDir
(
ctx
),
DataDir
:
MustMakeDataDir
(
ctx
),
IpcPath
:
MakeIpcPath
(
ctx
),
PrivateKey
:
MakeNodeKey
(
ctx
),
PrivateKey
:
MakeNodeKey
(
ctx
),
Name
:
MakeNodeName
(
name
,
version
,
ctx
),
Name
:
MakeNodeName
(
name
,
version
,
ctx
),
NoDiscovery
:
ctx
.
GlobalBool
(
NoDiscoverFlag
.
Name
),
NoDiscovery
:
ctx
.
GlobalBool
(
NoDiscoverFlag
.
Name
),
...
@@ -734,63 +744,6 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database
...
@@ -734,63 +744,6 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database
return
chain
,
chainDb
return
chain
,
chainDb
}
}
func
IPCSocketPath
(
ctx
*
cli
.
Context
)
(
ipcpath
string
)
{
if
runtime
.
GOOS
==
"windows"
{
ipcpath
=
common
.
DefaultIpcPath
()
if
ctx
.
GlobalIsSet
(
IPCPathFlag
.
Name
)
{
ipcpath
=
ctx
.
GlobalString
(
IPCPathFlag
.
Name
)
}
}
else
{
ipcpath
=
common
.
DefaultIpcPath
()
if
ctx
.
GlobalIsSet
(
DataDirFlag
.
Name
)
{
ipcpath
=
filepath
.
Join
(
ctx
.
GlobalString
(
DataDirFlag
.
Name
),
"geth.ipc"
)
}
if
ctx
.
GlobalIsSet
(
IPCPathFlag
.
Name
)
{
ipcpath
=
ctx
.
GlobalString
(
IPCPathFlag
.
Name
)
}
}
return
}
func
StartIPC
(
stack
*
node
.
Node
,
ctx
*
cli
.
Context
)
error
{
var
ethereum
*
eth
.
Ethereum
if
err
:=
stack
.
Service
(
&
ethereum
);
err
!=
nil
{
return
err
}
endpoint
:=
IPCSocketPath
(
ctx
)
listener
,
err
:=
rpc
.
CreateIPCListener
(
endpoint
)
if
err
!=
nil
{
return
err
}
server
:=
rpc
.
NewServer
()
// register package API's this node provides
offered
:=
stack
.
APIs
()
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
)
}
go
func
()
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Start IPC server on %s
\n
"
,
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
}
// StartRPC starts a HTTP JSON-RPC API server.
// StartRPC starts a HTTP JSON-RPC API server.
func
StartRPC
(
stack
*
node
.
Node
,
ctx
*
cli
.
Context
)
error
{
func
StartRPC
(
stack
*
node
.
Node
,
ctx
*
cli
.
Context
)
error
{
for
_
,
api
:=
range
stack
.
APIs
()
{
for
_
,
api
:=
range
stack
.
APIs
()
{
...
...
common/path.go
View file @
188ab928
...
@@ -89,9 +89,8 @@ func DefaultDataDir() string {
...
@@ -89,9 +89,8 @@ func DefaultDataDir() string {
return
""
return
""
}
}
func
DefaultIpcPath
()
string
{
// DefaultIpcSocket returns the relative name of the default IPC socket. The path
if
runtime
.
GOOS
==
"windows"
{
// resolution is done by a node with other contextual infos.
return
`\\.\pipe\geth.ipc`
func
DefaultIpcSocket
()
string
{
}
return
"geth.ipc"
return
filepath
.
Join
(
DefaultDataDir
(),
"geth.ipc"
)
}
}
node/config.go
View file @
188ab928
...
@@ -23,7 +23,10 @@ import (
...
@@ -23,7 +23,10 @@ import (
"net"
"net"
"os"
"os"
"path/filepath"
"path/filepath"
"runtime"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"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"
...
@@ -49,6 +52,12 @@ type Config struct {
...
@@ -49,6 +52,12 @@ type Config struct {
// in memory.
// in memory.
DataDir
string
DataDir
string
// IpcPath is the requested location to place the IPC endpoint. If the path is
// a simple file name, it is placed inside the data directory (or on the root
// pipe path on Windows), whereas if it's a resolvable path name (absolute or
// relative), then that specific path is enforced. An empty path disables IPC.
IpcPath
string
// This field should be a valid secp256k1 private key that will be used for both
// This field should be a valid secp256k1 private key that will be used for both
// remote peer identification as well as network traffic encryption. If no key
// remote peer identification as well as network traffic encryption. If no key
// is configured, the preset one is loaded from the data dir, generating it if
// is configured, the preset one is loaded from the data dir, generating it if
...
@@ -90,6 +99,37 @@ type Config struct {
...
@@ -90,6 +99,37 @@ type Config struct {
MaxPendingPeers
int
MaxPendingPeers
int
}
}
// IpcEndpoint resolves an IPC endpoint based on a configured value, taking into
// account the set data folders as well as the designated platform we're currently
// running on.
func
(
c
*
Config
)
IpcEndpoint
()
string
{
// Short circuit if IPC has not been enabled
if
c
.
IpcPath
==
""
{
return
""
}
// On windows we can only use plain top-level pipes
if
runtime
.
GOOS
==
"windows"
{
if
strings
.
HasPrefix
(
c
.
IpcPath
,
`\\.\pipe\`
)
{
return
c
.
IpcPath
}
return
`\\.\pipe\`
+
c
.
IpcPath
}
// Resolve names into the data directory full paths otherwise
if
filepath
.
Base
(
c
.
IpcPath
)
==
c
.
IpcPath
{
if
c
.
DataDir
==
""
{
return
filepath
.
Join
(
os
.
TempDir
(),
c
.
IpcPath
)
}
return
filepath
.
Join
(
c
.
DataDir
,
c
.
IpcPath
)
}
return
c
.
IpcPath
}
// DefaultIpcEndpoint returns the IPC path used by default.
func
DefaultIpcEndpoint
()
string
{
config
:=
&
Config
{
DataDir
:
common
.
DefaultDataDir
(),
IpcPath
:
common
.
DefaultIpcSocket
()}
return
config
.
IpcEndpoint
()
}
// NodeKey retrieves the currently configured private key of the node, checking
// NodeKey retrieves the currently configured private key of the node, checking
// first any manually set key, falling back to the one found in the configured
// first any manually set key, falling back to the one found in the configured
// data folder. If no key can be found, a new one is generated.
// data folder. If no key can be found, a new one is generated.
...
...
node/config_test.go
View file @
188ab928
...
@@ -21,6 +21,7 @@ import (
...
@@ -21,6 +21,7 @@ import (
"io/ioutil"
"io/ioutil"
"os"
"os"
"path/filepath"
"path/filepath"
"runtime"
"testing"
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
...
@@ -60,6 +61,37 @@ func TestDatadirCreation(t *testing.T) {
...
@@ -60,6 +61,37 @@ func TestDatadirCreation(t *testing.T) {
}
}
}
}
// Tests that IPC paths are correctly resolved to valid endpoints of different
// platforms.
func
TestIpcPathResolution
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
DataDir
string
IpcPath
string
Windows
bool
Endpoint
string
}{
{
""
,
""
,
false
,
""
},
{
"data"
,
""
,
false
,
""
},
{
""
,
"geth.ipc"
,
false
,
filepath
.
Join
(
os
.
TempDir
(),
"geth.ipc"
)},
{
"data"
,
"geth.ipc"
,
false
,
"data/geth.ipc"
},
{
"data"
,
"./geth.ipc"
,
false
,
"./geth.ipc"
},
{
"data"
,
"/geth.ipc"
,
false
,
"/geth.ipc"
},
{
""
,
""
,
true
,
``
},
{
"data"
,
""
,
true
,
``
},
{
""
,
"geth.ipc"
,
true
,
`\\.\pipe\geth.ipc`
},
{
"data"
,
"geth.ipc"
,
true
,
`\\.\pipe\geth.ipc`
},
{
"data"
,
`\\.\pipe\geth.ipc`
,
true
,
`\\.\pipe\geth.ipc`
},
}
for
i
,
test
:=
range
tests
{
// Only run when platform/test match
if
(
runtime
.
GOOS
==
"windows"
)
==
test
.
Windows
{
if
endpoint
:=
(
&
Config
{
DataDir
:
test
.
DataDir
,
IpcPath
:
test
.
IpcPath
})
.
IpcEndpoint
();
endpoint
!=
test
.
Endpoint
{
t
.
Errorf
(
"test %d: IPC endpoint mismatch: have %s, want %s"
,
i
,
endpoint
,
test
.
Endpoint
)
}
}
}
}
// Tests that node keys can be correctly created, persisted, loaded and/or made
// Tests that node keys can be correctly created, persisted, loaded and/or made
// ephemeral.
// ephemeral.
func
TestNodeKeyPersistency
(
t
*
testing
.
T
)
{
func
TestNodeKeyPersistency
(
t
*
testing
.
T
)
{
...
...
node/node.go
View file @
188ab928
...
@@ -19,6 +19,7 @@ package node
...
@@ -19,6 +19,7 @@ package node
import
(
import
(
"errors"
"errors"
"net"
"os"
"os"
"path/filepath"
"path/filepath"
"reflect"
"reflect"
...
@@ -27,6 +28,8 @@ import (
...
@@ -27,6 +28,8 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc"
)
)
...
@@ -52,6 +55,10 @@ type Node struct {
...
@@ -52,6 +55,10 @@ type Node struct {
serviceFuncs
[]
ServiceConstructor
// Service constructors (in dependency order)
serviceFuncs
[]
ServiceConstructor
// Service constructors (in dependency order)
services
map
[
reflect
.
Type
]
Service
// Currently running services
services
map
[
reflect
.
Type
]
Service
// Currently running services
ipcEndpoint
string
// IPC endpoint to listen at (empty = IPC disabled)
ipcListener
net
.
Listener
// IPC RPC listener socket to serve API requests
ipcHandler
*
rpc
.
Server
// IPC RPC request handler to process the API requests
stop
chan
struct
{}
// Channel to wait for termination notifications
stop
chan
struct
{}
// Channel to wait for termination notifications
lock
sync
.
RWMutex
lock
sync
.
RWMutex
}
}
...
@@ -87,6 +94,7 @@ func New(conf *Config) (*Node, error) {
...
@@ -87,6 +94,7 @@ func New(conf *Config) (*Node, error) {
MaxPendingPeers
:
conf
.
MaxPendingPeers
,
MaxPendingPeers
:
conf
.
MaxPendingPeers
,
},
},
serviceFuncs
:
[]
ServiceConstructor
{},
serviceFuncs
:
[]
ServiceConstructor
{},
ipcEndpoint
:
conf
.
IpcEndpoint
(),
eventmux
:
new
(
event
.
TypeMux
),
eventmux
:
new
(
event
.
TypeMux
),
},
nil
},
nil
}
}
...
@@ -164,6 +172,14 @@ func (n *Node) Start() error {
...
@@ -164,6 +172,14 @@ func (n *Node) Start() error {
// Mark the service started for potential cleanup
// Mark the service started for potential cleanup
started
=
append
(
started
,
kind
)
started
=
append
(
started
,
kind
)
}
}
// Lastly start the configured RPC interfaces
if
err
:=
n
.
startRPC
(
services
);
err
!=
nil
{
for
_
,
service
:=
range
services
{
service
.
Stop
()
}
running
.
Stop
()
return
err
}
// Finish initializing the startup
// Finish initializing the startup
n
.
services
=
services
n
.
services
=
services
n
.
server
=
running
n
.
server
=
running
...
@@ -172,6 +188,58 @@ func (n *Node) Start() error {
...
@@ -172,6 +188,58 @@ func (n *Node) Start() error {
return
nil
return
nil
}
}
// startRPC initializes and starts the IPC RPC endpoints.
func
(
n
*
Node
)
startRPC
(
services
map
[
reflect
.
Type
]
Service
)
error
{
// Gather and register all the APIs exposed by the services
apis
:=
n
.
apis
()
for
_
,
service
:=
range
services
{
apis
=
append
(
apis
,
service
.
APIs
()
...
)
}
ipcHandler
:=
rpc
.
NewServer
()
for
_
,
api
:=
range
apis
{
if
err
:=
ipcHandler
.
RegisterName
(
api
.
Namespace
,
api
.
Service
);
err
!=
nil
{
return
err
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"Register %T under namespace '%s'"
,
api
.
Service
,
api
.
Namespace
)
}
// All APIs registered, start the IPC and HTTP listeners
var
(
ipcListener
net
.
Listener
err
error
)
if
n
.
ipcEndpoint
!=
""
{
if
ipcListener
,
err
=
rpc
.
CreateIPCListener
(
n
.
ipcEndpoint
);
err
!=
nil
{
return
err
}
go
func
()
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC endpoint opened: %s"
,
n
.
ipcEndpoint
)
defer
glog
.
V
(
logger
.
Info
)
.
Infof
(
"IPC endpoint closed: %s"
,
n
.
ipcEndpoint
)
for
{
conn
,
err
:=
ipcListener
.
Accept
()
if
err
!=
nil
{
// Terminate if the listener was closed
n
.
lock
.
RLock
()
closed
:=
n
.
ipcListener
==
nil
n
.
lock
.
RUnlock
()
if
closed
{
return
}
// Not closed, just some error; report and continue
glog
.
V
(
logger
.
Error
)
.
Infof
(
"IPC accept failed: %v"
,
err
)
continue
}
go
ipcHandler
.
ServeCodec
(
rpc
.
NewJSONCodec
(
conn
))
}
}()
}
// All listeners booted successfully
n
.
ipcListener
=
ipcListener
n
.
ipcHandler
=
ipcHandler
return
nil
}
// Stop terminates a running node along with all it's services. In the node was
// Stop terminates a running node along with all it's services. In the node was
// not started, an error is returned.
// not started, an error is returned.
func
(
n
*
Node
)
Stop
()
error
{
func
(
n
*
Node
)
Stop
()
error
{
...
@@ -182,7 +250,15 @@ func (n *Node) Stop() error {
...
@@ -182,7 +250,15 @@ func (n *Node) Stop() error {
if
n
.
server
==
nil
{
if
n
.
server
==
nil
{
return
ErrNodeStopped
return
ErrNodeStopped
}
}
// Otherwise terminate all the services and the P2P server too
// Otherwise terminate the API, all services and the P2P server too
if
n
.
ipcListener
!=
nil
{
n
.
ipcListener
.
Close
()
n
.
ipcListener
=
nil
}
if
n
.
ipcHandler
!=
nil
{
n
.
ipcHandler
.
Stop
()
n
.
ipcHandler
=
nil
}
failure
:=
&
StopError
{
failure
:=
&
StopError
{
Services
:
make
(
map
[
reflect
.
Type
]
error
),
Services
:
make
(
map
[
reflect
.
Type
]
error
),
}
}
...
@@ -261,18 +337,20 @@ func (n *Node) DataDir() string {
...
@@ -261,18 +337,20 @@ func (n *Node) DataDir() string {
return
n
.
datadir
return
n
.
datadir
}
}
// IpcEndpoint retrieves the current IPC endpoint used by the protocol stack.
func
(
n
*
Node
)
IpcEndpoint
()
string
{
return
n
.
ipcEndpoint
}
// EventMux retrieves the event multiplexer used by all the network services in
// EventMux retrieves the event multiplexer used by all the network services in
// the current protocol stack.
// the current protocol stack.
func
(
n
*
Node
)
EventMux
()
*
event
.
TypeMux
{
func
(
n
*
Node
)
EventMux
()
*
event
.
TypeMux
{
return
n
.
eventmux
return
n
.
eventmux
}
}
// APIs returns the collection of RPC descriptor this node offers. This method
// apis returns the collection of RPC descriptors this node offers.
// is just a quick placeholder passthrough for the RPC update, which in the next
func
(
n
*
Node
)
apis
()
[]
rpc
.
API
{
// step will be fully integrated into the node itself.
return
[]
rpc
.
API
{
func
(
n
*
Node
)
APIs
()
[]
rpc
.
API
{
// Define all the APIs owned by the node itself
apis
:=
[]
rpc
.
API
{
{
{
Namespace
:
"admin"
,
Namespace
:
"admin"
,
Version
:
"1.0"
,
Version
:
"1.0"
,
...
@@ -298,7 +376,13 @@ func (n *Node) APIs() []rpc.API {
...
@@ -298,7 +376,13 @@ func (n *Node) APIs() []rpc.API {
Public
:
true
,
Public
:
true
,
},
},
}
}
// Inject all the APIs owned by various services
}
// APIs returns the collection of RPC descriptor this node offers. This method
// is just a quick placeholder passthrough for the RPC update, which in the next
// step will be fully integrated into the node itself.
func
(
n
*
Node
)
APIs
()
[]
rpc
.
API
{
apis
:=
n
.
apis
()
for
_
,
api
:=
range
n
.
services
{
for
_
,
api
:=
range
n
.
services
{
apis
=
append
(
apis
,
api
.
APIs
()
...
)
apis
=
append
(
apis
,
api
.
APIs
()
...
)
}
}
...
...
node/node_example_test.go
View file @
188ab928
...
@@ -31,6 +31,7 @@ import (
...
@@ -31,6 +31,7 @@ import (
//
//
// The following methods are needed to implement a node.Service:
// The following methods are needed to implement a node.Service:
// - Protocols() []p2p.Protocol - devp2p protocols the service can communicate on
// - Protocols() []p2p.Protocol - devp2p protocols the service can communicate on
// - APIs() []rpc.API - api methods the service wants to expose on rpc channels
// - Start() error - method invoked when the node is ready to start the service
// - Start() error - method invoked when the node is ready to start the service
// - Stop() error - method invoked when the node terminates the service
// - Stop() error - method invoked when the node terminates the service
type
SampleService
struct
{}
type
SampleService
struct
{}
...
...
node/node_test.go
View file @
188ab928
...
@@ -18,27 +18,34 @@ package node
...
@@ -18,27 +18,34 @@ package node
import
(
import
(
"errors"
"errors"
"fmt"
"io/ioutil"
"io/ioutil"
"math/rand"
"os"
"os"
"reflect"
"reflect"
"testing"
"testing"
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
)
)
var
(
var
(
testNodeKey
,
_
=
crypto
.
GenerateKey
()
testNodeKey
,
_
=
crypto
.
GenerateKey
()
)
testNodeConfig
=
&
Config
{
func
testNodeConfig
()
*
Config
{
return
&
Config
{
IpcPath
:
fmt
.
Sprintf
(
"test-%d.ipc"
,
rand
.
Int63
()),
PrivateKey
:
testNodeKey
,
PrivateKey
:
testNodeKey
,
Name
:
"test node"
,
Name
:
"test node"
,
}
}
)
}
// Tests that an empty protocol stack can be started, restarted and stopped.
// Tests that an empty protocol stack can be started, restarted and stopped.
func
TestNodeLifeCycle
(
t
*
testing
.
T
)
{
func
TestNodeLifeCycle
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -101,7 +108,7 @@ func TestNodeUsedDataDir(t *testing.T) {
...
@@ -101,7 +108,7 @@ func TestNodeUsedDataDir(t *testing.T) {
// Tests whether services can be registered and duplicates caught.
// Tests whether services can be registered and duplicates caught.
func
TestServiceRegistry
(
t
*
testing
.
T
)
{
func
TestServiceRegistry
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -133,7 +140,7 @@ func TestServiceRegistry(t *testing.T) {
...
@@ -133,7 +140,7 @@ func TestServiceRegistry(t *testing.T) {
// Tests that registered services get started and stopped correctly.
// Tests that registered services get started and stopped correctly.
func
TestServiceLifeCycle
(
t
*
testing
.
T
)
{
func
TestServiceLifeCycle
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -183,7 +190,7 @@ func TestServiceLifeCycle(t *testing.T) {
...
@@ -183,7 +190,7 @@ func TestServiceLifeCycle(t *testing.T) {
// Tests that services are restarted cleanly as new instances.
// Tests that services are restarted cleanly as new instances.
func
TestServiceRestarts
(
t
*
testing
.
T
)
{
func
TestServiceRestarts
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -231,7 +238,7 @@ func TestServiceRestarts(t *testing.T) {
...
@@ -231,7 +238,7 @@ func TestServiceRestarts(t *testing.T) {
// Tests that if a service fails to initialize itself, none of the other services
// Tests that if a service fails to initialize itself, none of the other services
// will be allowed to even start.
// will be allowed to even start.
func
TestServiceConstructionAbortion
(
t
*
testing
.
T
)
{
func
TestServiceConstructionAbortion
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -278,7 +285,7 @@ func TestServiceConstructionAbortion(t *testing.T) {
...
@@ -278,7 +285,7 @@ func TestServiceConstructionAbortion(t *testing.T) {
// Tests that if a service fails to start, all others started before it will be
// Tests that if a service fails to start, all others started before it will be
// shut down.
// shut down.
func
TestServiceStartupAbortion
(
t
*
testing
.
T
)
{
func
TestServiceStartupAbortion
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -331,7 +338,7 @@ func TestServiceStartupAbortion(t *testing.T) {
...
@@ -331,7 +338,7 @@ func TestServiceStartupAbortion(t *testing.T) {
// Tests that even if a registered service fails to shut down cleanly, it does
// Tests that even if a registered service fails to shut down cleanly, it does
// not influece the rest of the shutdown invocations.
// not influece the rest of the shutdown invocations.
func
TestServiceTerminationGuarantee
(
t
*
testing
.
T
)
{
func
TestServiceTerminationGuarantee
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -406,7 +413,7 @@ func TestServiceTerminationGuarantee(t *testing.T) {
...
@@ -406,7 +413,7 @@ func TestServiceTerminationGuarantee(t *testing.T) {
// TestServiceRetrieval tests that individual services can be retrieved.
// TestServiceRetrieval tests that individual services can be retrieved.
func
TestServiceRetrieval
(
t
*
testing
.
T
)
{
func
TestServiceRetrieval
(
t
*
testing
.
T
)
{
// Create a simple stack and register two service types
// Create a simple stack and register two service types
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -441,7 +448,7 @@ func TestServiceRetrieval(t *testing.T) {
...
@@ -441,7 +448,7 @@ func TestServiceRetrieval(t *testing.T) {
// Tests that all protocols defined by individual services get launched.
// Tests that all protocols defined by individual services get launched.
func
TestProtocolGather
(
t
*
testing
.
T
)
{
func
TestProtocolGather
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
@@ -494,3 +501,75 @@ func TestProtocolGather(t *testing.T) {
...
@@ -494,3 +501,75 @@ func TestProtocolGather(t *testing.T) {
}
}
}
}
}
}
// Tests that all APIs defined by individual services get exposed.
func
TestAPIGather
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
())
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
// Register a batch of services with some configured APIs
calls
:=
make
(
chan
string
,
1
)
services
:=
map
[
string
]
struct
{
APIs
[]
rpc
.
API
Maker
InstrumentingWrapper
}{
"Zero APIs"
:
{[]
rpc
.
API
{},
InstrumentedServiceMakerA
},
"Single API"
:
{[]
rpc
.
API
{
{
"single"
,
"1"
,
&
OneMethodApi
{
fun
:
func
()
{
calls
<-
"single.v1"
}},
true
},
},
InstrumentedServiceMakerB
},
"Many APIs"
:
{[]
rpc
.
API
{
{
"multi"
,
"1"
,
&
OneMethodApi
{
fun
:
func
()
{
calls
<-
"multi.v1"
}},
true
},
{
"multi.v2"
,
"2"
,
&
OneMethodApi
{
fun
:
func
()
{
calls
<-
"multi.v2"
}},
true
},
{
"multi.v2.nested"
,
"2"
,
&
OneMethodApi
{
fun
:
func
()
{
calls
<-
"multi.v2.nested"
}},
true
},
},
InstrumentedServiceMakerC
},
}
for
id
,
config
:=
range
services
{
config
:=
config
constructor
:=
func
(
*
ServiceContext
)
(
Service
,
error
)
{
return
&
InstrumentedService
{
apis
:
config
.
APIs
},
nil
}
if
err
:=
stack
.
Register
(
config
.
Maker
(
constructor
));
err
!=
nil
{
t
.
Fatalf
(
"service %s: registration failed: %v"
,
id
,
err
)
}
}
// Start the services and ensure all API start successfully
if
err
:=
stack
.
Start
();
err
!=
nil
{
t
.
Fatalf
(
"failed to start protocol stack: %v"
,
err
)
}
defer
stack
.
Stop
()
// Connect to the RPC server and verify the various registered endpoints
ipcClient
,
err
:=
rpc
.
NewIPCClient
(
stack
.
IpcEndpoint
())
if
err
!=
nil
{
t
.
Fatalf
(
"failed to connect to the IPC API server: %v"
,
err
)
}
tests
:=
[]
struct
{
Method
string
Result
string
}{
{
"single_theOneMethod"
,
"single.v1"
},
{
"multi_theOneMethod"
,
"multi.v1"
},
{
"multi.v2_theOneMethod"
,
"multi.v2"
},
{
"multi.v2.nested_theOneMethod"
,
"multi.v2.nested"
},
}
for
i
,
test
:=
range
tests
{
if
err
:=
ipcClient
.
Send
(
rpc
.
JSONRequest
{
Id
:
new
(
int64
),
Version
:
"2.0"
,
Method
:
test
.
Method
});
err
!=
nil
{
t
.
Fatalf
(
"test %d: failed to send API request: %v"
,
i
,
err
)
}
reply
:=
new
(
rpc
.
JSONSuccessResponse
)
if
err
:=
ipcClient
.
Recv
(
reply
);
err
!=
nil
{
t
.
Fatalf
(
"test %d: failed to read API reply: %v"
,
i
,
err
)
}
select
{
case
result
:=
<-
calls
:
if
result
!=
test
.
Result
{
t
.
Errorf
(
"test %d: result mismatch: have %s, want %s"
,
i
,
result
,
test
.
Result
)
}
case
<-
time
.
After
(
time
.
Second
)
:
t
.
Fatalf
(
"test %d: rpc execution timeout"
,
i
)
}
}
}
node/service_test.go
View file @
188ab928
...
@@ -63,7 +63,7 @@ func TestContextDatabases(t *testing.T) {
...
@@ -63,7 +63,7 @@ func TestContextDatabases(t *testing.T) {
// Tests that already constructed services can be retrieves by later ones.
// Tests that already constructed services can be retrieves by later ones.
func
TestContextServices
(
t
*
testing
.
T
)
{
func
TestContextServices
(
t
*
testing
.
T
)
{
stack
,
err
:=
New
(
testNodeConfig
)
stack
,
err
:=
New
(
testNodeConfig
()
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
t
.
Fatalf
(
"failed to create protocol stack: %v"
,
err
)
}
}
...
...
node/utils_test.go
View file @
188ab928
...
@@ -52,6 +52,7 @@ func NewNoopServiceD(*ServiceContext) (Service, error) { return new(NoopServiceD
...
@@ -52,6 +52,7 @@ func NewNoopServiceD(*ServiceContext) (Service, error) { return new(NoopServiceD
// methods can be instrumented both return value as well as event hook wise.
// methods can be instrumented both return value as well as event hook wise.
type
InstrumentedService
struct
{
type
InstrumentedService
struct
{
protocols
[]
p2p
.
Protocol
protocols
[]
p2p
.
Protocol
apis
[]
rpc
.
API
start
error
start
error
stop
error
stop
error
...
@@ -70,7 +71,7 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol {
...
@@ -70,7 +71,7 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol {
}
}
func
(
s
*
InstrumentedService
)
APIs
()
[]
rpc
.
API
{
func
(
s
*
InstrumentedService
)
APIs
()
[]
rpc
.
API
{
return
nil
return
s
.
apis
}
}
func
(
s
*
InstrumentedService
)
Start
(
server
*
p2p
.
Server
)
error
{
func
(
s
*
InstrumentedService
)
Start
(
server
*
p2p
.
Server
)
error
{
...
@@ -121,3 +122,14 @@ func InstrumentedServiceMakerB(base ServiceConstructor) ServiceConstructor {
...
@@ -121,3 +122,14 @@ func InstrumentedServiceMakerB(base ServiceConstructor) ServiceConstructor {
func
InstrumentedServiceMakerC
(
base
ServiceConstructor
)
ServiceConstructor
{
func
InstrumentedServiceMakerC
(
base
ServiceConstructor
)
ServiceConstructor
{
return
InstrumentingWrapperMaker
(
base
,
reflect
.
TypeOf
(
InstrumentedServiceC
{}))
return
InstrumentingWrapperMaker
(
base
,
reflect
.
TypeOf
(
InstrumentedServiceC
{}))
}
}
// OneMethodApi is a single-method API handler to be returned by test services.
type
OneMethodApi
struct
{
fun
func
()
}
func
(
api
*
OneMethodApi
)
TheOneMethod
()
{
if
api
.
fun
!=
nil
{
api
.
fun
()
}
}
rpc/json.go
View file @
188ab928
...
@@ -41,7 +41,7 @@ type JSONRequest struct {
...
@@ -41,7 +41,7 @@ type JSONRequest struct {
Method
string
`json:"method"`
Method
string
`json:"method"`
Version
string
`json:"jsonrpc"`
Version
string
`json:"jsonrpc"`
Id
*
int64
`json:"id,omitempty"`
Id
*
int64
`json:"id,omitempty"`
Payload
json
.
RawMessage
`json:"params"`
Payload
json
.
RawMessage
`json:"params
,omitempty
"`
}
}
// JSON-RPC response
// JSON-RPC response
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment