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
44bc2e80
Commit
44bc2e80
authored
Sep 29, 2016
by
Felix Lange
Committed by
GitHub
Sep 29, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2914 from fjl/node-coinhabit
cmd/utils, node: make datadir reusable for bzzd
parents
4e8cec05
b42a5b11
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
470 additions
and
239 deletions
+470
-239
chaincmd.go
cmd/geth/chaincmd.go
+35
-16
consolecmd.go
cmd/geth/consolecmd.go
+2
-2
dao_test.go
cmd/geth/dao_test.go
+2
-2
main.go
cmd/geth/main.go
+5
-11
monitorcmd.go
cmd/geth/monitorcmd.go
+1
-1
main.go
cmd/gethrpctest/main.go
+5
-6
customflags.go
cmd/utils/customflags.go
+12
-2
flags.go
cmd/utils/flags.go
+34
-32
path.go
common/path.go
+0
-27
database.go
ethdb/database.go
+5
-0
api.go
node/api.go
+11
-11
config.go
node/config.go
+108
-25
config_test.go
node/config_test.go
+20
-22
defaults.go
node/defaults.go
+14
-2
doc.go
node/doc.go
+90
-0
node.go
node/node.go
+112
-63
service.go
node/service.go
+10
-9
service_test.go
node/service_test.go
+3
-3
nat.go
p2p/nat/nat.go
+1
-5
No files found.
cmd/geth/chaincmd.go
View file @
44bc2e80
...
...
@@ -79,7 +79,8 @@ func importChain(ctx *cli.Context) error {
if
ctx
.
GlobalBool
(
utils
.
TestNetFlag
.
Name
)
{
state
.
StartingNonce
=
1048576
// (2**20)
}
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
)
stack
:=
makeFullNode
(
ctx
)
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
,
stack
)
start
:=
time
.
Now
()
err
:=
utils
.
ImportChain
(
chain
,
ctx
.
Args
()
.
First
())
chainDb
.
Close
()
...
...
@@ -94,7 +95,8 @@ func exportChain(ctx *cli.Context) error {
if
len
(
ctx
.
Args
())
<
1
{
utils
.
Fatalf
(
"This command requires an argument."
)
}
chain
,
_
:=
utils
.
MakeChain
(
ctx
)
stack
:=
makeFullNode
(
ctx
)
chain
,
_
:=
utils
.
MakeChain
(
ctx
,
stack
)
start
:=
time
.
Now
()
var
err
error
...
...
@@ -122,20 +124,25 @@ func exportChain(ctx *cli.Context) error {
}
func
removeDB
(
ctx
*
cli
.
Context
)
error
{
confirm
,
err
:=
console
.
Stdin
.
PromptConfirm
(
"Remove local database?"
)
if
err
!=
nil
{
utils
.
Fatalf
(
"%v"
,
err
)
stack
:=
utils
.
MakeNode
(
ctx
,
clientIdentifier
,
gitCommit
)
dbdir
:=
stack
.
ResolvePath
(
"chaindata"
)
if
!
common
.
FileExist
(
dbdir
)
{
fmt
.
Println
(
dbdir
,
"does not exist"
)
return
nil
}
if
confirm
{
fmt
.
Println
(
"Removing chaindata..."
)
fmt
.
Println
(
dbdir
)
confirm
,
err
:=
console
.
Stdin
.
PromptConfirm
(
"Remove this database?"
)
switch
{
case
err
!=
nil
:
utils
.
Fatalf
(
"%v"
,
err
)
case
!
confirm
:
fmt
.
Println
(
"Operation aborted"
)
default
:
fmt
.
Println
(
"Removing..."
)
start
:=
time
.
Now
()
os
.
RemoveAll
(
filepath
.
Join
(
ctx
.
GlobalString
(
utils
.
DataDirFlag
.
Name
),
"chaindata"
))
os
.
RemoveAll
(
dbdir
)
fmt
.
Printf
(
"Removed in %v
\n
"
,
time
.
Since
(
start
))
}
else
{
fmt
.
Println
(
"Operation aborted"
)
}
return
nil
}
...
...
@@ -143,7 +150,8 @@ func removeDB(ctx *cli.Context) error {
func
upgradeDB
(
ctx
*
cli
.
Context
)
error
{
glog
.
Infoln
(
"Upgrading blockchain database"
)
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
)
stack
:=
utils
.
MakeNode
(
ctx
,
clientIdentifier
,
gitCommit
)
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
,
stack
)
bcVersion
:=
core
.
GetBlockChainVersion
(
chainDb
)
if
bcVersion
==
0
{
bcVersion
=
core
.
BlockChainVersion
...
...
@@ -156,10 +164,12 @@ func upgradeDB(ctx *cli.Context) error {
utils
.
Fatalf
(
"Unable to export chain for reimport %s"
,
err
)
}
chainDb
.
Close
()
os
.
RemoveAll
(
filepath
.
Join
(
ctx
.
GlobalString
(
utils
.
DataDirFlag
.
Name
),
"chaindata"
))
if
dir
:=
dbDirectory
(
chainDb
);
dir
!=
""
{
os
.
RemoveAll
(
dir
)
}
// Import the chain file.
chain
,
chainDb
=
utils
.
MakeChain
(
ctx
)
chain
,
chainDb
=
utils
.
MakeChain
(
ctx
,
stack
)
core
.
WriteBlockChainVersion
(
chainDb
,
core
.
BlockChainVersion
)
err
:=
utils
.
ImportChain
(
chain
,
exportFile
)
chainDb
.
Close
()
...
...
@@ -172,8 +182,17 @@ func upgradeDB(ctx *cli.Context) error {
return
nil
}
func
dbDirectory
(
db
ethdb
.
Database
)
string
{
ldb
,
ok
:=
db
.
(
*
ethdb
.
LDBDatabase
)
if
!
ok
{
return
""
}
return
ldb
.
Path
()
}
func
dump
(
ctx
*
cli
.
Context
)
error
{
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
)
stack
:=
makeFullNode
(
ctx
)
chain
,
chainDb
:=
utils
.
MakeChain
(
ctx
,
stack
)
for
_
,
arg
:=
range
ctx
.
Args
()
{
var
block
*
types
.
Block
if
hashish
(
arg
)
{
...
...
cmd/geth/consolecmd.go
View file @
44bc2e80
...
...
@@ -107,7 +107,7 @@ func remoteConsole(ctx *cli.Context) error {
utils
.
Fatalf
(
"Unable to attach to remote geth: %v"
,
err
)
}
config
:=
console
.
Config
{
DataDir
:
utils
.
M
ustM
akeDataDir
(
ctx
),
DataDir
:
utils
.
MakeDataDir
(
ctx
),
DocRoot
:
ctx
.
GlobalString
(
utils
.
JSpathFlag
.
Name
),
Client
:
client
,
Preload
:
utils
.
MakeConsolePreloads
(
ctx
),
...
...
@@ -135,7 +135,7 @@ func remoteConsole(ctx *cli.Context) error {
// for "geth attach" and "geth monitor" with no argument.
func
dialRPC
(
endpoint
string
)
(
*
rpc
.
Client
,
error
)
{
if
endpoint
==
""
{
endpoint
=
node
.
DefaultIPCEndpoint
()
endpoint
=
node
.
DefaultIPCEndpoint
(
clientIdentifier
)
}
else
if
strings
.
HasPrefix
(
endpoint
,
"rpc:"
)
||
strings
.
HasPrefix
(
endpoint
,
"ipc:"
)
{
// Backwards compatibility with geth < 1.5 which required
// these prefixes.
...
...
cmd/geth/dao_test.go
View file @
44bc2e80
...
...
@@ -195,9 +195,9 @@ func testDAOForkBlockNewChain(t *testing.T, testnet bool, genesis string, votes
geth
.
cmd
.
Wait
()
}
// Retrieve the DAO config flag from the database
path
:=
filepath
.
Join
(
datadir
,
"chaindata"
)
path
:=
filepath
.
Join
(
datadir
,
"
geth"
,
"
chaindata"
)
if
testnet
&&
genesis
==
""
{
path
=
filepath
.
Join
(
datadir
,
"testnet"
,
"chaindata"
)
path
=
filepath
.
Join
(
datadir
,
"testnet"
,
"
geth"
,
"
chaindata"
)
}
db
,
err
:=
ethdb
.
NewLDBDatabase
(
path
,
0
,
0
)
if
err
!=
nil
{
...
...
cmd/geth/main.go
View file @
44bc2e80
...
...
@@ -36,7 +36,6 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
...
...
@@ -46,7 +45,7 @@ import (
)
const
(
clientIdentifier
=
"
G
eth"
// Client identifier to advertise over the network
clientIdentifier
=
"
g
eth"
// Client identifier to advertise over the network
)
var
(
...
...
@@ -245,17 +244,15 @@ func initGenesis(ctx *cli.Context) error {
state
.
StartingNonce
=
1048576
// (2**20)
}
chainDb
,
err
:=
ethdb
.
NewLDBDatabase
(
filepath
.
Join
(
utils
.
MustMakeDataDir
(
ctx
),
"chaindata"
),
0
,
0
)
if
err
!=
nil
{
utils
.
Fatalf
(
"could not open database: %v"
,
err
)
}
stack
:=
makeFullNode
(
ctx
)
chaindb
:=
utils
.
MakeChainDatabase
(
ctx
,
stack
)
genesisFile
,
err
:=
os
.
Open
(
genesisPath
)
if
err
!=
nil
{
utils
.
Fatalf
(
"failed to read genesis file: %v"
,
err
)
}
block
,
err
:=
core
.
WriteGenesisBlock
(
chain
D
b
,
genesisFile
)
block
,
err
:=
core
.
WriteGenesisBlock
(
chain
d
b
,
genesisFile
)
if
err
!=
nil
{
utils
.
Fatalf
(
"failed to write genesis block: %v"
,
err
)
}
...
...
@@ -296,9 +293,6 @@ func makeFullNode(ctx *cli.Context) *node.Node {
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func
startNode
(
ctx
*
cli
.
Context
,
stack
*
node
.
Node
)
{
// Report geth version
glog
.
V
(
logger
.
Info
)
.
Infof
(
"instance: Geth/%s/%s/%s
\n
"
,
utils
.
Version
,
runtime
.
Version
(),
runtime
.
GOOS
)
// Start up the node itself
utils
.
StartNode
(
stack
)
...
...
@@ -379,7 +373,7 @@ func gpubench(ctx *cli.Context) error {
}
func
version
(
c
*
cli
.
Context
)
error
{
fmt
.
Println
(
clientIdentifier
)
fmt
.
Println
(
strings
.
Title
(
clientIdentifier
)
)
fmt
.
Println
(
"Version:"
,
utils
.
Version
)
if
gitCommit
!=
""
{
fmt
.
Println
(
"Git Commit:"
,
gitCommit
)
...
...
cmd/geth/monitorcmd.go
View file @
44bc2e80
...
...
@@ -35,7 +35,7 @@ import (
var
(
monitorCommandAttachFlag
=
cli
.
StringFlag
{
Name
:
"attach"
,
Value
:
node
.
DefaultIPCEndpoint
(),
Value
:
node
.
DefaultIPCEndpoint
(
clientIdentifier
),
Usage
:
"API endpoint to attach to"
,
}
monitorCommandRowsFlag
=
cli
.
IntFlag
{
...
...
cmd/gethrpctest/main.go
View file @
44bc2e80
...
...
@@ -23,7 +23,6 @@ import (
"os"
"os/signal"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
...
...
@@ -88,12 +87,12 @@ func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) {
// Create a networkless protocol stack
stack
,
err
:=
node
.
New
(
&
node
.
Config
{
UseLightweightKDF
:
true
,
IPCPath
:
node
.
DefaultIPCEndpoint
(),
HTTPHost
:
common
.
DefaultHTTPHost
,
HTTPPort
:
common
.
DefaultHTTPPort
,
IPCPath
:
node
.
DefaultIPCEndpoint
(
""
),
HTTPHost
:
node
.
DefaultHTTPHost
,
HTTPPort
:
node
.
DefaultHTTPPort
,
HTTPModules
:
[]
string
{
"admin"
,
"db"
,
"eth"
,
"debug"
,
"miner"
,
"net"
,
"shh"
,
"txpool"
,
"personal"
,
"web3"
},
WSHost
:
common
.
DefaultWSHost
,
WSPort
:
common
.
DefaultWSPort
,
WSHost
:
node
.
DefaultWSHost
,
WSPort
:
node
.
DefaultWSPort
,
WSModules
:
[]
string
{
"admin"
,
"db"
,
"eth"
,
"debug"
,
"miner"
,
"net"
,
"shh"
,
"txpool"
,
"personal"
,
"web3"
},
NoDiscovery
:
true
,
})
...
...
cmd/utils/customflags.go
View file @
44bc2e80
...
...
@@ -137,9 +137,19 @@ func (self *DirectoryFlag) Set(value string) {
// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
func
expandPath
(
p
string
)
string
{
if
strings
.
HasPrefix
(
p
,
"~/"
)
||
strings
.
HasPrefix
(
p
,
"~
\\
"
)
{
if
user
,
err
:=
user
.
Current
();
err
==
nil
{
p
=
user
.
HomeDir
+
p
[
1
:
]
if
home
:=
homeDir
();
home
!=
""
{
p
=
home
+
p
[
1
:
]
}
}
return
path
.
Clean
(
os
.
ExpandEnv
(
p
))
}
func
homeDir
()
string
{
if
home
:=
os
.
Getenv
(
"HOME"
);
home
!=
""
{
return
home
}
if
usr
,
err
:=
user
.
Current
();
err
==
nil
{
return
usr
.
HomeDir
}
return
""
}
cmd/utils/flags.go
View file @
44bc2e80
...
...
@@ -105,7 +105,7 @@ var (
DataDirFlag
=
DirectoryFlag
{
Name
:
"datadir"
,
Usage
:
"Data directory for the databases and keystore"
,
Value
:
DirectoryString
{
common
.
DefaultDataDir
()},
Value
:
DirectoryString
{
node
.
DefaultDataDir
()},
}
KeyStoreDirFlag
=
DirectoryFlag
{
Name
:
"keystore"
,
...
...
@@ -139,7 +139,7 @@ var (
DocRootFlag
=
DirectoryFlag
{
Name
:
"docroot"
,
Usage
:
"Document Root for HTTPClient file scheme"
,
Value
:
DirectoryString
{
common
.
H
omeDir
()},
Value
:
DirectoryString
{
h
omeDir
()},
}
CacheFlag
=
cli
.
IntFlag
{
Name
:
"cache"
,
...
...
@@ -245,12 +245,12 @@ var (
RPCListenAddrFlag
=
cli
.
StringFlag
{
Name
:
"rpcaddr"
,
Usage
:
"HTTP-RPC server listening interface"
,
Value
:
common
.
DefaultHTTPHost
,
Value
:
node
.
DefaultHTTPHost
,
}
RPCPortFlag
=
cli
.
IntFlag
{
Name
:
"rpcport"
,
Usage
:
"HTTP-RPC server listening port"
,
Value
:
common
.
DefaultHTTPPort
,
Value
:
node
.
DefaultHTTPPort
,
}
RPCCORSDomainFlag
=
cli
.
StringFlag
{
Name
:
"rpccorsdomain"
,
...
...
@@ -268,13 +268,13 @@ var (
}
IPCApiFlag
=
cli
.
StringFlag
{
Name
:
"ipcapi"
,
Usage
:
"API
'
s offered over the IPC-RPC interface"
,
Usage
:
"APIs offered over the IPC-RPC interface"
,
Value
:
rpc
.
DefaultIPCApis
,
}
IPCPathFlag
=
DirectoryFlag
{
Name
:
"ipcpath"
,
Usage
:
"Filename for IPC socket/pipe within the datadir (explicit paths escape it)"
,
Value
:
DirectoryString
{
common
.
DefaultIPCSocket
},
Value
:
DirectoryString
{
"geth.ipc"
},
}
WSEnabledFlag
=
cli
.
BoolFlag
{
Name
:
"ws"
,
...
...
@@ -283,12 +283,12 @@ var (
WSListenAddrFlag
=
cli
.
StringFlag
{
Name
:
"wsaddr"
,
Usage
:
"WS-RPC server listening interface"
,
Value
:
common
.
DefaultWSHost
,
Value
:
node
.
DefaultWSHost
,
}
WSPortFlag
=
cli
.
IntFlag
{
Name
:
"wsport"
,
Usage
:
"WS-RPC server listening port"
,
Value
:
common
.
DefaultWSPort
,
Value
:
node
.
DefaultWSPort
,
}
WSApiFlag
=
cli
.
StringFlag
{
Name
:
"wsapi"
,
...
...
@@ -396,13 +396,14 @@ var (
}
)
// M
ustM
akeDataDir retrieves the currently requested data directory, terminating
// MakeDataDir retrieves the currently requested data directory, terminating
// if none (or the empty string) is specified. If the node is starting a testnet,
// the a subdirectory of the specified datadir will be used.
func
M
ustM
akeDataDir
(
ctx
*
cli
.
Context
)
string
{
func
MakeDataDir
(
ctx
*
cli
.
Context
)
string
{
if
path
:=
ctx
.
GlobalString
(
DataDirFlag
.
Name
);
path
!=
""
{
// TODO: choose a different location outside of the regular datadir.
if
ctx
.
GlobalBool
(
TestNetFlag
.
Name
)
{
return
filepath
.
Join
(
path
,
"
/
testnet"
)
return
filepath
.
Join
(
path
,
"testnet"
)
}
return
path
}
...
...
@@ -447,16 +448,16 @@ func MakeNodeKey(ctx *cli.Context) *ecdsa.PrivateKey {
return
key
}
//
MakeNodeName creates a node name from a base set and the command line
flags.
func
MakeNodeName
(
client
,
version
string
,
ctx
*
cli
.
Context
)
string
{
name
:=
common
.
MakeName
(
client
,
version
)
//
makeNodeUserIdent creates the user identifier from CLI
flags.
func
makeNodeUserIdent
(
ctx
*
cli
.
Context
)
string
{
var
comps
[]
string
if
identity
:=
ctx
.
GlobalString
(
IdentityFlag
.
Name
);
len
(
identity
)
>
0
{
name
+=
"/"
+
identity
comps
=
append
(
comps
,
identity
)
}
if
ctx
.
GlobalBool
(
VMEnableJitFlag
.
Name
)
{
name
+=
"/JIT"
comps
=
append
(
comps
,
"JIT"
)
}
return
name
return
strings
.
Join
(
comps
,
"/"
)
}
// MakeBootstrapNodes creates a list of bootstrap nodes from the command line
...
...
@@ -612,11 +613,13 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
}
config
:=
&
node
.
Config
{
DataDir
:
M
ustM
akeDataDir
(
ctx
),
DataDir
:
MakeDataDir
(
ctx
),
KeyStoreDir
:
ctx
.
GlobalString
(
KeyStoreDirFlag
.
Name
),
UseLightweightKDF
:
ctx
.
GlobalBool
(
LightKDFFlag
.
Name
),
PrivateKey
:
MakeNodeKey
(
ctx
),
Name
:
MakeNodeName
(
name
,
vsn
,
ctx
),
Name
:
name
,
Version
:
vsn
,
UserIdent
:
makeNodeUserIdent
(
ctx
),
NoDiscovery
:
ctx
.
GlobalBool
(
NoDiscoverFlag
.
Name
),
BootstrapNodes
:
MakeBootstrapNodes
(
ctx
),
ListenAddr
:
MakeListenAddress
(
ctx
),
...
...
@@ -674,7 +677,7 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf
:=
&
eth
.
Config
{
Etherbase
:
MakeEtherbase
(
stack
.
AccountManager
(),
ctx
),
ChainConfig
:
M
ustMakeChainConfig
(
ctx
),
ChainConfig
:
M
akeChainConfig
(
ctx
,
stack
),
FastSync
:
ctx
.
GlobalBool
(
FastSyncFlag
.
Name
),
DatabaseCache
:
ctx
.
GlobalInt
(
CacheFlag
.
Name
),
DatabaseHandles
:
MakeDatabaseHandles
(),
...
...
@@ -748,16 +751,16 @@ func SetupNetwork(ctx *cli.Context) {
params
.
TargetGasLimit
=
common
.
String2Big
(
ctx
.
GlobalString
(
TargetGasLimitFlag
.
Name
))
}
// M
ustM
akeChainConfig reads the chain configuration from the database in ctx.Datadir.
func
M
ustMakeChainConfig
(
ctx
*
cli
.
Context
)
*
core
.
ChainConfig
{
db
:=
MakeChainDatabase
(
ctx
)
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
func
M
akeChainConfig
(
ctx
*
cli
.
Context
,
stack
*
node
.
Node
)
*
core
.
ChainConfig
{
db
:=
MakeChainDatabase
(
ctx
,
stack
)
defer
db
.
Close
()
return
M
ustM
akeChainConfigFromDb
(
ctx
,
db
)
return
MakeChainConfigFromDb
(
ctx
,
db
)
}
// M
ustM
akeChainConfigFromDb reads the chain configuration from the given database.
func
M
ustM
akeChainConfigFromDb
(
ctx
*
cli
.
Context
,
db
ethdb
.
Database
)
*
core
.
ChainConfig
{
// MakeChainConfigFromDb reads the chain configuration from the given database.
func
MakeChainConfigFromDb
(
ctx
*
cli
.
Context
,
db
ethdb
.
Database
)
*
core
.
ChainConfig
{
// If the chain is already initialized, use any existing chain configs
config
:=
new
(
core
.
ChainConfig
)
...
...
@@ -800,14 +803,13 @@ func MustMakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainC
}
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
func
MakeChainDatabase
(
ctx
*
cli
.
Context
)
ethdb
.
Database
{
func
MakeChainDatabase
(
ctx
*
cli
.
Context
,
stack
*
node
.
Node
)
ethdb
.
Database
{
var
(
datadir
=
MustMakeDataDir
(
ctx
)
cache
=
ctx
.
GlobalInt
(
CacheFlag
.
Name
)
handles
=
MakeDatabaseHandles
()
)
chainDb
,
err
:=
ethdb
.
NewLDBDatabase
(
filepath
.
Join
(
datadir
,
"chaindata"
)
,
cache
,
handles
)
chainDb
,
err
:=
stack
.
OpenDatabase
(
"chaindata"
,
cache
,
handles
)
if
err
!=
nil
{
Fatalf
(
"Could not open database: %v"
,
err
)
}
...
...
@@ -815,9 +817,9 @@ func MakeChainDatabase(ctx *cli.Context) ethdb.Database {
}
// MakeChain creates a chain manager from set command line flags.
func
MakeChain
(
ctx
*
cli
.
Context
)
(
chain
*
core
.
BlockChain
,
chainDb
ethdb
.
Database
)
{
func
MakeChain
(
ctx
*
cli
.
Context
,
stack
*
node
.
Node
)
(
chain
*
core
.
BlockChain
,
chainDb
ethdb
.
Database
)
{
var
err
error
chainDb
=
MakeChainDatabase
(
ctx
)
chainDb
=
MakeChainDatabase
(
ctx
,
stack
)
if
ctx
.
GlobalBool
(
OlympicFlag
.
Name
)
{
_
,
err
:=
core
.
WriteTestNetGenesisBlock
(
chainDb
)
...
...
@@ -825,7 +827,7 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database
glog
.
Fatalln
(
err
)
}
}
chainConfig
:=
M
ustM
akeChainConfigFromDb
(
ctx
,
chainDb
)
chainConfig
:=
MakeChainConfigFromDb
(
ctx
,
chainDb
)
pow
:=
pow
.
PoW
(
core
.
FakePow
{})
if
!
ctx
.
GlobalBool
(
FakePoWFlag
.
Name
)
{
...
...
common/path.go
View file @
44bc2e80
...
...
@@ -19,10 +19,8 @@ package common
import
(
"fmt"
"os"
"os/user"
"path/filepath"
"runtime"
"strings"
)
// MakeName creates a node name that follows the ethereum convention
...
...
@@ -32,21 +30,6 @@ func MakeName(name, version string) string {
return
fmt
.
Sprintf
(
"%s/v%s/%s/%s"
,
name
,
version
,
runtime
.
GOOS
,
runtime
.
Version
())
}
func
ExpandHomePath
(
p
string
)
(
path
string
)
{
path
=
p
sep
:=
string
(
os
.
PathSeparator
)
// Check in case of paths like "/something/~/something/"
if
len
(
p
)
>
1
&&
p
[
:
1
+
len
(
sep
)]
==
"~"
+
sep
{
usr
,
_
:=
user
.
Current
()
dir
:=
usr
.
HomeDir
path
=
strings
.
Replace
(
p
,
"~"
,
dir
,
1
)
}
return
}
func
FileExist
(
filePath
string
)
bool
{
_
,
err
:=
os
.
Stat
(
filePath
)
if
err
!=
nil
&&
os
.
IsNotExist
(
err
)
{
...
...
@@ -62,13 +45,3 @@ func AbsolutePath(Datadir string, filename string) string {
}
return
filepath
.
Join
(
Datadir
,
filename
)
}
func
HomeDir
()
string
{
if
home
:=
os
.
Getenv
(
"HOME"
);
home
!=
""
{
return
home
}
if
usr
,
err
:=
user
.
Current
();
err
==
nil
{
return
usr
.
HomeDir
}
return
""
}
ethdb/database.go
View file @
44bc2e80
...
...
@@ -100,6 +100,11 @@ func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
},
nil
}
// Path returns the path to the database directory.
func
(
db
*
LDBDatabase
)
Path
()
string
{
return
db
.
fn
}
// Put puts the given key / value to the queue
func
(
self
*
LDBDatabase
)
Put
(
key
[]
byte
,
value
[]
byte
)
error
{
// Measure the database put latency, if requested
...
...
node/api.go
View file @
44bc2e80
...
...
@@ -84,17 +84,17 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *rpc.HexNumber, cors *st
}
if
host
==
nil
{
h
:=
common
.
DefaultHTTPHost
if
api
.
node
.
http
Host
!=
""
{
h
=
api
.
node
.
http
Host
h
:=
DefaultHTTPHost
if
api
.
node
.
config
.
HTTP
Host
!=
""
{
h
=
api
.
node
.
config
.
HTTP
Host
}
host
=
&
h
}
if
port
==
nil
{
port
=
rpc
.
NewHexNumber
(
api
.
node
.
http
Port
)
port
=
rpc
.
NewHexNumber
(
api
.
node
.
config
.
HTTP
Port
)
}
if
cors
==
nil
{
cors
=
&
api
.
node
.
http
Cors
cors
=
&
api
.
node
.
config
.
HTTP
Cors
}
modules
:=
api
.
node
.
httpWhitelist
...
...
@@ -133,20 +133,20 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *rpc.HexNumber, allowedOr
}
if
host
==
nil
{
h
:=
common
.
DefaultWSHost
if
api
.
node
.
ws
Host
!=
""
{
h
=
api
.
node
.
ws
Host
h
:=
DefaultWSHost
if
api
.
node
.
config
.
WS
Host
!=
""
{
h
=
api
.
node
.
config
.
WS
Host
}
host
=
&
h
}
if
port
==
nil
{
port
=
rpc
.
NewHexNumber
(
api
.
node
.
ws
Port
)
port
=
rpc
.
NewHexNumber
(
api
.
node
.
config
.
WS
Port
)
}
if
allowedOrigins
==
nil
{
allowedOrigins
=
&
api
.
node
.
ws
Origins
allowedOrigins
=
&
api
.
node
.
config
.
WS
Origins
}
modules
:=
api
.
node
.
wsWhitelist
modules
:=
api
.
node
.
config
.
WSModules
if
apis
!=
nil
{
modules
=
nil
for
_
,
m
:=
range
strings
.
Split
(
*
apis
,
","
)
{
...
...
node/config.go
View file @
44bc2e80
...
...
@@ -18,7 +18,6 @@ package node
import
(
"crypto/ecdsa"
"encoding/json"
"fmt"
"io/ioutil"
"net"
...
...
@@ -48,6 +47,18 @@ var (
// P2P network layer of a protocol stack. These values can be further extended by
// all registered services.
type
Config
struct
{
// Name sets the instance name of the node. It must not contain the / character and is
// used in the devp2p node identifier. The instance name of geth is "geth". If no
// value is specified, the basename of the current executable is used.
Name
string
// UserIdent, if set, is used as an additional component in the devp2p node identifier.
UserIdent
string
// Version should be set to the version number of the program. It is used
// in the devp2p node identifier.
Version
string
// DataDir is the file system folder the node should use for any data storage
// requirements. The configured data directory will not be directly shared with
// registered services, instead those can use utility methods to create/access
...
...
@@ -80,10 +91,6 @@ type Config struct {
// needed.
PrivateKey
*
ecdsa
.
PrivateKey
// Name sets the node name of this server. Use common.MakeName to create a name
// that follows existing conventions.
Name
string
// NoDiscovery specifies whether the peer discovery mechanism should be started
// or not. Disabling is usually useful for protocol debugging (manual topology).
NoDiscovery
bool
...
...
@@ -178,9 +185,23 @@ func (c *Config) IPCEndpoint() string {
return
c
.
IPCPath
}
// NodeDB returns the path to the discovery node database.
func
(
c
*
Config
)
NodeDB
()
string
{
if
c
.
DataDir
==
""
{
return
""
// ephemeral
}
return
c
.
resolvePath
(
"nodes"
)
}
// DefaultIPCEndpoint returns the IPC path used by default.
func
DefaultIPCEndpoint
()
string
{
config
:=
&
Config
{
DataDir
:
common
.
DefaultDataDir
(),
IPCPath
:
common
.
DefaultIPCSocket
}
func
DefaultIPCEndpoint
(
clientIdentifier
string
)
string
{
if
clientIdentifier
==
""
{
clientIdentifier
=
strings
.
TrimSuffix
(
filepath
.
Base
(
os
.
Args
[
0
]),
".exe"
)
if
clientIdentifier
==
""
{
panic
(
"empty executable name"
)
}
}
config
:=
&
Config
{
DataDir
:
DefaultDataDir
(),
IPCPath
:
clientIdentifier
+
".ipc"
}
return
config
.
IPCEndpoint
()
}
...
...
@@ -195,7 +216,7 @@ func (c *Config) HTTPEndpoint() string {
// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
func
DefaultHTTPEndpoint
()
string
{
config
:=
&
Config
{
HTTPHost
:
common
.
DefaultHTTPHost
,
HTTPPort
:
common
.
DefaultHTTPPort
}
config
:=
&
Config
{
HTTPHost
:
DefaultHTTPHost
,
HTTPPort
:
DefaultHTTPPort
}
return
config
.
HTTPEndpoint
()
}
...
...
@@ -210,19 +231,80 @@ func (c *Config) WSEndpoint() string {
// DefaultWSEndpoint returns the websocket endpoint used by default.
func
DefaultWSEndpoint
()
string
{
config
:=
&
Config
{
WSHost
:
common
.
DefaultWSHost
,
WSPort
:
common
.
DefaultWSPort
}
config
:=
&
Config
{
WSHost
:
DefaultWSHost
,
WSPort
:
DefaultWSPort
}
return
config
.
WSEndpoint
()
}
// NodeName returns the devp2p node identifier.
func
(
c
*
Config
)
NodeName
()
string
{
name
:=
c
.
name
()
// Backwards compatibility: previous versions used title-cased "Geth", keep that.
if
name
==
"geth"
||
name
==
"geth-testnet"
{
name
=
"Geth"
}
if
c
.
UserIdent
!=
""
{
name
+=
"/"
+
c
.
UserIdent
}
if
c
.
Version
!=
""
{
name
+=
"/v"
+
c
.
Version
}
name
+=
"/"
+
runtime
.
GOOS
name
+=
"/"
+
runtime
.
Version
()
return
name
}
func
(
c
*
Config
)
name
()
string
{
if
c
.
Name
==
""
{
progname
:=
strings
.
TrimSuffix
(
filepath
.
Base
(
os
.
Args
[
0
]),
".exe"
)
if
progname
==
""
{
panic
(
"empty executable name, set Config.Name"
)
}
return
progname
}
return
c
.
Name
}
// These resources are resolved differently for the "geth" and "geth-testnet" instances.
var
isOldGethResource
=
map
[
string
]
bool
{
"chaindata"
:
true
,
"nodes"
:
true
,
"nodekey"
:
true
,
"static-nodes.json"
:
true
,
"trusted-nodes.json"
:
true
,
}
// resolvePath resolves path in the instance directory.
func
(
c
*
Config
)
resolvePath
(
path
string
)
string
{
if
filepath
.
IsAbs
(
path
)
{
return
path
}
if
c
.
DataDir
==
""
{
return
""
}
// Backwards-compatibility: ensure that data directory files created
// by geth 1.4 are used if they exist.
if
c
.
name
()
==
"geth"
&&
isOldGethResource
[
path
]
{
oldpath
:=
""
if
c
.
Name
==
"geth"
{
oldpath
=
filepath
.
Join
(
c
.
DataDir
,
path
)
}
if
oldpath
!=
""
&&
common
.
FileExist
(
oldpath
)
{
// TODO: print warning
return
oldpath
}
}
return
filepath
.
Join
(
c
.
DataDir
,
c
.
name
(),
path
)
}
// 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
// data folder. If no key can be found, a new one is generated.
func
(
c
*
Config
)
NodeKey
()
*
ecdsa
.
PrivateKey
{
// Use any specifically configured key
// Use any specifically configured key
.
if
c
.
PrivateKey
!=
nil
{
return
c
.
PrivateKey
}
// Generate ephemeral key if no datadir is being used
// Generate ephemeral key if no datadir is being used
.
if
c
.
DataDir
==
""
{
key
,
err
:=
crypto
.
GenerateKey
()
if
err
!=
nil
{
...
...
@@ -230,16 +312,22 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey {
}
return
key
}
// Fall back to persistent key from the data directory
keyfile
:=
filepath
.
Join
(
c
.
DataDir
,
datadirPrivateKey
)
keyfile
:=
c
.
resolvePath
(
datadirPrivateKey
)
if
key
,
err
:=
crypto
.
LoadECDSA
(
keyfile
);
err
==
nil
{
return
key
}
// No persistent key found, generate and store a new one
// No persistent key found, generate and store a new one
.
key
,
err
:=
crypto
.
GenerateKey
()
if
err
!=
nil
{
glog
.
Fatalf
(
"Failed to generate node key: %v"
,
err
)
}
instanceDir
:=
filepath
.
Join
(
c
.
DataDir
,
c
.
name
())
if
err
:=
os
.
MkdirAll
(
instanceDir
,
0700
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Failed to persist node key: %v"
,
err
)
return
key
}
keyfile
=
filepath
.
Join
(
instanceDir
,
datadirPrivateKey
)
if
err
:=
crypto
.
SaveECDSA
(
keyfile
,
key
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Failed to persist node key: %v"
,
err
)
}
...
...
@@ -248,12 +336,12 @@ func (c *Config) NodeKey() *ecdsa.PrivateKey {
// StaticNodes returns a list of node enode URLs configured as static nodes.
func
(
c
*
Config
)
StaticNodes
()
[]
*
discover
.
Node
{
return
c
.
parsePersistentNodes
(
datadirStaticNodes
)
return
c
.
parsePersistentNodes
(
c
.
resolvePath
(
datadirStaticNodes
)
)
}
// TrusterNodes returns a list of node enode URLs configured as trusted nodes.
func
(
c
*
Config
)
TrusterNodes
()
[]
*
discover
.
Node
{
return
c
.
parsePersistentNodes
(
datadirTrustedNodes
)
return
c
.
parsePersistentNodes
(
c
.
resolvePath
(
datadirTrustedNodes
)
)
}
// parsePersistentNodes parses a list of discovery node URLs loaded from a .json
...
...
@@ -267,15 +355,10 @@ func (c *Config) parsePersistentNodes(file string) []*discover.Node {
if
_
,
err
:=
os
.
Stat
(
path
);
err
!=
nil
{
return
nil
}
// Load the nodes from the config file
blob
,
err
:=
ioutil
.
ReadFile
(
path
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Failed to access nodes: %v"
,
err
)
return
nil
}
nodelist
:=
[]
string
{}
if
err
:=
json
.
Unmarshal
(
blob
,
&
nodelist
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Failed to load nodes: %v"
,
err
)
// Load the nodes from the config file.
var
nodelist
[]
string
if
err
:=
common
.
LoadJSON
(
path
,
&
nodelist
);
err
!=
nil
{
glog
.
V
(
logger
.
Error
)
.
Infof
(
"Can't load node file %s: %v"
,
path
,
err
)
return
nil
}
// Interpret the list as a discovery node array
...
...
node/config_test.go
View file @
44bc2e80
...
...
@@ -96,57 +96,55 @@ func TestIPCPathResolution(t *testing.T) {
// ephemeral.
func
TestNodeKeyPersistency
(
t
*
testing
.
T
)
{
// Create a temporary folder and make sure no key is present
dir
,
err
:=
ioutil
.
TempDir
(
""
,
""
)
dir
,
err
:=
ioutil
.
TempDir
(
""
,
"
node-test
"
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to create temporary data directory: %v"
,
err
)
}
defer
os
.
RemoveAll
(
dir
)
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
dir
,
datadirPrivateKey
));
err
==
nil
{
t
.
Fatalf
(
"non-created node key already exists"
)
}
keyfile
:=
filepath
.
Join
(
dir
,
"unit-test"
,
datadirPrivateKey
)
// Configure a node with a preset key and ensure it's not persisted
key
,
err
:=
crypto
.
GenerateKey
()
if
err
!=
nil
{
t
.
Fatalf
(
"failed to generate one-shot node key: %v"
,
err
)
}
if
_
,
err
:=
New
(
&
Config
{
DataDir
:
dir
,
PrivateKey
:
key
});
err
!=
nil
{
t
.
Fatalf
(
"failed to create empty stack: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
dir
,
datadirPrivateKey
));
err
==
nil
{
config
:=
&
Config
{
Name
:
"unit-test"
,
DataDir
:
dir
,
PrivateKey
:
key
}
config
.
NodeKey
()
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
keyfile
));
err
==
nil
{
t
.
Fatalf
(
"one-shot node key persisted to data directory"
)
}
// Configure a node with no preset key and ensure it is persisted this time
if
_
,
err
:=
New
(
&
Config
{
DataDir
:
dir
});
err
!=
nil
{
t
.
Fatalf
(
"failed to create newly keyed stack: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
dir
,
datadirPrivateKey
));
err
!=
nil
{
config
=
&
Config
{
Name
:
"unit-test"
,
DataDir
:
dir
}
config
.
NodeKey
()
if
_
,
err
:=
os
.
Stat
(
keyfile
);
err
!=
nil
{
t
.
Fatalf
(
"node key not persisted to data directory: %v"
,
err
)
}
key
,
err
=
crypto
.
LoadECDSA
(
filepath
.
Join
(
dir
,
datadirPrivateKey
)
)
key
,
err
=
crypto
.
LoadECDSA
(
keyfile
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to load freshly persisted node key: %v"
,
err
)
}
blob1
,
err
:=
ioutil
.
ReadFile
(
filepath
.
Join
(
dir
,
datadirPrivateKey
)
)
blob1
,
err
:=
ioutil
.
ReadFile
(
keyfile
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read freshly persisted node key: %v"
,
err
)
}
// Configure a new node and ensure the previously persisted key is loaded
if
_
,
err
:=
New
(
&
Config
{
DataDir
:
dir
});
err
!=
nil
{
t
.
Fatalf
(
"failed to create previously keyed stack: %v"
,
err
)
}
blob2
,
err
:=
ioutil
.
ReadFile
(
filepath
.
Join
(
dir
,
datadirPrivateKey
))
config
=
&
Config
{
Name
:
"unit-test"
,
DataDir
:
dir
}
config
.
NodeKey
()
blob2
,
err
:=
ioutil
.
ReadFile
(
filepath
.
Join
(
keyfile
))
if
err
!=
nil
{
t
.
Fatalf
(
"failed to read previously persisted node key: %v"
,
err
)
}
if
bytes
.
Compare
(
blob1
,
blob2
)
!=
0
{
t
.
Fatalf
(
"persisted node key mismatch: have %x, want %x"
,
blob2
,
blob1
)
}
// Configure ephemeral node and ensure no key is dumped locally
if
_
,
err
:=
New
(
&
Config
{
DataDir
:
""
});
err
!=
nil
{
t
.
Fatalf
(
"failed to create ephemeral stack: %v"
,
err
)
}
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
"."
,
datadirPrivateKey
));
err
==
nil
{
config
=
&
Config
{
Name
:
"unit-test"
,
DataDir
:
""
}
config
.
NodeKey
()
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
"."
,
"unit-test"
,
datadirPrivateKey
));
err
==
nil
{
t
.
Fatalf
(
"ephemeral node key persisted to disk"
)
}
}
common
/defaults.go
→
node
/defaults.go
View file @
44bc2e80
...
...
@@ -14,9 +14,11 @@
// 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
common
package
node
import
(
"os"
"os/user"
"path/filepath"
"runtime"
)
...
...
@@ -33,7 +35,7 @@ const (
// persistence requirements.
func
DefaultDataDir
()
string
{
// Try to place the data folder in the user's home dir
home
:=
H
omeDir
()
home
:=
h
omeDir
()
if
home
!=
""
{
if
runtime
.
GOOS
==
"darwin"
{
return
filepath
.
Join
(
home
,
"Library"
,
"Ethereum"
)
...
...
@@ -46,3 +48,13 @@ func DefaultDataDir() string {
// As we cannot guess a stable location, return empty and handle later
return
""
}
func
homeDir
()
string
{
if
home
:=
os
.
Getenv
(
"HOME"
);
home
!=
""
{
return
home
}
if
usr
,
err
:=
user
.
Current
();
err
==
nil
{
return
usr
.
HomeDir
}
return
""
}
node/doc.go
0 → 100644
View file @
44bc2e80
// Copyright 2016 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 node sets up multi-protocol Ethereum nodes.
In the model exposed by this package, a node is a collection of services which use shared
resources to provide RPC APIs. Services can also offer devp2p protocols, which are wired
up to the devp2p network when the node instance is started.
Resources Managed By Node
All file-system resources used by a node instance are located in a directory called the
data directory. The location of each resource can be overridden through additional node
configuration. The data directory is optional. If it is not set and the location of a
resource is otherwise unspecified, package node will create the resource in memory.
To access to the devp2p network, Node configures and starts p2p.Server. Each host on the
devp2p network has a unique identifier, the node key. The Node instance persists this key
across restarts. Node also loads static and trusted node lists and ensures that knowledge
about other hosts is persisted.
JSON-RPC servers which run HTTP, WebSocket or IPC can be started on a Node. RPC modules
offered by registered services will be offered on those endpoints. Users can restrict any
endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3"
modules.
Service implementations can open LevelDB databases through the service context. Package
node chooses the file system location of each database. If the node is configured to run
without a data directory, databases are opened in memory instead.
Node also creates the shared store of encrypted Ethereum account keys. Services can access
the account manager through the service context.
Sharing Data Directory Among Instances
Multiple node instances can share a single data directory if they have distinct instance
names (set through the Name config option). Sharing behaviour depends on the type of
resource.
devp2p-related resources (node key, static/trusted node lists, known hosts database) are
stored in a directory with the same name as the instance. Thus, multiple node instances
using the same data directory will store this information in different subdirectories of
the data directory.
LevelDB databases are also stored within the instance subdirectory. If multiple node
instances use the same data directory, openening the databases with identical names will
create one database for each instance.
The account key store is shared among all node instances using the same data directory
unless its location is changed through the KeyStoreDir configuration option.
Data Directory Sharing Example
In this exanple, two node instances named A and B are started with the same data
directory. Mode instance A opens the database "db", node instance B opens the databases
"db" and "db-2". The following files will be created in the data directory:
data-directory/
A/
nodekey -- devp2p node key of instance A
nodes/ -- devp2p discovery knowledge database of instance A
db/ -- LevelDB content for "db"
A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A
B/
nodekey -- devp2p node key of node B
nodes/ -- devp2p discovery knowledge database of instance B
static-nodes.json -- devp2p static node list of instance B
db/ -- LevelDB content for "db"
db-2/ -- LevelDB content for "db-2"
B.ipc -- JSON-RPC UNIX domain socket endpoint of instance A
keystore/ -- account key store, used by both instances
*/
package
node
node/node.go
View file @
44bc2e80
...
...
@@ -14,7 +14,6 @@
// 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 node represents the Ethereum protocol stack container.
package
node
import
(
...
...
@@ -23,16 +22,19 @@ import (
"os"
"path/filepath"
"reflect"
"strings"
"sync"
"syscall"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"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/rpc"
"github.com/syndtr/goleveldb/leveldb/storage"
)
var
(
...
...
@@ -44,14 +46,14 @@ var (
datadirInUseErrnos
=
map
[
uint
]
bool
{
11
:
true
,
32
:
true
,
35
:
true
}
)
// Node represents a P2P node into which arbitrary (uniquely typed) services might
// be registered.
// Node is a container on which services can be registered.
type
Node
struct
{
datadir
string
// Path to the currently used data directory
eventmux
*
event
.
TypeMux
// Event multiplexer used between the services of a stack
config
*
Config
accman
*
accounts
.
Manager
ephemeralKeystore
string
// if non-empty, the key directory that will be removed by Stop
instanceDirLock
storage
.
Storage
// prevents concurrent use of instance directory
serverConfig
p2p
.
Config
server
*
p2p
.
Server
// Currently running P2P networking layer
...
...
@@ -66,19 +68,12 @@ type Node struct {
ipcListener
net
.
Listener
// IPC RPC listener socket to serve API requests
ipcHandler
*
rpc
.
Server
// IPC RPC request handler to process the API requests
httpHost
string
// HTTP hostname
httpPort
int
// HTTP post
httpEndpoint
string
// HTTP endpoint (interface + port) to listen at (empty = HTTP disabled)
httpWhitelist
[]
string
// HTTP RPC modules to allow through this endpoint
httpCors
string
// HTTP RPC Cross-Origin Resource Sharing header
httpListener
net
.
Listener
// HTTP RPC listener socket to server API requests
httpHandler
*
rpc
.
Server
// HTTP RPC request handler to process the API requests
wsHost
string
// Websocket host
wsPort
int
// Websocket post
wsEndpoint
string
// Websocket endpoint (interface + port) to listen at (empty = websocket disabled)
wsWhitelist
[]
string
// Websocket RPC modules to allow through this endpoint
wsOrigins
string
// Websocket RPC allowed origin domains
wsListener
net
.
Listener
// Websocket RPC listener socket to server API requests
wsHandler
*
rpc
.
Server
// Websocket RPC request handler to process the API requests
...
...
@@ -88,53 +83,44 @@ type Node struct {
// New creates a new P2P node, ready for protocol registration.
func
New
(
conf
*
Config
)
(
*
Node
,
error
)
{
// Ensure the data directory exists, failing if it cannot be created
// Copy config and resolve the datadir so future changes to the current
// working directory don't affect the node.
confCopy
:=
*
conf
conf
=
&
confCopy
if
conf
.
DataDir
!=
""
{
if
err
:=
os
.
MkdirAll
(
conf
.
DataDir
,
0700
);
err
!=
nil
{
absdatadir
,
err
:=
filepath
.
Abs
(
conf
.
DataDir
)
if
err
!=
nil
{
return
nil
,
err
}
conf
.
DataDir
=
absdatadir
}
// Ensure that the instance name doesn't cause weird conflicts with
// other files in the data directory.
if
strings
.
ContainsAny
(
conf
.
Name
,
`/\`
)
{
return
nil
,
errors
.
New
(
`Config.Name must not contain '/' or '\'`
)
}
if
conf
.
Name
==
datadirDefaultKeyStore
{
return
nil
,
errors
.
New
(
`Config.Name cannot be "`
+
datadirDefaultKeyStore
+
`"`
)
}
if
strings
.
HasSuffix
(
conf
.
Name
,
".ipc"
)
{
return
nil
,
errors
.
New
(
`Config.Name cannot end in ".ipc"`
)
}
// Ensure that the AccountManager method works before the node has started.
// We rely on this in cmd/geth.
am
,
ephemeralKeystore
,
err
:=
makeAccountManager
(
conf
)
if
err
!=
nil
{
return
nil
,
err
}
// Assemble the networking layer and the node itself
nodeDbPath
:=
""
if
conf
.
DataDir
!=
""
{
nodeDbPath
=
filepath
.
Join
(
conf
.
DataDir
,
datadirNodeDatabase
)
}
// Note: any interaction with Config that would create/touch files
// in the data directory or instance directory is delayed until Start.
return
&
Node
{
datadir
:
conf
.
DataDir
,
accman
:
am
,
ephemeralKeystore
:
ephemeralKeystore
,
serverConfig
:
p2p
.
Config
{
PrivateKey
:
conf
.
NodeKey
(),
Name
:
conf
.
Name
,
Discovery
:
!
conf
.
NoDiscovery
,
BootstrapNodes
:
conf
.
BootstrapNodes
,
StaticNodes
:
conf
.
StaticNodes
(),
TrustedNodes
:
conf
.
TrusterNodes
(),
NodeDatabase
:
nodeDbPath
,
ListenAddr
:
conf
.
ListenAddr
,
NAT
:
conf
.
NAT
,
Dialer
:
conf
.
Dialer
,
NoDial
:
conf
.
NoDial
,
MaxPeers
:
conf
.
MaxPeers
,
MaxPendingPeers
:
conf
.
MaxPendingPeers
,
},
config
:
conf
,
serviceFuncs
:
[]
ServiceConstructor
{},
ipcEndpoint
:
conf
.
IPCEndpoint
(),
httpHost
:
conf
.
HTTPHost
,
httpPort
:
conf
.
HTTPPort
,
httpEndpoint
:
conf
.
HTTPEndpoint
(),
httpWhitelist
:
conf
.
HTTPModules
,
httpCors
:
conf
.
HTTPCors
,
wsHost
:
conf
.
WSHost
,
wsPort
:
conf
.
WSPort
,
wsEndpoint
:
conf
.
WSEndpoint
(),
wsWhitelist
:
conf
.
WSModules
,
wsOrigins
:
conf
.
WSOrigins
,
eventmux
:
new
(
event
.
TypeMux
),
},
nil
}
...
...
@@ -161,13 +147,36 @@ func (n *Node) Start() error {
if
n
.
server
!=
nil
{
return
ErrNodeRunning
}
// Otherwise copy and specialize the P2P configuration
if
err
:=
n
.
openDataDir
();
err
!=
nil
{
return
err
}
// Initialize the p2p server. This creates the node key and
// discovery databases.
n
.
serverConfig
=
p2p
.
Config
{
PrivateKey
:
n
.
config
.
NodeKey
(),
Name
:
n
.
config
.
NodeName
(),
Discovery
:
!
n
.
config
.
NoDiscovery
,
BootstrapNodes
:
n
.
config
.
BootstrapNodes
,
StaticNodes
:
n
.
config
.
StaticNodes
(),
TrustedNodes
:
n
.
config
.
TrusterNodes
(),
NodeDatabase
:
n
.
config
.
NodeDB
(),
ListenAddr
:
n
.
config
.
ListenAddr
,
NAT
:
n
.
config
.
NAT
,
Dialer
:
n
.
config
.
Dialer
,
NoDial
:
n
.
config
.
NoDial
,
MaxPeers
:
n
.
config
.
MaxPeers
,
MaxPendingPeers
:
n
.
config
.
MaxPendingPeers
,
}
running
:=
&
p2p
.
Server
{
Config
:
n
.
serverConfig
}
glog
.
V
(
logger
.
Info
)
.
Infoln
(
"instance:"
,
n
.
serverConfig
.
Name
)
// Otherwise copy and specialize the P2P configuration
services
:=
make
(
map
[
reflect
.
Type
]
Service
)
for
_
,
constructor
:=
range
n
.
serviceFuncs
{
// Create a new context for the particular service
ctx
:=
&
ServiceContext
{
datadir
:
n
.
datadir
,
config
:
n
.
config
,
services
:
make
(
map
[
reflect
.
Type
]
Service
),
EventMux
:
n
.
eventmux
,
AccountManager
:
n
.
accman
,
...
...
@@ -227,6 +236,26 @@ func (n *Node) Start() error {
return
nil
}
func
(
n
*
Node
)
openDataDir
()
error
{
if
n
.
config
.
DataDir
==
""
{
return
nil
// ephemeral
}
instdir
:=
filepath
.
Join
(
n
.
config
.
DataDir
,
n
.
config
.
name
())
if
err
:=
os
.
MkdirAll
(
instdir
,
0700
);
err
!=
nil
{
return
err
}
// Try to open the instance directory as LevelDB storage. This creates a lock file
// which prevents concurrent use by another instance as well as accidental use of the
// instance directory as a database.
storage
,
err
:=
storage
.
OpenFile
(
instdir
,
true
)
if
err
!=
nil
{
return
err
}
n
.
instanceDirLock
=
storage
return
nil
}
// startRPC is a helper method to start all the various RPC endpoint during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
...
...
@@ -244,12 +273,12 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
n
.
stopInProc
()
return
err
}
if
err
:=
n
.
startHTTP
(
n
.
httpEndpoint
,
apis
,
n
.
httpWhitelist
,
n
.
http
Cors
);
err
!=
nil
{
if
err
:=
n
.
startHTTP
(
n
.
httpEndpoint
,
apis
,
n
.
config
.
HTTPModules
,
n
.
config
.
HTTP
Cors
);
err
!=
nil
{
n
.
stopIPC
()
n
.
stopInProc
()
return
err
}
if
err
:=
n
.
startWS
(
n
.
wsEndpoint
,
apis
,
n
.
wsWhitelist
,
n
.
ws
Origins
);
err
!=
nil
{
if
err
:=
n
.
startWS
(
n
.
wsEndpoint
,
apis
,
n
.
config
.
WSModules
,
n
.
config
.
WS
Origins
);
err
!=
nil
{
n
.
stopHTTP
()
n
.
stopIPC
()
n
.
stopInProc
()
...
...
@@ -381,7 +410,6 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
n
.
httpEndpoint
=
endpoint
n
.
httpListener
=
listener
n
.
httpHandler
=
handler
n
.
httpCors
=
cors
return
nil
}
...
...
@@ -436,7 +464,6 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
n
.
wsEndpoint
=
endpoint
n
.
wsListener
=
listener
n
.
wsHandler
=
handler
n
.
wsOrigins
=
wsOrigins
return
nil
}
...
...
@@ -465,12 +492,12 @@ func (n *Node) Stop() error {
if
n
.
server
==
nil
{
return
ErrNodeStopped
}
// Otherwise terminate the API, all services and the P2P server too
// Terminate the API, services and the p2p server.
n
.
stopWS
()
n
.
stopHTTP
()
n
.
stopIPC
()
n
.
rpcAPIs
=
nil
failure
:=
&
StopError
{
Services
:
make
(
map
[
reflect
.
Type
]
error
),
}
...
...
@@ -480,9 +507,16 @@ func (n *Node) Stop() error {
}
}
n
.
server
.
Stop
()
n
.
services
=
nil
n
.
server
=
nil
// Release instance directory lock.
if
n
.
instanceDirLock
!=
nil
{
n
.
instanceDirLock
.
Close
()
n
.
instanceDirLock
=
nil
}
// unblock n.Wait
close
(
n
.
stop
)
// Remove the keystore if it was created ephemerally.
...
...
@@ -566,7 +600,7 @@ func (n *Node) Service(service interface{}) error {
// DataDir retrieves the current datadir used by the protocol stack.
func
(
n
*
Node
)
DataDir
()
string
{
return
n
.
datad
ir
return
n
.
config
.
DataD
ir
}
// AccountManager retrieves the account manager used by the protocol stack.
...
...
@@ -595,6 +629,21 @@ func (n *Node) EventMux() *event.TypeMux {
return
n
.
eventmux
}
// OpenDatabase opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
func
(
n
*
Node
)
OpenDatabase
(
name
string
,
cache
,
handles
int
)
(
ethdb
.
Database
,
error
)
{
if
n
.
config
.
DataDir
==
""
{
return
ethdb
.
NewMemDatabase
()
}
return
ethdb
.
NewLDBDatabase
(
n
.
config
.
resolvePath
(
name
),
cache
,
handles
)
}
// ResolvePath returns the absolute path of a resource in the instance directory.
func
(
n
*
Node
)
ResolvePath
(
x
string
)
string
{
return
n
.
config
.
resolvePath
(
x
)
}
// apis returns the collection of RPC descriptors this node offers.
func
(
n
*
Node
)
apis
()
[]
rpc
.
API
{
return
[]
rpc
.
API
{
...
...
node/service.go
View file @
44bc2e80
...
...
@@ -17,7 +17,6 @@
package
node
import
(
"path/filepath"
"reflect"
"github.com/ethereum/go-ethereum/accounts"
...
...
@@ -31,7 +30,7 @@ import (
// the protocol stack, that is passed to all constructors to be optionally used;
// as well as utility methods to operate on the service environment.
type
ServiceContext
struct
{
datadir
string
// Data directory for protocol persistence
config
*
Config
services
map
[
reflect
.
Type
]
Service
// Index of the already constructed services
EventMux
*
event
.
TypeMux
// Event multiplexer used for decoupled notifications
AccountManager
*
accounts
.
Manager
// Account manager created by the node.
...
...
@@ -41,10 +40,10 @@ type ServiceContext struct {
// if no previous can be found) from within the node's data directory. If the
// node is an ephemeral one, a memory database is returned.
func
(
ctx
*
ServiceContext
)
OpenDatabase
(
name
string
,
cache
int
,
handles
int
)
(
ethdb
.
Database
,
error
)
{
if
ctx
.
datad
ir
==
""
{
if
ctx
.
config
.
DataD
ir
==
""
{
return
ethdb
.
NewMemDatabase
()
}
return
ethdb
.
NewLDBDatabase
(
filepath
.
Join
(
ctx
.
datadir
,
name
),
cache
,
handles
)
return
ethdb
.
NewLDBDatabase
(
ctx
.
config
.
resolvePath
(
name
),
cache
,
handles
)
}
// Service retrieves a currently running service registered of a specific type.
...
...
@@ -64,10 +63,12 @@ type ServiceConstructor func(ctx *ServiceContext) (Service, error)
// Service is an individual protocol that can be registered into a node.
//
// Notes:
// - Service life-cycle management is delegated to the node. The service is
// allowed to initialize itself upon creation, but no goroutines should be
// spun up outside of the Start method.
// - Restart logic is not required as the node will create a fresh instance
//
// • Service life-cycle management is delegated to the node. The service is allowed to
// initialize itself upon creation, but no goroutines should be spun up outside of the
// Start method.
//
// • Restart logic is not required as the node will create a fresh instance
// every time a service is started.
type
Service
interface
{
// Protocols retrieves the P2P protocols the service wishes to start.
...
...
node/service_test.go
View file @
44bc2e80
...
...
@@ -38,18 +38,18 @@ func TestContextDatabases(t *testing.T) {
t
.
Fatalf
(
"non-created database already exists"
)
}
// Request the opening/creation of a database and ensure it persists to disk
ctx
:=
&
ServiceContext
{
datadir
:
dir
}
ctx
:=
&
ServiceContext
{
config
:
&
Config
{
Name
:
"unit-test"
,
DataDir
:
dir
}
}
db
,
err
:=
ctx
.
OpenDatabase
(
"persistent"
,
0
,
0
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to open persistent database: %v"
,
err
)
}
db
.
Close
()
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
dir
,
"persistent"
));
err
!=
nil
{
if
_
,
err
:=
os
.
Stat
(
filepath
.
Join
(
dir
,
"
unit-test"
,
"
persistent"
));
err
!=
nil
{
t
.
Fatalf
(
"persistent database doesn't exists: %v"
,
err
)
}
// Request th opening/creation of an ephemeral database and ensure it's not persisted
ctx
=
&
ServiceContext
{
datadir
:
""
}
ctx
=
&
ServiceContext
{
config
:
&
Config
{
DataDir
:
""
}
}
db
,
err
=
ctx
.
OpenDatabase
(
"ephemeral"
,
0
,
0
)
if
err
!=
nil
{
t
.
Fatalf
(
"failed to open ephemeral database: %v"
,
err
)
...
...
p2p/nat/nat.go
View file @
44bc2e80
...
...
@@ -197,11 +197,7 @@ type autodisc struct {
func
startautodisc
(
what
string
,
doit
func
()
Interface
)
Interface
{
// TODO: monitor network configuration and rerun doit when it changes.
ad
:=
&
autodisc
{
what
:
what
,
doit
:
doit
}
// Start the auto discovery as early as possible so it is already
// in progress when the rest of the stack calls the methods.
go
ad
.
wait
()
return
ad
return
&
autodisc
{
what
:
what
,
doit
:
doit
}
}
func
(
n
*
autodisc
)
AddMapping
(
protocol
string
,
extport
,
intport
int
,
name
string
,
lifetime
time
.
Duration
)
error
{
...
...
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