Merge pull request #158 from farazdagi/feature/split-cluster
Bootcluster (Rinkeby, Homestead) + Dev/Prod Mode
This commit is contained in:
commit
697baa93f2
|
@ -0,0 +1 @@
|
|||
*
|
|
@ -0,0 +1,15 @@
|
|||
FROM alpine:3.5
|
||||
|
||||
RUN \
|
||||
apk add --update go git make gcc musl-dev linux-headers ca-certificates && \
|
||||
git clone --depth 1 --branch feature/statusd-replaces-geth-on-cluster https://github.com/farazdagi/status-go && \
|
||||
(cd status-go && make) && \
|
||||
cp status-go/build/bin/statusd /statusd && \
|
||||
apk del go git make gcc musl-dev linux-headers && \
|
||||
rm -rf /status-go && rm -rf /var/cache/apk/*
|
||||
|
||||
EXPOSE 8545
|
||||
EXPOSE 30303
|
||||
EXPOSE 3001
|
||||
|
||||
ENTRYPOINT ["/statusd"]
|
|
@ -0,0 +1,61 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/status-go/geth"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
faucetCommand = cli.Command{
|
||||
Action: faucetCommandHandler,
|
||||
Name: "faucet",
|
||||
Usage: "Starts faucet node (light node used by faucet service to request Ether)",
|
||||
Flags: []cli.Flag{
|
||||
HTTPPortFlag,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// faucetCommandHandler handles `statusd faucet` command
|
||||
func faucetCommandHandler(ctx *cli.Context) error {
|
||||
config, err := parseFaucetCommandConfig(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can not parse config: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Starting Status Faucet node..")
|
||||
if err = geth.CreateAndRunNode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait till node has been stopped
|
||||
geth.NodeManagerInstance().Node().GethStack().Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseFaucetCommandConfig parses incoming CLI options and returns node configuration object
|
||||
func parseFaucetCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := makeNodeConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// select sub-protocols
|
||||
nodeConfig.LightEthConfig.Enabled = true
|
||||
nodeConfig.WhisperConfig.Enabled = false
|
||||
nodeConfig.SwarmConfig.Enabled = false
|
||||
|
||||
// RPC configuration
|
||||
nodeConfig.APIModules = "eth"
|
||||
nodeConfig.HTTPHost = "0.0.0.0" // allow to connect from anywhere
|
||||
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
|
||||
|
||||
// extra options
|
||||
nodeConfig.BootClusterConfig.Enabled = true
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/status-im/status-go/geth"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
lesCommand = cli.Command{
|
||||
Action: lesCommandHandler,
|
||||
Name: "les",
|
||||
Usage: "Starts Light Ethereum node",
|
||||
Flags: []cli.Flag{
|
||||
WhisperEnabledFlag,
|
||||
SwarmEnabledFlag,
|
||||
HTTPEnabledFlag,
|
||||
HTTPPortFlag,
|
||||
IPCEnabledFlag,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// lesCommandHandler handles `statusd les` command
|
||||
func lesCommandHandler(ctx *cli.Context) error {
|
||||
config, err := parseLESCommandConfig(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can not parse config: %v", err)
|
||||
}
|
||||
|
||||
fmt.Println("Starting Light Status node..")
|
||||
if err = geth.CreateAndRunNode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait till node has been stopped
|
||||
geth.NodeManagerInstance().Node().GethStack().Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseLESCommandConfig parses incoming CLI options and returns node configuration object
|
||||
func parseLESCommandConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := makeNodeConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Enabled sub-protocols
|
||||
nodeConfig.LightEthConfig.Enabled = true
|
||||
nodeConfig.WhisperConfig.Enabled = ctx.Bool(WhisperEnabledFlag.Name)
|
||||
nodeConfig.SwarmConfig.Enabled = ctx.Bool(SwarmEnabledFlag.Name)
|
||||
|
||||
// RPC configuration
|
||||
if !ctx.Bool(HTTPEnabledFlag.Name) {
|
||||
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
||||
}
|
||||
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
|
||||
nodeConfig.IPCEnabled = ctx.Bool(IPCEnabledFlag.Name)
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
|
@ -179,8 +179,8 @@ func DiscardTransactions(ids *C.char) *C.char {
|
|||
}
|
||||
|
||||
//export GenerateConfig
|
||||
func GenerateConfig(datadir *C.char, networkID C.int) *C.char {
|
||||
config, err := params.NewNodeConfig(C.GoString(datadir), uint64(networkID))
|
||||
func GenerateConfig(datadir *C.char, networkID C.int, devMode C.int) *C.char {
|
||||
config, err := params.NewNodeConfig(C.GoString(datadir), uint64(networkID), devMode == 1)
|
||||
if err != nil {
|
||||
return makeJSONErrorResponse(err)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/status-im/status-go/geth"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
@ -18,6 +17,12 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
// ProdModeFlag is whether we need dev or production settings
|
||||
ProdModeFlag = cli.BoolFlag{
|
||||
Name: "production",
|
||||
Usage: "Whether production settings should be loaded",
|
||||
}
|
||||
|
||||
// NodeKeyFileFlag is a node key file to be used as node's private key
|
||||
NodeKeyFileFlag = cli.StringFlag{
|
||||
Name: "nodekey",
|
||||
|
@ -34,8 +39,8 @@ var (
|
|||
// NetworkIDFlag defines network ID
|
||||
NetworkIDFlag = cli.IntFlag{
|
||||
Name: "networkid",
|
||||
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
|
||||
Value: params.TestNetworkID,
|
||||
Usage: "Network identifier (integer, 1=Homestead, 3=Ropsten, 4=Rinkeby)",
|
||||
Value: params.RopstenNetworkID,
|
||||
}
|
||||
|
||||
// LightEthEnabledFlag flags whether LES is enabled or not
|
||||
|
@ -85,23 +90,19 @@ var (
|
|||
|
||||
func init() {
|
||||
// setup the app
|
||||
app.Action = statusd
|
||||
app.Action = cli.ShowAppHelp
|
||||
app.HideVersion = true // separate command prints version
|
||||
app.Commands = []cli.Command{
|
||||
versionCommand,
|
||||
faucetCommand,
|
||||
lesCommand,
|
||||
wnodeCommand,
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
ProdModeFlag,
|
||||
NodeKeyFileFlag,
|
||||
DataDirFlag,
|
||||
NetworkIDFlag,
|
||||
LightEthEnabledFlag,
|
||||
WhisperEnabledFlag,
|
||||
SwarmEnabledFlag,
|
||||
HTTPEnabledFlag,
|
||||
HTTPPortFlag,
|
||||
IPCEnabledFlag,
|
||||
LogLevelFlag,
|
||||
}
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
|
@ -120,49 +121,6 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// statusd runs Status node
|
||||
func statusd(ctx *cli.Context) error {
|
||||
config, err := makeNodeConfig(ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "can not parse config: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := geth.CreateAndRunNode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait till node has been stopped
|
||||
geth.NodeManagerInstance().Node().GethStack().Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeNodeConfig parses incoming CLI options and returns node configuration object
|
||||
func makeNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := params.NewNodeConfig(ctx.GlobalString(DataDirFlag.Name), ctx.GlobalUint64(NetworkIDFlag.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeConfig.NodeKeyFile = ctx.GlobalString(NodeKeyFileFlag.Name)
|
||||
if !ctx.GlobalBool(HTTPEnabledFlag.Name) {
|
||||
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
||||
}
|
||||
nodeConfig.IPCEnabled = ctx.GlobalBool(IPCEnabledFlag.Name)
|
||||
nodeConfig.LightEthConfig.Enabled = ctx.GlobalBool(LightEthEnabledFlag.Name)
|
||||
nodeConfig.WhisperConfig.Enabled = ctx.GlobalBool(WhisperEnabledFlag.Name)
|
||||
nodeConfig.SwarmConfig.Enabled = ctx.GlobalBool(SwarmEnabledFlag.Name)
|
||||
nodeConfig.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name)
|
||||
|
||||
if logLevel := ctx.GlobalString(LogLevelFlag.Name); len(logLevel) > 0 {
|
||||
nodeConfig.LogEnabled = true
|
||||
nodeConfig.LogLevel = logLevel
|
||||
}
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
|
||||
// makeApp creates an app with sane defaults.
|
||||
func makeApp(gitCommit string) *cli.App {
|
||||
app := cli.NewApp()
|
||||
|
@ -174,6 +132,37 @@ func makeApp(gitCommit string) *cli.App {
|
|||
if gitCommit != "" {
|
||||
app.Version += "-" + gitCommit[:8]
|
||||
}
|
||||
app.Usage = "Status CLI"
|
||||
app.Usage = "CLI for Status nodes management"
|
||||
return app
|
||||
}
|
||||
|
||||
// makeNodeConfig parses incoming CLI options and returns node configuration object
|
||||
func makeNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := params.NewNodeConfig(
|
||||
ctx.GlobalString(DataDirFlag.Name),
|
||||
ctx.GlobalUint64(NetworkIDFlag.Name),
|
||||
!ctx.GlobalBool(ProdModeFlag.Name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeConfig.NodeKeyFile = ctx.GlobalString(NodeKeyFileFlag.Name)
|
||||
|
||||
if logLevel := ctx.GlobalString(LogLevelFlag.Name); len(logLevel) > 0 {
|
||||
nodeConfig.LogEnabled = true
|
||||
nodeConfig.LogLevel = logLevel
|
||||
}
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
|
||||
// printNodeConfig prints node config
|
||||
func printNodeConfig(ctx *cli.Context) {
|
||||
nodeConfig, err := makeNodeConfig(ctx)
|
||||
if err != nil {
|
||||
fmt.Printf("Loaded Config: failed (err: %v)", err)
|
||||
return
|
||||
}
|
||||
nodeConfig.LightEthConfig.Genesis = "SKIP"
|
||||
fmt.Println("Loaded Config: ", nodeConfig)
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@ import (
|
|||
|
||||
var (
|
||||
versionCommand = cli.Command{
|
||||
Action: version,
|
||||
Action: versionCommandHandler,
|
||||
Name: "version",
|
||||
Usage: "Print app version",
|
||||
}
|
||||
)
|
||||
|
||||
// version displays app version
|
||||
func version(ctx *cli.Context) error {
|
||||
// versionCommandHandler displays app version
|
||||
func versionCommandHandler(ctx *cli.Context) error {
|
||||
fmt.Println(strings.Title(params.ClientIdentifier))
|
||||
fmt.Println("Version:", params.Version)
|
||||
if gitCommit != "" {
|
||||
|
@ -35,5 +35,7 @@ func version(ctx *cli.Context) error {
|
|||
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
||||
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
||||
|
||||
printNodeConfig(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ func testGetDefaultConfig(t *testing.T) bool {
|
|||
// test Mainnet config
|
||||
nodeConfig := params.NodeConfig{}
|
||||
|
||||
rawResponse := GenerateConfig(C.CString("/tmp/data-folder"), 1)
|
||||
rawResponse := GenerateConfig(C.CString("/tmp/data-folder"), 1, 1)
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
|
||||
t.Errorf("cannot decode response (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
|
@ -200,7 +200,7 @@ func testGetDefaultConfig(t *testing.T) bool {
|
|||
|
||||
// test Testnet
|
||||
nodeConfig = params.NodeConfig{}
|
||||
rawResponse = GenerateConfig(C.CString("/tmp/data-folder"), 3)
|
||||
rawResponse = GenerateConfig(C.CString("/tmp/data-folder"), 3, 1)
|
||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &nodeConfig); err != nil {
|
||||
t.Errorf("cannot decode response (%s): %v", C.GoString(rawResponse), err)
|
||||
return false
|
||||
|
@ -1430,7 +1430,7 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
|||
|
||||
go func() {
|
||||
configJSON := `{
|
||||
"NetworkId": ` + strconv.Itoa(params.TestNetworkID) + `,
|
||||
"NetworkId": ` + strconv.Itoa(params.RopstenNetworkID) + `,
|
||||
"DataDir": "` + geth.TestDataDir + `",
|
||||
"HTTPPort": ` + strconv.Itoa(testConfig.Node.HTTPPort) + `,
|
||||
"WSPort": ` + strconv.Itoa(testConfig.Node.WSPort) + `,
|
||||
|
|
|
@ -108,6 +108,8 @@ var (
|
|||
WhisperTTLFlag,
|
||||
WhisperInjectTestAccounts,
|
||||
FirebaseAuthorizationKey,
|
||||
HTTPEnabledFlag,
|
||||
HTTPPortFlag,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -170,6 +172,8 @@ func makeWhisperNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
nodeConfig.LightEthConfig.Enabled = false
|
||||
|
||||
whisperConfig := nodeConfig.WhisperConfig
|
||||
|
||||
whisperConfig.Enabled = true
|
||||
|
@ -221,6 +225,12 @@ func makeWhisperNodeConfig(ctx *cli.Context) (*params.NodeConfig, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// RPC configuration
|
||||
if !ctx.Bool(HTTPEnabledFlag.Name) {
|
||||
nodeConfig.HTTPHost = "" // HTTP RPC is disabled
|
||||
}
|
||||
nodeConfig.HTTPPort = ctx.Int(HTTPPortFlag.Name)
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1110,7 +1110,7 @@ func TestJailWhisper(t *testing.T) {
|
|||
for testKey, filter := range installedFilters {
|
||||
if filter != "" {
|
||||
t.Logf("filter found: %v", filter)
|
||||
for _, message := range whisperAPI.GetSubscriptionMessages(filter) {
|
||||
for _, message := range whisperAPI.GetNewSubscriptionMessages(filter) {
|
||||
t.Logf("message found: %s", common.FromHex(message.Payload))
|
||||
passedTests[testKey] = true
|
||||
}
|
||||
|
|
59
geth/node.go
59
geth/node.go
|
@ -80,33 +80,7 @@ func MakeNode(config *params.NodeConfig) *Node {
|
|||
}
|
||||
|
||||
// configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config)
|
||||
stackConfig := &node.Config{
|
||||
DataDir: config.DataDir,
|
||||
KeyStoreDir: config.KeyStoreDir,
|
||||
UseLightweightKDF: true,
|
||||
Name: config.Name,
|
||||
Version: config.Version,
|
||||
P2P: p2p.Config{
|
||||
NoDiscovery: true,
|
||||
DiscoveryV5: false,
|
||||
DiscoveryV5Addr: ":0",
|
||||
BootstrapNodes: makeBootstrapNodes(),
|
||||
BootstrapNodesV5: makeBootstrapNodesV5(),
|
||||
ListenAddr: ":0",
|
||||
NAT: nat.Any(),
|
||||
MaxPeers: config.MaxPeers,
|
||||
MaxPendingPeers: config.MaxPendingPeers,
|
||||
},
|
||||
IPCPath: makeIPCPath(config),
|
||||
HTTPHost: config.HTTPHost,
|
||||
HTTPPort: config.HTTPPort,
|
||||
HTTPCors: []string{"*"},
|
||||
HTTPModules: strings.Split(config.APIModules, ","),
|
||||
WSHost: makeWSHost(config),
|
||||
WSPort: config.WSPort,
|
||||
WSOrigins: []string{"*"},
|
||||
WSModules: strings.Split(config.APIModules, ","),
|
||||
}
|
||||
stackConfig := defaultEmbeddedNodeConfig(config)
|
||||
|
||||
if len(config.NodeKeyFile) > 0 {
|
||||
log.Info("Loading private key file", "file", config.NodeKeyFile)
|
||||
|
@ -153,6 +127,37 @@ func MakeNode(config *params.NodeConfig) *Node {
|
|||
}
|
||||
}
|
||||
|
||||
// defaultEmbeddedNodeConfig returns default stack configuration for mobile client node
|
||||
func defaultEmbeddedNodeConfig(config *params.NodeConfig) *node.Config {
|
||||
return &node.Config{
|
||||
DataDir: config.DataDir,
|
||||
KeyStoreDir: config.KeyStoreDir,
|
||||
UseLightweightKDF: true,
|
||||
Name: config.Name,
|
||||
Version: config.Version,
|
||||
P2P: p2p.Config{
|
||||
NoDiscovery: true,
|
||||
DiscoveryV5: false,
|
||||
DiscoveryV5Addr: ":0",
|
||||
BootstrapNodes: makeBootstrapNodes(),
|
||||
BootstrapNodesV5: makeBootstrapNodesV5(),
|
||||
ListenAddr: ":0",
|
||||
NAT: nat.Any(),
|
||||
MaxPeers: config.MaxPeers,
|
||||
MaxPendingPeers: config.MaxPendingPeers,
|
||||
},
|
||||
IPCPath: makeIPCPath(config),
|
||||
HTTPHost: config.HTTPHost,
|
||||
HTTPPort: config.HTTPPort,
|
||||
HTTPCors: []string{"*"},
|
||||
HTTPModules: strings.Split(config.APIModules, ","),
|
||||
WSHost: makeWSHost(config),
|
||||
WSPort: config.WSPort,
|
||||
WSOrigins: []string{"*"},
|
||||
WSModules: strings.Split(config.APIModules, ","),
|
||||
}
|
||||
}
|
||||
|
||||
// activateEthService configures and registers the eth.Ethereum service with a given node.
|
||||
func activateEthService(stack *node.Node, config *params.NodeConfig) error {
|
||||
if !config.LightEthConfig.Enabled {
|
||||
|
|
|
@ -413,8 +413,18 @@ func (m *NodeManager) onNodeStarted() {
|
|||
|
||||
// PopulateStaticPeers connects current node with our publicly available LES/SHH/Swarm cluster
|
||||
func (m *NodeManager) PopulateStaticPeers() {
|
||||
for _, enode := range params.TestnetBootnodes {
|
||||
if !m.node.config.BootClusterConfig.Enabled {
|
||||
log.Info("Boot cluster is disabled")
|
||||
return
|
||||
}
|
||||
|
||||
enodes, err := m.node.config.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
log.Warn("Can not load boot nodes", "error", err)
|
||||
}
|
||||
for _, enode := range enodes {
|
||||
m.AddPeer(enode) // nolint: errcheck
|
||||
log.Info("Boot node added", "enode", enode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package params
|
||||
|
||||
// MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the main Ethereum network.
|
||||
var MainnetBootnodes = []string{}
|
||||
|
||||
// TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the Ropsten test network.
|
||||
var TestnetBootnodes = []string{
|
||||
"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30379",
|
||||
//"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30399",
|
||||
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
|
||||
|
||||
"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30379",
|
||||
//"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30399",
|
||||
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
|
||||
|
||||
"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30379",
|
||||
//"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30399",
|
||||
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
|
||||
|
||||
"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30379",
|
||||
//"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30399",
|
||||
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
|
||||
|
||||
"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30379",
|
||||
//"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30399",
|
||||
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303",
|
||||
|
||||
"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30379",
|
||||
//"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30399",
|
||||
"enode://1fa2dfe6b925ca753496ea197c973b66ef889ef4de2bf52acd5b8665c0cc2e8b95fbd192e764f10735f589297f1ae533f350f004e403063e8d4ad979aae44c12@51.15.61.194:30303",
|
||||
|
||||
"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30379",
|
||||
//"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30399",
|
||||
"enode://44b91c043bcd96bc5279524f1bfe32df0670374135435ebacb29ba5d0e18192623e63ead711c9c363afdf2500fac423116ac28bdd2d700bd70e096326f95c63f@51.15.35.2:30303",
|
||||
|
||||
"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30379",
|
||||
//"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30399",
|
||||
"enode://fb7622d3a50dc603f5c76919dd99c4112e5925cb891a67086b9dce581166fbdad361fd0bfb7ff128ab8f5e24e209e0b923668fbddb7e8b99edb82c1e3d782a80@51.15.54.229:30303",
|
||||
|
||||
"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30379",
|
||||
//"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30399",
|
||||
"enode://14c2960f57f6d63ed541cf64226aafbc7a21c40c6e4935a2e58fd2466fa7d06ec32082734c64d32f7c4692f4b90f26d019f472ba55cdda6d624ef4d7d8441285@51.15.35.70:30303",
|
||||
|
||||
"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30379",
|
||||
//"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30399",
|
||||
"enode://02cfa2b02b5431bfdc1bad0f575de8ea151029fe9a9c689074793d704d1b428255bd111bf578f0b4fcaa18267da7c335db9557e1012434f4a8ab2c25f4b3da4d@51.15.39.57:30303",
|
||||
}
|
||||
|
||||
// DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the
|
||||
// experimental RLPx v5 topic-discovery network.
|
||||
var DiscoveryV5Bootnodes = []string{}
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/static"
|
||||
)
|
||||
|
||||
// default node configuration options
|
||||
|
@ -40,7 +41,7 @@ var (
|
|||
// LightEthConfig holds LES-related configuration
|
||||
// Status nodes are always lightweight clients (due to mobile platform constraints)
|
||||
type LightEthConfig struct {
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
Enabled bool
|
||||
|
||||
// Genesis is JSON to seed the chain database with
|
||||
|
@ -61,7 +62,7 @@ type FirebaseConfig struct {
|
|||
|
||||
// WhisperConfig holds SHH-related configuration
|
||||
type WhisperConfig struct {
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
Enabled bool
|
||||
|
||||
// IdentityFile path to private key, that will be loaded as identity into Whisper
|
||||
|
@ -104,14 +105,31 @@ type WhisperConfig struct {
|
|||
|
||||
// SwarmConfig holds Swarm-related configuration
|
||||
type SwarmConfig struct {
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
// Enabled flag specifies whether protocol is enabled
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// BootCluster holds configuration for supporting boot cluster, which is a temporary
|
||||
// means for mobile devices to get connected to Ethereum network (UDP-based discovery
|
||||
// may not be available, so we need means to discover the network manually).
|
||||
type BootClusterConfig struct {
|
||||
// Enabled flag specifies whether feature is enabled
|
||||
Enabled bool
|
||||
|
||||
// ConfigFile is a path to JSON file containing array of boot nodes
|
||||
// See `static/bootcluster/*.json` for cluster configurations provided
|
||||
// out of box. You can pass absolute path, and if file at that path can be
|
||||
// loaded, it will be used. Otherwise, file is supposed to be relative to
|
||||
// `static/bootcluster` folder.
|
||||
ConfigFile string
|
||||
}
|
||||
|
||||
// NodeConfig stores configuration options for a node
|
||||
type NodeConfig struct {
|
||||
// TestNet flag whether given configuration describes a test or mainnet
|
||||
TestNet bool
|
||||
// DevMode is true when given configuration is to be used during development.
|
||||
// For production, this flag should be turned off, so that more strict requirements
|
||||
// are applied to node's configuration
|
||||
DevMode bool
|
||||
|
||||
// NetworkID sets network to use for selecting peers to connect to
|
||||
NetworkID uint64 `json:"NetworkId,"`
|
||||
|
@ -183,6 +201,9 @@ type NodeConfig struct {
|
|||
// LogToStderr defines whether logged info should also be output to os.Stderr
|
||||
LogToStderr bool
|
||||
|
||||
// BootClusterConfig extra configuration for supporting cluster
|
||||
BootClusterConfig *BootClusterConfig `json:"BootClusterConfig,"`
|
||||
|
||||
// LightEthConfig extra configuration for LES
|
||||
LightEthConfig *LightEthConfig `json:"LightEthConfig,"`
|
||||
|
||||
|
@ -194,15 +215,15 @@ type NodeConfig struct {
|
|||
}
|
||||
|
||||
// NewNodeConfig creates new node configuration object
|
||||
func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
|
||||
func NewNodeConfig(dataDir string, networkID uint64, devMode bool) (*NodeConfig, error) {
|
||||
nodeConfig := &NodeConfig{
|
||||
DevMode: devMode,
|
||||
NetworkID: networkID,
|
||||
DataDir: dataDir,
|
||||
Name: ClientIdentifier,
|
||||
Version: Version,
|
||||
HTTPHost: HTTPHost,
|
||||
HTTPPort: HTTPPort,
|
||||
APIModules: APIModules,
|
||||
WSHost: WSHost,
|
||||
WSPort: WSPort,
|
||||
MaxPeers: MaxPeers,
|
||||
|
@ -215,6 +236,10 @@ func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
|
|||
Enabled: true,
|
||||
DatabaseCache: DatabaseCache,
|
||||
},
|
||||
BootClusterConfig: &BootClusterConfig{
|
||||
Enabled: true,
|
||||
ConfigFile: BootClusterConfigFile,
|
||||
},
|
||||
WhisperConfig: &WhisperConfig{
|
||||
Enabled: true,
|
||||
Port: WhisperPort,
|
||||
|
@ -227,64 +252,17 @@ func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
|
|||
SwarmConfig: &SwarmConfig{},
|
||||
}
|
||||
|
||||
// auto-populate some dependent values
|
||||
if err := nodeConfig.populateGenesis(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := nodeConfig.populateDirs(); err != nil {
|
||||
// adjust dependent values
|
||||
if err := nodeConfig.updateConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
|
||||
// populateDirs updates directories that should be wrt to DataDir
|
||||
func (c *NodeConfig) populateDirs() error {
|
||||
makeSubDirPath := func(baseDir, subDir string) string {
|
||||
if len(baseDir) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return filepath.Join(baseDir, subDir)
|
||||
}
|
||||
if len(c.KeyStoreDir) == 0 {
|
||||
c.KeyStoreDir = makeSubDirPath(c.DataDir, KeyStoreDir)
|
||||
}
|
||||
|
||||
if len(c.WhisperConfig.DataDir) == 0 {
|
||||
c.WhisperConfig.DataDir = makeSubDirPath(c.DataDir, WhisperDataDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateChainConfig does necessary adjustments to config object (depending on network node will be runnin on)
|
||||
func (c *NodeConfig) populateGenesis() error {
|
||||
c.TestNet = false
|
||||
if c.NetworkID == TestNetworkID {
|
||||
c.TestNet = true
|
||||
}
|
||||
|
||||
var genesis *core.Genesis
|
||||
if c.TestNet {
|
||||
genesis = core.DefaultTestnetGenesisBlock()
|
||||
} else {
|
||||
genesis = core.DefaultGenesisBlock()
|
||||
}
|
||||
|
||||
// encode the genesis into JSON
|
||||
enc, err := json.Marshal(genesis)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.LightEthConfig.Genesis = string(enc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadNodeConfig parses incoming JSON and returned it as Config
|
||||
func LoadNodeConfig(configJSON string) (*NodeConfig, error) {
|
||||
nodeConfig, err := NewNodeConfig("", 0)
|
||||
nodeConfig, err := NewNodeConfig("", 0, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -298,10 +276,7 @@ func LoadNodeConfig(configJSON string) (*NodeConfig, error) {
|
|||
}
|
||||
|
||||
// repopulate
|
||||
if err := nodeConfig.populateGenesis(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := nodeConfig.populateDirs(); err != nil {
|
||||
if err := nodeConfig.updateConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -336,6 +311,125 @@ func (c *NodeConfig) Save() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// LoadBootClusterNodes loads boot nodes from a config file provided in BootClusterConfig
|
||||
func (c *NodeConfig) LoadBootClusterNodes() ([]string, error) {
|
||||
var bootnodes []string
|
||||
var configData []byte
|
||||
var err error
|
||||
|
||||
filename := c.BootClusterConfig.ConfigFile
|
||||
log.Info("Loading boot nodes config file", "source", filename)
|
||||
if _, err = os.Stat(filename); os.IsNotExist(err) { // load from static resources
|
||||
configData, err = static.Asset("bootcluster/" + filename)
|
||||
} else {
|
||||
configData, err = ioutil.ReadFile(filename)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse JSON
|
||||
if err := json.Unmarshal([]byte(configData), &bootnodes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bootnodes, nil
|
||||
}
|
||||
|
||||
// updateConfig traverses configuration and adjusts dependent fields
|
||||
// (we have a development/production and mobile/full node dependent configurations)
|
||||
func (c *NodeConfig) updateConfig() error {
|
||||
if err := c.updateGenesisConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.updateRPCConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.updateBootClusterConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.updateRelativeDirsConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateGenesisConfig does necessary adjustments to config object (depending on network node will be running on)
|
||||
func (c *NodeConfig) updateGenesisConfig() error {
|
||||
var genesis *core.Genesis
|
||||
|
||||
switch c.NetworkID {
|
||||
case MainNetworkID:
|
||||
genesis = core.DefaultGenesisBlock()
|
||||
case RopstenNetworkID:
|
||||
genesis = core.DefaultTestnetGenesisBlock()
|
||||
case RinkebyNetworkID:
|
||||
genesis = core.DefaultRinkebyGenesisBlock()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// encode the genesis into JSON
|
||||
enc, err := json.Marshal(genesis)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.LightEthConfig.Genesis = string(enc)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateBootClusterConfig populates cluster config file, depending on dev/prod and mobile/full settings
|
||||
func (c *NodeConfig) updateBootClusterConfig() error {
|
||||
var configFile string
|
||||
switch c.NetworkID {
|
||||
case MainNetworkID:
|
||||
configFile = "homestead.prod.json"
|
||||
case RopstenNetworkID:
|
||||
configFile = "ropsten.prod.json"
|
||||
case RinkebyNetworkID:
|
||||
configFile = "rinkeby.prod.json"
|
||||
}
|
||||
if c.DevMode {
|
||||
configFile = strings.Replace(configFile, "prod", "dev", 1)
|
||||
}
|
||||
if len(configFile) > 0 {
|
||||
c.BootClusterConfig.ConfigFile = configFile
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateRPCConfig transforms RPC settings to meet requirements of a given configuration
|
||||
func (c *NodeConfig) updateRPCConfig() error {
|
||||
c.APIModules = ProdAPIModules
|
||||
if c.DevMode {
|
||||
c.APIModules = DevAPIModules
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateRelativeDirsConfig updates directories that should be wrt to DataDir
|
||||
func (c *NodeConfig) updateRelativeDirsConfig() error {
|
||||
makeSubDirPath := func(baseDir, subDir string) string {
|
||||
if len(baseDir) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return filepath.Join(baseDir, subDir)
|
||||
}
|
||||
if len(c.KeyStoreDir) == 0 {
|
||||
c.KeyStoreDir = makeSubDirPath(c.DataDir, KeyStoreDir)
|
||||
}
|
||||
|
||||
if len(c.WhisperConfig.DataDir) == 0 {
|
||||
c.WhisperConfig.DataDir = makeSubDirPath(c.DataDir, WhisperDataDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String dumps config object as nicely indented JSON
|
||||
func (c *NodeConfig) String() string {
|
||||
data, _ := json.MarshalIndent(c, "", " ")
|
||||
|
@ -354,6 +448,12 @@ func (c *SwarmConfig) String() string {
|
|||
return string(data)
|
||||
}
|
||||
|
||||
// String dumps config object as nicely indented JSON
|
||||
func (c *BootClusterConfig) String() string {
|
||||
data, _ := json.MarshalIndent(c, "", " ")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// ReadPasswordFile reads and returns content of the password file
|
||||
func (c *WhisperConfig) ReadPasswordFile() ([]byte, error) {
|
||||
if len(c.PasswordFile) <= 0 {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -285,8 +286,6 @@ var loadConfigTestCases = []struct {
|
|||
"WSEnabled": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
//nodeConfig.LightEthConfig.Genesis = nodeConfig.LightEthConfig.Genesis[:125]
|
||||
//fmt.Println(nodeConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -297,6 +296,509 @@ var loadConfigTestCases = []struct {
|
|||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`default boot cluster (Ropsten Dev)`,
|
||||
`{
|
||||
"NetworkId": 3,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("boot cluster is expected to be enabled by default")
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30379",
|
||||
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
|
||||
"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30379",
|
||||
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
|
||||
"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30379",
|
||||
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
|
||||
"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30379",
|
||||
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
|
||||
"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30379",
|
||||
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`disabled boot cluster`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"Enabled": false
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != false {
|
||||
t.Fatal("boot cluster is expected to be disabled")
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Ropsten Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "ropsten.prod.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := "ropsten.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30379",
|
||||
"enode://1fa2dfe6b925ca753496ea197c973b66ef889ef4de2bf52acd5b8665c0cc2e8b95fbd192e764f10735f589297f1ae533f350f004e403063e8d4ad979aae44c12@51.15.61.194:30303",
|
||||
"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30379",
|
||||
"enode://44b91c043bcd96bc5279524f1bfe32df0670374135435ebacb29ba5d0e18192623e63ead711c9c363afdf2500fac423116ac28bdd2d700bd70e096326f95c63f@51.15.35.2:30303",
|
||||
"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30379",
|
||||
"enode://fb7622d3a50dc603f5c76919dd99c4112e5925cb891a67086b9dce581166fbdad361fd0bfb7ff128ab8f5e24e209e0b923668fbddb7e8b99edb82c1e3d782a80@51.15.54.229:30303",
|
||||
"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30379",
|
||||
"enode://14c2960f57f6d63ed541cf64226aafbc7a21c40c6e4935a2e58fd2466fa7d06ec32082734c64d32f7c4692f4b90f26d019f472ba55cdda6d624ef4d7d8441285@51.15.35.70:30303",
|
||||
"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30379",
|
||||
"enode://02cfa2b02b5431bfdc1bad0f575de8ea151029fe9a9c689074793d704d1b428255bd111bf578f0b4fcaa18267da7c335db9557e1012434f4a8ab2c25f4b3da4d@51.15.39.57:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Rinkeby Dev)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "rinkeby.dev.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := "rinkeby.dev.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303",
|
||||
"enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303",
|
||||
"enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Rinkeby Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "rinkeby.prod.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := "rinkeby.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303",
|
||||
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
|
||||
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Homestead Dev)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "homestead.dev.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := "homestead.dev.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303",
|
||||
"enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303",
|
||||
"enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (Homestead Prod)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "homestead.prod.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := "homestead.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303",
|
||||
"enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303",
|
||||
"enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`select boot cluster (custom JSON, via absolute path)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR",
|
||||
"BootClusterConfig": {
|
||||
"ConfigFile": "$TMPDIR/bootstrap-cluster.json"
|
||||
}
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
expectedConfigFile := filepath.Join(dataDir, "bootstrap-cluster.json")
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedConfigFile {
|
||||
t.Fatalf("unexpected BootClusterConfigFile, expected: %v, got: %v",
|
||||
expectedConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
|
||||
enodes, err := nodeConfig.LoadBootClusterNodes()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expectedEnodes := []string{
|
||||
"enode://foobar@41.41.41.41:30300",
|
||||
"enode://foobaz@42.42.42.42:30302",
|
||||
}
|
||||
if len(enodes) != len(expectedEnodes) {
|
||||
t.Fatalf("wrong number of enodes, expected: %d, got: %d", len(expectedEnodes), len(enodes))
|
||||
}
|
||||
if !reflect.DeepEqual(enodes, expectedEnodes) {
|
||||
t.Fatalf("wrong list of enodes, expected: \n%v,\n\ngot:\n%v", expectedEnodes, enodes)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`default DevMode (true)`,
|
||||
`{
|
||||
"NetworkId": 311,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != true {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != params.BootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
params.BootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`explicit DevMode = false`,
|
||||
`{
|
||||
"NetworkId": 3,
|
||||
"DataDir": "$TMPDIR",
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != false {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "ropsten.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Homestead/Dev)`,
|
||||
`{
|
||||
"NetworkId": 1,
|
||||
"DataDir": "$TMPDIR",
|
||||
"DevMode": true
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != true {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "homestead.dev.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Homestead/Prod)`,
|
||||
`{
|
||||
"NetworkId": 1,
|
||||
"DataDir": "$TMPDIR",
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != false {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "homestead.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Ropsten/Dev)`,
|
||||
`{
|
||||
"NetworkId": 3,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != true {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "ropsten.dev.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Ropsten/Prod)`,
|
||||
`{
|
||||
"NetworkId": 3,
|
||||
"DataDir": "$TMPDIR",
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != false {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "ropsten.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Rinkeby/Dev)`,
|
||||
`{
|
||||
"NetworkId": 4,
|
||||
"DataDir": "$TMPDIR"
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != true {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", true, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "rinkeby.dev.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
`populate bootstrap config (Rinkeby/Prod)`,
|
||||
`{
|
||||
"NetworkId": 4,
|
||||
"DataDir": "$TMPDIR",
|
||||
"DevMode": false
|
||||
}`,
|
||||
func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if nodeConfig.DevMode != false {
|
||||
t.Fatalf("unexpected dev mode: expected: %v, got: %v", false, nodeConfig.DevMode)
|
||||
}
|
||||
|
||||
if nodeConfig.BootClusterConfig.Enabled != true {
|
||||
t.Fatal("expected boot cluster to be enabled")
|
||||
}
|
||||
|
||||
expectedBootClusterConfigFile := "rinkeby.prod.json"
|
||||
if nodeConfig.BootClusterConfig.ConfigFile != expectedBootClusterConfigFile {
|
||||
t.Fatalf("unexpected bootcluster config file, expected: %v, got: %v",
|
||||
expectedBootClusterConfigFile, nodeConfig.BootClusterConfig.ConfigFile)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestLoadNodeConfig(t *testing.T) {
|
||||
|
@ -306,6 +808,13 @@ func TestLoadNodeConfig(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||
|
||||
// create sample Bootstrap Cluster Config
|
||||
bootstrapConfig := []byte(`["enode://foobar@41.41.41.41:30300", "enode://foobaz@42.42.42.42:30302"]`)
|
||||
if err = ioutil.WriteFile(filepath.Join(tmpDir, "bootstrap-cluster.json"), bootstrapConfig, os.ModePerm); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(tmpDir)
|
||||
|
||||
for _, testCase := range loadConfigTestCases {
|
||||
t.Log("test: " + testCase.name)
|
||||
testCase.configJSON = strings.Replace(testCase.configJSON, "$TMPDIR", tmpDir, -1)
|
||||
|
@ -322,7 +831,7 @@ func TestConfigWriteRead(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||
|
||||
nodeConfig, err := params.NewNodeConfig(tmpDir, networkId)
|
||||
nodeConfig, err := params.NewNodeConfig(tmpDir, networkId, true)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot create new config object: %v", err)
|
||||
}
|
||||
|
@ -345,6 +854,7 @@ func TestConfigWriteRead(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
configReadWrite(params.TestNetworkID, "testdata/config.testnet.json")
|
||||
configReadWrite(params.RinkebyNetworkID, "testdata/config.rinkeby.json")
|
||||
configReadWrite(params.RopstenNetworkID, "testdata/config.ropsten.json")
|
||||
configReadWrite(params.MainNetworkID, "testdata/config.mainnet.json")
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@ const (
|
|||
// HTTPPort is HTTP-RPC port (replaced in unit tests)
|
||||
HTTPPort = 8545
|
||||
|
||||
// APIModules is a list of modules to expose vie HTTP RPC
|
||||
// TODO remove "admin" on main net
|
||||
APIModules = "db,eth,net,web3,shh,personal,admin"
|
||||
// DevAPIModules is a list of modules to expose via any type of RPC (HTTP, IPC) during development
|
||||
DevAPIModules = "db,eth,net,web3,shh,personal,admin"
|
||||
|
||||
// ProdAPIModules is a list of modules to expose via any type of RPC (HTTP, IPC) in production
|
||||
ProdAPIModules = "eth,net,web3,shh,personal"
|
||||
|
||||
// WSHost is a host interface for the websocket RPC server
|
||||
WSHost = "localhost"
|
||||
|
@ -72,6 +74,12 @@ const (
|
|||
// MainNetworkID is id of the main network
|
||||
MainNetworkID = 1
|
||||
|
||||
// TestNetworkID is id of a test network
|
||||
TestNetworkID = 3
|
||||
// RopstenNetworkID is id of a test network (on PoW)
|
||||
RopstenNetworkID = 3
|
||||
|
||||
// RinkebyNetworkID is id of a test network (on PoA)
|
||||
RinkebyNetworkID = 4
|
||||
|
||||
// BootClusterConfigFile is default config file containing boot node list (as JSON array)
|
||||
BootClusterConfigFile = "ropsten.dev.json"
|
||||
)
|
||||
|
|
|
@ -18,7 +18,7 @@ func TestLogger(t *testing.T) {
|
|||
}
|
||||
//defer os.RemoveAll(tmpDir)
|
||||
|
||||
nodeConfig, err := params.NewNodeConfig(tmpDir, params.TestNetworkID)
|
||||
nodeConfig, err := params.NewNodeConfig(tmpDir, params.RopstenNetworkID, true)
|
||||
if err != nil {
|
||||
t.Fatal("cannot create config object")
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -165,7 +165,7 @@ func PrepareTestNode() (err error) {
|
|||
}
|
||||
|
||||
// start geth node and wait for it to initialize
|
||||
config, err := params.NewNodeConfig(filepath.Join(TestDataDir, "data"), params.TestNetworkID)
|
||||
config, err := params.NewNodeConfig(filepath.Join(TestDataDir, "data"), params.RopstenNetworkID, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
"enode://93833be81c3d1bdb2ae5cde258c8f82ad1011a1bea8eb49fe50b0af394d4f7f7e45974356870552f36744efd732692a64865d1e8b64114eaf89a1bad0a1903a2@51.15.64.29:30303",
|
||||
"enode://d76854bc54144b2269c5316d5f00f0a194efee2fb8d31e7b1939effd7e17f25773f8dc7fda8c4eb469450799da7f39b4e364e2a278d91b53539dcbb10b139635@51.15.73.37:30303",
|
||||
"enode://57874205931df976079e4ff8ebb5756461030fb00f73486bd5ec4ae6ed6ba98e27d09f58e59bd85281d24084a6062bc8ab514dbcdaa9678fc3001d47772e626e@51.15.75.213:30303"
|
||||
]
|
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
"enode://f3b0e5dca730962bae814f3402b8f8a296644c33e8d7a95bd1ab313143a752c77076a03bcb76263570f2f34d4eb530f1daf5054c0990921a872a34eb505dcedf@51.15.73.129:30303",
|
||||
"enode://fce0d1c2292829b0eccce444f8943f88087ce00a5e910b157972ee1658a948d23c7a046f26567f73b2b18d126811509d7ef1de5be9b1decfcbb14738a590c477@51.15.75.187:30303",
|
||||
"enode://3b4b9fa02ae8d54c2db51a674bc93d85649b4775f22400f74ae25e9f1c665baa3bcdd33cadd2c1a93cd08a6af984cb605fbb61ec0d750a11d48d4080298af008@51.15.77.193:30303"
|
||||
]
|
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
"enode://7512c8f6e7ffdcc723cf77e602a1de9d8cc2e8ad35db309464819122cd773857131aee390fec33894db13da730c8432bb248eed64039e3810e156e979b2847cb@51.15.78.243:30303",
|
||||
"enode://1cc27a5a41130a5c8b90db5b2273dc28f7b56f3edfc0dcc57b665d451274b26541e8de49ea7a074281906a82209b9600239c981163b6ff85c3038a8e2bc5d8b8@51.15.68.93:30303",
|
||||
"enode://798d17064141b8f88df718028a8272b943d1cb8e696b3dab56519c70b77b1d3469b56b6f4ce3788457646808f5c7299e9116626f2281f30b959527b969a71e4f@51.15.75.244:30303"
|
||||
]
|
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
"enode://fda3f6273a0f2da4ac5858d1f52e5afaf9def281121be3d37558c67d4d9ca26c6ad7a0520b2cd7454120fb770e86d5760487c9924b2166e65485f606e56d60fc@51.15.69.144:30303",
|
||||
"enode://ba41aa829287a0a9076d9bffed97c8ce2e491b99873288c9e886f16fd575306ac6c656db4fbf814f5a9021aec004ffa9c0ae8650f92fd10c12eeb7c364593eb3@51.15.69.147:30303",
|
||||
"enode://28ecf5272b560ca951f4cd7f1eb8bd62da5853b026b46db432c4b01797f5b0114819a090a72acd7f32685365ecd8e00450074fa0673039aefe10f3fb666e0f3f@51.15.76.249:30303"
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
"enode://bc4a130219ae94c2a66e3ec3377c2a460e006d56b877d5e8edb0d0f8064cf400f117a53a5389f552c9e1a122b9a07eeaa41e7ed885268ee825b6a788188fb52e@51.15.55.219:30379",
|
||||
"enode://fbddff478e18292dc32b90f139bf773a08da89ffe29208e4de0091f6c589e60fccfaf16d4f4a76be49f57782c061ec8ea97078601c6f367feabda740f5ce8246@51.15.55.219:30303",
|
||||
|
||||
"enode://df20352d07924ffe93e67ee7e81105d7b250f7932ff4e0351da2cfa17282e53f765895c32cda36b70dfb98def0b472b29d79321737035641bf3bcf595dcc1041@51.15.35.110:30379",
|
||||
"enode://4e5ee0487a4d8349ab9a9925b00eed0f976d98972c5a22f43fd50d1424897757032c36f273b434a4d3e013a2544eca74a9d1a0419f9f07f7bb43182a73df3690@51.15.35.110:30303",
|
||||
|
||||
"enode://2cbcc7b3d067581072066143e0fade0d007e80ecc8f86eb475200c3da3a6d81dd4e1e7051fc3dfaee337f110ceec61594a901b09e36eb367629ddff6e1dfd955@51.15.34.3:30379",
|
||||
"enode://18efd9afb60443e00fed602cc0df526cd1d8543d2f6037df9380eb973d30b5fd04ac9f221053f82034581051bfd6e54356a99af2255f1a674d71d17440a6c95b@51.15.34.3:30303",
|
||||
|
||||
"enode://cdb95f3d866472a74195342979ffea4ed7f9b68cd1e8c6f9a25b3197c221f01bc076ccba760341d8b69bb6bfbc9bf4fdeabd0caa99ee0bf4e79917fa1f42423c@51.15.56.154:30379",
|
||||
"enode://5b99c0cb372299fd3f2d94612a682990722eb7c3a252dacefc8270eb7f172fc699c1ddfad826fbfc979270538e8d89bd6919703eb9ef526eac0a45e9fb455123@51.15.56.154:30303",
|
||||
|
||||
"enode://5ce8e96d9589671767a7b1c6b9a34bcf532587387eb062de712a9f716a66f05f412126121ce4d97330bc5dc7a4938ff1ecc22306b0b8b97a7f748c6f5f59c620@51.15.60.23:30379",
|
||||
"enode://0e1d4d0fcfe888bf8a478b0fd89760a47733a5c04cd47de353295a6eb8dde8f54821b31196527d0c5c73a7024dc9ff34127692d237840fc09c312b3a19cd28fe@51.15.60.23:30303"
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
"enode://6853f434735e540f0fcd85ffebcaa75280d1171ca9a205e8c41d87428d71b07ad14ab266236b64268467ccc462679edc888f76326418d18d7bcfe8d1159391aa@51.15.61.194:30379",
|
||||
"enode://1fa2dfe6b925ca753496ea197c973b66ef889ef4de2bf52acd5b8665c0cc2e8b95fbd192e764f10735f589297f1ae533f350f004e403063e8d4ad979aae44c12@51.15.61.194:30303",
|
||||
|
||||
"enode://a8f1dae49f665c566734e002f89c1feb9b01e3ed09bdea6199aa6093f25085c4777fd553d2d1d14457286c24aaa48eaf6db99315e0caf62d97ea8bce801ae7c1@51.15.35.2:30379",
|
||||
"enode://44b91c043bcd96bc5279524f1bfe32df0670374135435ebacb29ba5d0e18192623e63ead711c9c363afdf2500fac423116ac28bdd2d700bd70e096326f95c63f@51.15.35.2:30303",
|
||||
|
||||
"enode://64278f1e4224a5ff4608da54b7b045ae0b875a332c57e6f9b4cbb3e9ac1e56a1d5b91ff2def2662c767146b3f7f08924c15f66d41352a18ebe71832c35f6a0cf@51.15.54.229:30379",
|
||||
"enode://fb7622d3a50dc603f5c76919dd99c4112e5925cb891a67086b9dce581166fbdad361fd0bfb7ff128ab8f5e24e209e0b923668fbddb7e8b99edb82c1e3d782a80@51.15.54.229:30303",
|
||||
|
||||
"enode://e1fcf9e7a47ab43a546d1c1633c511d98d13646bbf5c82d74ff98a1c88e54567b0be6574e977164e1b4c997ef8e79b19f1e12e85a6230c746dd74206fe37cfa0@51.15.35.70:30379",
|
||||
"enode://14c2960f57f6d63ed541cf64226aafbc7a21c40c6e4935a2e58fd2466fa7d06ec32082734c64d32f7c4692f4b90f26d019f472ba55cdda6d624ef4d7d8441285@51.15.35.70:30303",
|
||||
|
||||
"enode://a8512bcaae1245fda71d400291dd22937d89947b6fc31283945557abe1281c5a9325ffc11e363cfed6362e4d2d9b941c5b325270662ba43ac8c424168e6567a6@51.15.39.57:30379",
|
||||
"enode://02cfa2b02b5431bfdc1bad0f575de8ea151029fe9a9c689074793d704d1b428255bd111bf578f0b4fcaa18267da7c335db9557e1012434f4a8ab2c25f4b3da4d@51.15.39.57:30303"
|
||||
]
|
|
@ -1,4 +1,4 @@
|
|||
// Package static embeds static (JS, HTML) resources right into the binaries
|
||||
package static
|
||||
|
||||
//go:generate go-bindata -pkg static -o bindata.go scripts/ config/ keys/
|
||||
//go:generate go-bindata -pkg static -o bindata.go scripts/ bootcluster/ config/ keys/
|
||||
|
|
|
@ -10,8 +10,8 @@ describe('Whisper Tests', function () {
|
|||
node1.setProvider(new web3.providers.HttpProvider('http://localhost:8645'));
|
||||
node2.setProvider(new web3.providers.HttpProvider('http://localhost:8745'));
|
||||
|
||||
console.log('Node is expected: statusd --datadir app1 --http --httpport 8645 wnode');
|
||||
console.log('Node is expected: statusd --datadir app2 --http --httpport 8745 wnode');
|
||||
console.log('Node is expected: statusd --datadir app1 wnode --http --httpport 8645');
|
||||
console.log('Node is expected: statusd --datadir app2 wnode --http --httpport 8745');
|
||||
console.log('Node is expected: statusd --datadir wnode1 wnode --notify --injectaccounts=false --identity ./static/keys/wnodekey --firebaseauth ./static/keys/firebaseauthkey');
|
||||
|
||||
// some common vars
|
||||
|
@ -216,9 +216,9 @@ describe('Whisper Tests', function () {
|
|||
assert.lengthOf(filterid1, 64);
|
||||
});
|
||||
|
||||
it('shh.getMessages(filterID) - symmetric filter', function () {
|
||||
it('shh.getFloatingMessages(filterID) - symmetric filter', function () {
|
||||
// let's try to capture message that was there *before* filter is created
|
||||
var messages = node1.shh.getMessages(filterid1);
|
||||
var messages = node1.shh.getFloatingMessages(filterid1);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 1);
|
||||
assert.equal(web3.toAscii(messages[0].payload), payloadBeforeSymFilter);
|
||||
|
@ -233,9 +233,9 @@ describe('Whisper Tests', function () {
|
|||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
|
||||
it('shh.getMessages(filterID) - asymmetric filter', function () {
|
||||
it('shh.getFloatingMessages(filterID) - asymmetric filter', function () {
|
||||
// let's try to capture message that was there *before* filter is created
|
||||
var messages = node1.shh.getMessages(filterid2);
|
||||
var messages = node1.shh.getFloatingMessages(filterid2);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 1);
|
||||
assert.equal(web3.toAscii(messages[0].payload), payloadBeforeAsymFilter);
|
||||
|
@ -250,17 +250,17 @@ describe('Whisper Tests', function () {
|
|||
expect(node1.shh.post(message)).to.equal(null);
|
||||
});
|
||||
|
||||
it('shh.getSubscriptionMessages(filterID) - symmetric filter', function (done) {
|
||||
it('shh.getNewSubscriptionMessages(filterID) - symmetric filter', function (done) {
|
||||
// allow some time for message to propagate
|
||||
setTimeout(function () {
|
||||
// now let's try to capture new messages from our last capture
|
||||
var messages = node1.shh.getSubscriptionMessages(filterid1);
|
||||
var messages = node1.shh.getNewSubscriptionMessages(filterid1);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 1);
|
||||
assert.equal(web3.toAscii(messages[0].payload), payloadAfterSymFilter);
|
||||
|
||||
// no more messages should be returned
|
||||
messages = node1.shh.getSubscriptionMessages(filterid1);
|
||||
messages = node1.shh.getNewSubscriptionMessages(filterid1);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 0);
|
||||
|
||||
|
@ -268,17 +268,17 @@ describe('Whisper Tests', function () {
|
|||
}, 200);
|
||||
});
|
||||
|
||||
it('shh.getSubscriptionMessages(filterID) - asymmetric filter', function () {
|
||||
it('shh.getNewSubscriptionMessages(filterID) - asymmetric filter', function () {
|
||||
// allow some time for message to propagate
|
||||
setTimeout(function () {
|
||||
// now let's try to capture new messages from our last capture
|
||||
var messages = node1.shh.getSubscriptionMessages(filterid2);
|
||||
var messages = node1.shh.getNewSubscriptionMessages(filterid2);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 1);
|
||||
assert.equal(web3.toAscii(messages[0].payload), payloadAfterAsymFilter);
|
||||
|
||||
// no more messages should be returned
|
||||
messages = node1.shh.getSubscriptionMessages(filterid2);
|
||||
messages = node1.shh.getNewSubscriptionMessages(filterid2);
|
||||
assert.typeOf(messages, 'array');
|
||||
assert.lengthOf(messages, 0);
|
||||
|
||||
|
|
|
@ -278,6 +278,18 @@ func DefaultTestnetGenesisBlock() *Genesis {
|
|||
}
|
||||
}
|
||||
|
||||
// DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block.
|
||||
func DefaultRinkebyGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
Config: params.RinkebyChainConfig,
|
||||
Timestamp: 1492009146,
|
||||
ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
|
||||
GasLimit: 4700000,
|
||||
Difficulty: big.NewInt(1),
|
||||
Alloc: decodePrealloc(rinkebyAllocData),
|
||||
}
|
||||
}
|
||||
|
||||
// DevGenesisBlock returns the 'geth --dev' genesis block.
|
||||
func DevGenesisBlock() *Genesis {
|
||||
return &Genesis{
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -50,6 +50,22 @@ var (
|
|||
Ethash: new(EthashConfig),
|
||||
}
|
||||
|
||||
// RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network.
|
||||
RinkebyChainConfig = &ChainConfig{
|
||||
ChainId: big.NewInt(4),
|
||||
HomesteadBlock: big.NewInt(1),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: true,
|
||||
EIP150Block: big.NewInt(2),
|
||||
EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
|
||||
EIP155Block: big.NewInt(3),
|
||||
EIP158Block: big.NewInt(3),
|
||||
Clique: &CliqueConfig{
|
||||
Period: 15,
|
||||
Epoch: 30000,
|
||||
},
|
||||
}
|
||||
|
||||
// AllProtocolChanges contains every protocol change (EIPs)
|
||||
// introduced and accepted by the Ethereum core developers.
|
||||
// TestChainConfig is like AllProtocolChanges but has chain ID 1.
|
||||
|
|
|
@ -81,7 +81,10 @@ func (s *discoveryService) processDiscoveryRequest(msg *whisper.ReceivedMessage)
|
|||
PoW: s.server.config.MinimumPoW,
|
||||
WorkTime: 5,
|
||||
}
|
||||
response := whisper.NewSentMessage(&msgParams)
|
||||
response, err := whisper.NewSentMessage(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create proposal message: %v", err)
|
||||
}
|
||||
env, err := response.Wrap(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wrap server proposal message: %v", err)
|
||||
|
@ -133,7 +136,10 @@ func (s *discoveryService) processServerAcceptedRequest(msg *whisper.ReceivedMes
|
|||
PoW: s.server.config.MinimumPoW,
|
||||
WorkTime: 5,
|
||||
}
|
||||
response := whisper.NewSentMessage(&msgParams)
|
||||
response, err := whisper.NewSentMessage(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create server proposal message: %v", err)
|
||||
}
|
||||
env, err := response.Wrap(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wrap server proposal message: %v", err)
|
||||
|
|
|
@ -324,7 +324,10 @@ func (s *NotificationServer) processNewChatSessionRequest(msg *whisper.ReceivedM
|
|||
PoW: s.config.MinimumPoW,
|
||||
WorkTime: 5,
|
||||
}
|
||||
response := whisper.NewSentMessage(&msgParams)
|
||||
response, err := whisper.NewSentMessage(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create server response message: %v", err)
|
||||
}
|
||||
env, err := response.Wrap(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wrap server response message: %v", err)
|
||||
|
@ -386,7 +389,10 @@ func (s *NotificationServer) processNewDeviceRegistrationRequest(msg *whisper.Re
|
|||
PoW: s.config.MinimumPoW,
|
||||
WorkTime: 5,
|
||||
}
|
||||
response := whisper.NewSentMessage(&msgParams)
|
||||
response, err := whisper.NewSentMessage(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create server response message: %v", err)
|
||||
}
|
||||
env, err := response.Wrap(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wrap server response message: %v", err)
|
||||
|
@ -459,7 +465,10 @@ func (s *NotificationServer) processClientSessionStatusRequest(msg *whisper.Rece
|
|||
PoW: s.config.MinimumPoW,
|
||||
WorkTime: 5,
|
||||
}
|
||||
response := whisper.NewSentMessage(&msgParams)
|
||||
response, err := whisper.NewSentMessage(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create server response message: %v", err)
|
||||
}
|
||||
env, err := response.Wrap(&msgParams)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to wrap server response message: %v", err)
|
||||
|
|
|
@ -3,6 +3,7 @@ package notifications
|
|||
import (
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"crypto/sha256"
|
||||
|
||||
crand "crypto/rand"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
|
||||
|
@ -14,8 +15,7 @@ import (
|
|||
func makeSessionKey() ([]byte, error) {
|
||||
// generate random key
|
||||
const keyLen = 32
|
||||
const size = keyLen * 2
|
||||
buf := make([]byte, size)
|
||||
buf := make([]byte, keyLen)
|
||||
_, err := crand.Read(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -24,8 +24,7 @@ func makeSessionKey() ([]byte, error) {
|
|||
}
|
||||
|
||||
key := buf[:keyLen]
|
||||
salt := buf[keyLen:]
|
||||
derived, err := whisper.DeriveOneTimeKey(key, salt, whisper.EnvelopeVersion)
|
||||
derived, err := deriveKeyMaterial(key, whisper.EnvelopeVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !validateSymmetricKey(derived) {
|
||||
|
@ -50,6 +49,19 @@ func containsOnlyZeros(data []byte) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// deriveKeyMaterial derives symmetric key material from the key or password./~~~
|
||||
// pbkdf2 is used for security, in case people use password instead of randomly generated keys.
|
||||
func deriveKeyMaterial(key []byte, version uint64) (derivedKey []byte, err error) {
|
||||
if version == 0 {
|
||||
// kdf should run no less than 0.1 seconds on average compute,
|
||||
// because it's a once in a session experience
|
||||
derivedKey := pbkdf2.Key(key, nil, 65356, 32, sha256.New)
|
||||
return derivedKey, nil
|
||||
} else {
|
||||
return nil, errors.New("unknown version")
|
||||
}
|
||||
}
|
||||
|
||||
// MakeTopic returns Whisper topic *as bytes array* by generating cryptographic key from the provided password
|
||||
func MakeTopicAsBytes(password []byte) ([]byte) {
|
||||
topic := make([]byte, int(whisper.TopicLength))
|
||||
|
|
|
@ -219,7 +219,6 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
|||
}
|
||||
|
||||
filter := Filter{
|
||||
Src: crypto.ToECDSAPub(common.FromHex(args.Sig)),
|
||||
PoW: args.MinPoW,
|
||||
Messages: make(map[common.Hash]*ReceivedMessage),
|
||||
AllowP2P: args.AllowP2P,
|
||||
|
@ -243,8 +242,13 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
|
|||
}
|
||||
|
||||
if len(args.Sig) > 0 {
|
||||
sb := common.FromHex(args.Sig)
|
||||
if sb == nil {
|
||||
return "", errors.New("subscribe: sig parameter is invalid")
|
||||
}
|
||||
filter.Src = crypto.ToECDSAPub(sb)
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
return "", errors.New("subscribe: sig invalid is invalid")
|
||||
return "", errors.New("subscribe: invalid 'sig' field")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,14 +288,15 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
|
|||
api.whisper.Unsubscribe(id)
|
||||
}
|
||||
|
||||
// GetFilterChanges is alias for GetSubscriptionMessages
|
||||
// GetFilterChanges is alias for GetNewSubscriptionMessages
|
||||
func (api *PublicWhisperAPI) GetFilterChanges(filterId string) []*WhisperMessage {
|
||||
return api.GetSubscriptionMessages(filterId)
|
||||
return api.GetNewSubscriptionMessages(filterId)
|
||||
}
|
||||
|
||||
// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
|
||||
func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
|
||||
f := api.whisper.GetFilter(filterId)
|
||||
// GetNewSubscriptionMessages retrieves all the new messages matched by the corresponding
|
||||
// subscription filter since the last retrieval.
|
||||
func (api *PublicWhisperAPI) GetNewSubscriptionMessages(id string) []*WhisperMessage {
|
||||
f := api.whisper.GetFilter(id)
|
||||
if f != nil {
|
||||
newMail := f.Retrieve()
|
||||
return toWhisperMessages(newMail)
|
||||
|
@ -299,10 +304,10 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
|
|||
return toWhisperMessages(nil)
|
||||
}
|
||||
|
||||
// GetMessages retrieves all the floating messages that match a specific filter.
|
||||
// GetMessages retrieves all the floating messages that match a specific subscription filter.
|
||||
// It is likely to be called once per session, right after Subscribe call.
|
||||
func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
|
||||
all := api.whisper.Messages(filterId)
|
||||
func (api *PublicWhisperAPI) GetFloatingMessages(id string) []*WhisperMessage {
|
||||
all := api.whisper.Messages(id)
|
||||
return toWhisperMessages(all)
|
||||
}
|
||||
|
||||
|
@ -365,7 +370,11 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||
return errors.New("post: topic is missing for symmetric encryption")
|
||||
}
|
||||
} else if args.Type == "asym" {
|
||||
params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
|
||||
kb := common.FromHex(args.Key)
|
||||
if kb == nil {
|
||||
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||
}
|
||||
params.Dst = crypto.ToECDSAPub(kb)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
return errors.New("post: public key for asymmetric encryption is invalid")
|
||||
}
|
||||
|
@ -374,9 +383,9 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
|
|||
}
|
||||
|
||||
// encrypt and send
|
||||
message := NewSentMessage(¶ms)
|
||||
if message == nil {
|
||||
return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
|
||||
message, err := NewSentMessage(¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envelope, err := message.Wrap(¶ms)
|
||||
if err != nil {
|
||||
|
@ -403,7 +412,7 @@ type PostArgs struct {
|
|||
Type string `json:"type"` // "sym"/"asym" (symmetric or asymmetric)
|
||||
TTL uint32 `json:"ttl"` // time-to-live in seconds
|
||||
Sig string `json:"sig"` // id of the signing key
|
||||
Key string `json:"key"` // id of encryption key
|
||||
Key string `json:"key"` // key id (in case of sym) or public key (in case of asym)
|
||||
Topic hexutil.Bytes `json:"topic"` // topic (4 bytes)
|
||||
Padding hexutil.Bytes `json:"padding"` // optional padding bytes
|
||||
Payload hexutil.Bytes `json:"payload"` // payload to be encrypted
|
||||
|
@ -544,7 +553,6 @@ type WhisperMessage struct {
|
|||
// NewWhisperMessage converts an internal message into an API version.
|
||||
func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
|
||||
msg := WhisperMessage{
|
||||
Topic: common.ToHex(message.Topic[:]),
|
||||
Payload: common.ToHex(message.Payload),
|
||||
Padding: common.ToHex(message.Padding),
|
||||
Timestamp: message.Sent,
|
||||
|
@ -553,11 +561,20 @@ func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
|
|||
Hash: common.ToHex(message.EnvelopeHash.Bytes()),
|
||||
}
|
||||
|
||||
if len(message.Topic) == TopicLength {
|
||||
msg.Topic = common.ToHex(message.Topic[:])
|
||||
}
|
||||
if message.Dst != nil {
|
||||
msg.Dst = common.ToHex(crypto.FromECDSAPub(message.Dst))
|
||||
b := crypto.FromECDSAPub(message.Dst)
|
||||
if b != nil {
|
||||
msg.Dst = common.ToHex(b)
|
||||
}
|
||||
}
|
||||
if isMessageSigned(message.Raw[0]) {
|
||||
msg.Src = common.ToHex(crypto.FromECDSAPub(message.SigToPubKey()))
|
||||
b := crypto.FromECDSAPub(message.SigToPubKey())
|
||||
if b != nil {
|
||||
msg.Src = common.ToHex(b)
|
||||
}
|
||||
}
|
||||
return &msg
|
||||
}
|
||||
|
|
|
@ -51,19 +51,17 @@ const (
|
|||
paddingMask = byte(3)
|
||||
signatureFlag = byte(4)
|
||||
|
||||
TopicLength = 4
|
||||
signatureLength = 65
|
||||
aesKeyLength = 32
|
||||
saltLength = 12
|
||||
AESNonceMaxLength = 12
|
||||
keyIdSize = 32
|
||||
TopicLength = 4
|
||||
signatureLength = 65
|
||||
aesKeyLength = 32
|
||||
AESNonceLength = 12
|
||||
keyIdSize = 32
|
||||
|
||||
DefaultMaxMessageLength = 1024 * 1024
|
||||
DefaultMinimumPoWTime = 2 // todo: review after testing.
|
||||
DefaultMinimumPoW = 0.001 // todo: review after testing.
|
||||
|
||||
padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
|
||||
padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
|
||||
padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24)
|
||||
messageQueueLimit = 1024
|
||||
|
||||
expirationCycle = time.Second
|
||||
|
|
|
@ -40,7 +40,6 @@ type Envelope struct {
|
|||
Expiry uint32
|
||||
TTL uint32
|
||||
Topic TopicType
|
||||
Salt []byte
|
||||
AESNonce []byte
|
||||
Data []byte
|
||||
EnvNonce uint64
|
||||
|
@ -50,15 +49,25 @@ type Envelope struct {
|
|||
// Don't access hash directly, use Hash() function instead.
|
||||
}
|
||||
|
||||
// size returns the size of envelope as it is sent (i.e. public fields only)
|
||||
func (e *Envelope) size() int {
|
||||
return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
|
||||
}
|
||||
|
||||
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
||||
func (e *Envelope) rlpWithoutNonce() []byte {
|
||||
res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
|
||||
return res
|
||||
}
|
||||
|
||||
// NewEnvelope wraps a Whisper message with expiration and destination data
|
||||
// included into an envelope for network forwarding.
|
||||
func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope {
|
||||
func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *SentMessage) *Envelope {
|
||||
env := Envelope{
|
||||
Version: make([]byte, 1),
|
||||
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
|
||||
TTL: ttl,
|
||||
Topic: topic,
|
||||
Salt: salt,
|
||||
AESNonce: aesNonce,
|
||||
Data: msg.Raw,
|
||||
EnvNonce: 0,
|
||||
|
@ -126,10 +135,6 @@ func (e *Envelope) Seal(options *MessageParams) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (e *Envelope) size() int {
|
||||
return len(e.Data) + len(e.Version) + len(e.AESNonce) + len(e.Salt) + 20
|
||||
}
|
||||
|
||||
func (e *Envelope) PoW() float64 {
|
||||
if e.pow == 0 {
|
||||
e.calculatePoW(0)
|
||||
|
@ -159,12 +164,6 @@ func (e *Envelope) powToFirstBit(pow float64) int {
|
|||
return int(bits)
|
||||
}
|
||||
|
||||
// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
|
||||
func (e *Envelope) rlpWithoutNonce() []byte {
|
||||
res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data})
|
||||
return res
|
||||
}
|
||||
|
||||
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
|
||||
func (e *Envelope) Hash() common.Hash {
|
||||
if (e.hash == common.Hash{}) {
|
||||
|
@ -210,7 +209,7 @@ func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, erro
|
|||
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
|
||||
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
|
||||
msg = &ReceivedMessage{Raw: e.Data}
|
||||
err = msg.decryptSymmetric(key, e.Salt, e.AESNonce)
|
||||
err = msg.decryptSymmetric(key, e.AESNonce)
|
||||
if err != nil {
|
||||
msg = nil
|
||||
}
|
||||
|
|
|
@ -23,14 +23,14 @@ import (
|
|||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
// Options specifies the exact way a message should be wrapped into an Envelope.
|
||||
|
@ -86,58 +86,76 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
|
|||
return msg.Dst != nil
|
||||
}
|
||||
|
||||
func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
|
||||
if version == 0 {
|
||||
derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
|
||||
return derivedKey, nil
|
||||
} else {
|
||||
return nil, unknownVersionError(version)
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
|
||||
func NewSentMessage(params *MessageParams) *SentMessage {
|
||||
func NewSentMessage(params *MessageParams) (*SentMessage, error) {
|
||||
msg := SentMessage{}
|
||||
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
|
||||
msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
|
||||
msg.Raw[0] = 0 // set all the flags to zero
|
||||
err := msg.appendPadding(params)
|
||||
if err != nil {
|
||||
log.Error("failed to create NewSentMessage", "err", err)
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
msg.Raw = append(msg.Raw, params.Payload...)
|
||||
return &msg
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes)
|
||||
func getSizeOfLength(b []byte) (sz int, err error) {
|
||||
sz = intSize(len(b)) // first iteration
|
||||
sz = intSize(len(b) + sz) // second iteration
|
||||
if sz > 3 {
|
||||
err = errors.New("oversized padding parameter")
|
||||
}
|
||||
return sz, err
|
||||
}
|
||||
|
||||
// sizeOfIntSize returns minimal number of bytes necessary to encode an integer value
|
||||
func intSize(i int) (s int) {
|
||||
for s = 1; i >= 256; s++ {
|
||||
i /= 256
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
|
||||
// The last byte contains the size of padding (thus, its size must not exceed 256).
|
||||
func (msg *SentMessage) appendPadding(params *MessageParams) error {
|
||||
total := len(params.Payload) + 1
|
||||
rawSize := len(params.Payload) + 1
|
||||
if params.Src != nil {
|
||||
total += signatureLength
|
||||
rawSize += signatureLength
|
||||
}
|
||||
padChunk := padSizeLimitUpper
|
||||
if total <= padSizeLimitLower {
|
||||
padChunk = padSizeLimitLower
|
||||
}
|
||||
odd := total % padChunk
|
||||
if odd > 0 {
|
||||
padSize := padChunk - odd
|
||||
if padSize > 255 {
|
||||
// this algorithm is only valid if padSizeLimitUpper <= 256.
|
||||
// if padSizeLimitUpper will ever change, please fix the algorithm
|
||||
// (for more information see ReceivedMessage.extractPadding() function).
|
||||
odd := rawSize % padSizeLimit
|
||||
|
||||
if len(params.Padding) != 0 {
|
||||
padSize := len(params.Padding)
|
||||
padLengthSize, err := getSizeOfLength(params.Padding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
totalPadSize := padSize + padLengthSize
|
||||
buf := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
|
||||
buf = buf[:padLengthSize]
|
||||
msg.Raw = append(msg.Raw, buf...)
|
||||
msg.Raw = append(msg.Raw, params.Padding...)
|
||||
msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
|
||||
} else if odd != 0 {
|
||||
totalPadSize := padSizeLimit - odd
|
||||
if totalPadSize > 255 {
|
||||
// this algorithm is only valid if padSizeLimit < 256.
|
||||
// if padSizeLimit will ever change, please fix the algorithm
|
||||
// (please see also ReceivedMessage.extractPadding() function).
|
||||
panic("please fix the padding algorithm before releasing new version")
|
||||
}
|
||||
buf := make([]byte, padSize)
|
||||
buf := make([]byte, totalPadSize)
|
||||
_, err := crand.Read(buf[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf[0] = byte(padSize)
|
||||
if params.Padding != nil {
|
||||
copy(buf[1:], params.Padding)
|
||||
if totalPadSize > 6 && !validateSymmetricKey(buf) {
|
||||
return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
|
||||
}
|
||||
buf[0] = byte(totalPadSize)
|
||||
msg.Raw = append(msg.Raw, buf...)
|
||||
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
|
||||
}
|
||||
|
@ -178,46 +196,31 @@ func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
|
|||
|
||||
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
|
||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||
func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
|
||||
func (msg *SentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
|
||||
if !validateSymmetricKey(key) {
|
||||
return nil, nil, errors.New("invalid key provided for symmetric encryption")
|
||||
return nil, errors.New("invalid key provided for symmetric encryption")
|
||||
}
|
||||
|
||||
salt = make([]byte, saltLength)
|
||||
_, err = crand.Read(salt)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if !validateSymmetricKey(salt) {
|
||||
return nil, nil, errors.New("crypto/rand failed to generate salt")
|
||||
}
|
||||
|
||||
derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !validateSymmetricKey(derivedKey) {
|
||||
return nil, nil, errors.New("failed to derive one-time key")
|
||||
}
|
||||
block, err := aes.NewCipher(derivedKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
aesgcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// never use more than 2^32 random nonces with a given key
|
||||
nonce = make([]byte, aesgcm.NonceSize())
|
||||
_, err = crand.Read(nonce)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
} else if !validateSymmetricKey(nonce) {
|
||||
return nil, nil, errors.New("crypto/rand failed to generate nonce")
|
||||
return nil, errors.New("crypto/rand failed to generate nonce")
|
||||
}
|
||||
|
||||
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
|
||||
return salt, nonce, nil
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// Wrap bundles the message into an Envelope to transmit over the network.
|
||||
|
@ -231,11 +234,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
var salt, nonce []byte
|
||||
var nonce []byte
|
||||
if options.Dst != nil {
|
||||
err = msg.encryptAsymmetric(options.Dst)
|
||||
} else if options.KeySym != nil {
|
||||
salt, nonce, err = msg.encryptSymmetric(options.KeySym)
|
||||
nonce, err = msg.encryptSymmetric(options.KeySym)
|
||||
} else {
|
||||
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
|
||||
}
|
||||
|
@ -244,7 +247,7 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
return nil, err
|
||||
}
|
||||
|
||||
envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
|
||||
envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
|
||||
err = envelope.Seal(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -254,13 +257,8 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
|
|||
|
||||
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
|
||||
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
|
||||
func (msg *ReceivedMessage) decryptSymmetric(key []byte, salt []byte, nonce []byte) error {
|
||||
derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(derivedKey)
|
||||
func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -323,7 +321,8 @@ func (msg *ReceivedMessage) Validate() bool {
|
|||
// can be successfully decrypted.
|
||||
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
|
||||
paddingSize := 0
|
||||
sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
|
||||
sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
|
||||
// could be zero -- it means no padding
|
||||
if sz != 0 {
|
||||
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
|
||||
if paddingSize < sz || paddingSize+1 > end {
|
||||
|
|
|
@ -149,23 +149,22 @@ func (peer *Peer) expire() {
|
|||
// broadcast iterates over the collection of envelopes and transmits yet unknown
|
||||
// ones over the network.
|
||||
func (p *Peer) broadcast() error {
|
||||
// Fetch the envelopes and collect the unknown ones
|
||||
var cnt int
|
||||
envelopes := p.host.Envelopes()
|
||||
transmit := make([]*Envelope, 0, len(envelopes))
|
||||
for _, envelope := range envelopes {
|
||||
if !p.marked(envelope) {
|
||||
transmit = append(transmit, envelope)
|
||||
p.mark(envelope)
|
||||
err := p2p.Send(p.ws, messagesCode, envelope)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.mark(envelope)
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(transmit) == 0 {
|
||||
return nil
|
||||
if cnt > 0 {
|
||||
log.Trace("broadcast", "num. messages", cnt)
|
||||
}
|
||||
// Transmit the unknown batch (potentially empty)
|
||||
if err := p2p.Send(p.ws, messagesCode, transmit); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Trace("broadcast", "num. messages", len(transmit))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -331,24 +331,14 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
|
|||
// GenerateSymKey generates a random symmetric key and stores it under id,
|
||||
// which is then returned. Will be used in the future for session key exchange.
|
||||
func (w *Whisper) GenerateSymKey() (string, error) {
|
||||
const size = aesKeyLength * 2
|
||||
buf := make([]byte, size)
|
||||
_, err := crand.Read(buf)
|
||||
key := make([]byte, aesKeyLength)
|
||||
_, err := crand.Read(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if !validateSymmetricKey(buf) {
|
||||
} else if !validateSymmetricKey(key) {
|
||||
return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
|
||||
}
|
||||
|
||||
key := buf[:aesKeyLength]
|
||||
salt := buf[aesKeyLength:]
|
||||
derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if !validateSymmetricKey(derived) {
|
||||
return "", fmt.Errorf("failed to derive valid key")
|
||||
}
|
||||
|
||||
id, err := GenerateRandomID()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate ID: %s", err)
|
||||
|
@ -360,7 +350,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
|
|||
if w.symKeys[id] != nil {
|
||||
return "", fmt.Errorf("failed to generate unique ID")
|
||||
}
|
||||
w.symKeys[id] = derived
|
||||
w.symKeys[id] = key
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
@ -481,6 +471,9 @@ func (w *Whisper) Unsubscribe(id string) error {
|
|||
// network in the coming cycles.
|
||||
func (w *Whisper) Send(envelope *Envelope) error {
|
||||
ok, err := w.add(envelope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to add envelope")
|
||||
}
|
||||
|
@ -568,21 +561,18 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
|
|||
log.Warn("unxepected status message received", "peer", p.peer.ID())
|
||||
case messagesCode:
|
||||
// decode the contained envelopes
|
||||
var envelopes []*Envelope
|
||||
if err := packet.Decode(&envelopes); err != nil {
|
||||
var envelope Envelope
|
||||
if err := packet.Decode(&envelope); err != nil {
|
||||
log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
return errors.New("invalid envelope")
|
||||
}
|
||||
// inject all envelopes into the internal pool
|
||||
for _, envelope := range envelopes {
|
||||
cached, err := wh.add(envelope)
|
||||
if err != nil {
|
||||
log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
return errors.New("invalid envelope")
|
||||
}
|
||||
if cached {
|
||||
p.mark(envelope)
|
||||
}
|
||||
cached, err := wh.add(&envelope)
|
||||
if err != nil {
|
||||
log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
|
||||
return errors.New("invalid envelope")
|
||||
}
|
||||
if cached {
|
||||
p.mark(&envelope)
|
||||
}
|
||||
case p2pCode:
|
||||
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
|
||||
|
@ -649,14 +639,11 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
|
|||
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
|
||||
}
|
||||
|
||||
if len(envelope.AESNonce) > AESNonceMaxLength {
|
||||
// the standard AES GSM nonce size is 12,
|
||||
// but const gcmStandardNonceSize cannot be accessed directly
|
||||
return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
|
||||
}
|
||||
|
||||
if len(envelope.Salt) > saltLength {
|
||||
return false, fmt.Errorf("oversized salt [%x]", envelope.Hash())
|
||||
aesNonceSize := len(envelope.AESNonce)
|
||||
if aesNonceSize != 0 && aesNonceSize != AESNonceLength {
|
||||
// the standard AES GCM nonce size is 12 bytes,
|
||||
// but constant gcmStandardNonceSize cannot be accessed (not exported)
|
||||
return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash())
|
||||
}
|
||||
|
||||
if envelope.PoW() < wh.minPoW {
|
||||
|
|
Loading…
Reference in New Issue