// p2p flags
runNodeCmd.Flags().String("p2p.laddr", config.P2P.ListenAddress, "Node listen address. (0.0.0.0:0 means any interface, any port)")
runNodeCmd.Flags().String("p2p.seeds", config.P2P.Seeds, "Comma delimited host:port seed nodes")
+ runNodeCmd.Flags().String("p2p.node_key", config.P2P.PrivateKey, "Node key for p2p communication")
runNodeCmd.Flags().Bool("p2p.skip_upnp", config.P2P.SkipUPNP, "Skip UPNP configuration")
runNodeCmd.Flags().Int("p2p.max_num_peers", config.P2P.MaxNumPeers, "Set max num peers")
runNodeCmd.Flags().Int("p2p.handshake_timeout", config.P2P.HandshakeTimeout, "Set handshake timeout")
package config
import (
+ "io"
+ "io/ioutil"
"os"
"os/user"
"path/filepath"
"runtime"
log "github.com/sirupsen/logrus"
+ "github.com/tendermint/go-crypto"
)
var (
return cfg
}
+// NodeKey retrieves the currently configured private key of the node, checking
+// first any manually set key, falling back to the one found in the configured
+// data folder. If no key can be found, a new one is generated.
+func (cfg *Config) NodeKey() (string, error) {
+ // Use any specifically configured key.
+ if cfg.P2P.PrivateKey != "" {
+ return cfg.P2P.PrivateKey, nil
+ }
+
+ keyFile := rootify(cfg.P2P.NodeKeyFile, cfg.BaseConfig.RootDir)
+ buf := make([]byte, len(crypto.PrivKeyEd25519{})*2)
+ fd, err := os.Open(keyFile)
+ defer fd.Close()
+ if err == nil {
+ if _, err = io.ReadFull(fd, buf); err == nil {
+ return string(buf), nil
+ }
+ }
+
+ log.WithField("err", err).Warning("key file access failed")
+ privKey := crypto.GenPrivKeyEd25519()
+ if err = ioutil.WriteFile(keyFile, []byte(privKey.String()), 0600); err != nil {
+ return "", err
+ }
+
+ return privKey.String(), nil
+}
+
//-----------------------------------------------------------------------------
// BaseConfig
type BaseConfig struct {
type P2PConfig struct {
ListenAddress string `mapstructure:"laddr"`
Seeds string `mapstructure:"seeds"`
+ PrivateKey string `mapstructure:"node_key"`
+ NodeKeyFile string `mapstructure:"node_key_file"`
SkipUPNP bool `mapstructure:"skip_upnp"`
MaxNumPeers int `mapstructure:"max_num_peers"`
HandshakeTimeout int `mapstructure:"handshake_timeout"`
func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{
ListenAddress: "tcp://0.0.0.0:46656",
+ NodeKeyFile: "nodekey",
SkipUPNP: false,
MaxNumPeers: 50,
HandshakeTimeout: 30,
package config
import (
+ "io/ioutil"
+ "os"
+ "strings"
"testing"
"github.com/stretchr/testify/assert"
assert.Equal("/opt/data", cfg.DBDir())
}
+
+func TestNodeKey(t *testing.T) {
+ tmpDir, err := ioutil.TempDir(".", "")
+ if err != nil {
+ t.Fatalf("failed to create temporary data folder: %v", err)
+ }
+ defer os.RemoveAll(tmpDir)
+ config := DefaultConfig()
+ config.BaseConfig.RootDir = tmpDir
+
+ config.P2P.PrivateKey = "0fcbd0be11e35c35c41c686b7ca597bbcf8ecb78e320d01a93349c8ce9420ea4f26d0fbe651bb2c248d6727801329b589ed19e384c9e906d1da4ab2360558bc0"
+ privKey, err := config.NodeKey()
+ if err != nil {
+ t.Fatal("test node key error:", err)
+ }
+
+ if strings.Compare(privKey, config.P2P.PrivateKey) != 0 {
+ t.Fatal("test node key error. want:", config.P2P.PrivateKey, "got:", privKey)
+ }
+
+ config.P2P.PrivateKey = ""
+ writePrivKey, err := config.NodeKey()
+ if err != nil {
+ t.Fatal("test node key error:", err)
+ }
+
+ readPrivKey, err := config.NodeKey()
+ if err != nil {
+ t.Fatal("test node key error:", err)
+ }
+
+ if strings.Compare(writePrivKey, readPrivKey) != 0 {
+ t.Fatal("test node key error. write:", writePrivKey, "read:", readPrivKey)
+ }
+}
package p2p
import (
+ "encoding/hex"
"encoding/json"
"fmt"
"net"
// NewSwitch create a new Switch and set discover.
func NewSwitch(config *cfg.Config) (*Switch, error) {
- blacklistDB := dbm.NewDB("trusthistory", config.DBBackend, config.DBDir())
- privKey := crypto.GenPrivKeyEd25519()
+ var err error
var l Listener
var listenAddr string
- var err error
var discv *discover.Network
+
+ blacklistDB := dbm.NewDB("trusthistory", config.DBBackend, config.DBDir())
+ config.P2P.PrivateKey, err = config.NodeKey()
+ if err != nil {
+ return nil, err
+ }
+
+ bytes, err := hex.DecodeString(config.P2P.PrivateKey)
+ if err != nil {
+ return nil, err
+ }
+
+ var newKey [64]byte
+ copy(newKey[:], bytes)
+ privKey := crypto.PrivKeyEd25519(newKey)
if !config.VaultMode {
// Create listener
l, listenAddr = GetListener(config.P2P)
}
}
- return newSwitch(discv, blacklistDB, l, config, privKey, listenAddr)
+ return newSwitch(config, discv, blacklistDB, l, privKey, listenAddr)
}
// newSwitch creates a new Switch with the given config.
-func newSwitch(discv discv, blacklistDB dbm.DB, l Listener, config *cfg.Config, priv crypto.PrivKeyEd25519, listenAddr string) (*Switch, error) {
+func newSwitch(config *cfg.Config, discv discv, blacklistDB dbm.DB, l Listener, priv crypto.PrivKeyEd25519, listenAddr string) (*Switch, error) {
sw := &Switch{
Config: config,
peerConfig: DefaultPeerConfig(config.P2P),
package p2p
import (
+ "github.com/tendermint/go-crypto"
+ dbm "github.com/tendermint/tmlibs/db"
"io/ioutil"
"os"
"sync"
"testing"
- "time"
-
- "github.com/tendermint/go-crypto"
- dbm "github.com/tendermint/tmlibs/db"
cfg "github.com/bytom/config"
"github.com/bytom/errors"
}
//S1 dialing itself ip address
- addr, err := NewNetAddressString(s1.NodeInfo().ListenAddr)
+ addr, err := NewNetAddressString("0.0.0.0:46656")
if err != nil {
t.Fatal(err)
}
}
}
-func TestDuplicatePeer(t *testing.T) {
+func TestDuplicateOutBoundPeer(t *testing.T) {
dirPath, err := ioutil.TempDir(".", "")
if err != nil {
t.Fatal(err)
if err = s1.DialPeerWithAddress(rp.addr); errors.Root(err) != ErrDuplicatePeer {
t.Fatal(err)
}
+}
+
+func TestDuplicateInBoundPeer(t *testing.T) {
+ dirPath, err := ioutil.TempDir(".", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dirPath)
+
+ testDB := dbm.NewDB("testdb", "leveldb", dirPath)
+ s1 := MakeSwitch(testCfg, testDB, initSwitchFunc)
+ s1.Start()
+ defer s1.Stop()
inp := &inboundPeer{PrivKey: crypto.GenPrivKeyEd25519(), config: testCfg}
- addr, err := NewNetAddressString(s1.NodeInfo().ListenAddr)
+ addr, err := NewNetAddressString(s1.nodeInfo.ListenAddr)
if err != nil {
t.Fatal(err)
}
t.Fatal(err)
}
- time.Sleep(1 * time.Second)
- if outbound, inbound, dialing := s1.NumPeers(); outbound+inbound+dialing != 2 {
- t.Fatal("TestSwitchAddInboundPeer peer size error")
+ if outbound, inbound, dialing := s1.NumPeers(); outbound+inbound+dialing != 1 {
+ t.Fatal("TestSwitchAddInboundPeer peer size error", outbound, inbound, dialing)
}
}
defer s1.Stop()
inp := &inboundPeer{PrivKey: crypto.GenPrivKeyEd25519(), config: testCfg}
- addr, err := NewNetAddressString(s1.NodeInfo().ListenAddr)
+ addr, err := NewNetAddressString(s1.nodeInfo.ListenAddr)
if err != nil {
t.Fatal(err)
}
defer s1.Stop()
inp := &inboundPeer{PrivKey: crypto.GenPrivKeyEd25519(), config: testCfg}
- addr, err := NewNetAddressString(s1.NodeInfo().ListenAddr)
+ addr, err := NewNetAddressString("127.0.0.1:46656")
if err != nil {
t.Fatal(err)
}
// TODO: let the config be passed in?
privKey := crypto.GenPrivKeyEd25519()
l, listenAddr := GetListener(cfg.P2P)
- sw, err := newSwitch(new(mockDiscv), testdb, l, cfg, privKey, listenAddr)
+ sw, err := newSwitch(cfg, new(mockDiscv), testdb, l, privKey, listenAddr)
if err != nil {
log.Errorf("create switch error: %s", err)
return nil
package crypto
import (
+ "encoding/hex"
+
"github.com/tendermint/ed25519"
"github.com/tendermint/go-wire"
- data "github.com/tendermint/go-wire/data"
- . "github.com/tendermint/tmlibs/common"
+ "github.com/tendermint/go-wire/data"
)
func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) {
}
func (privKey PrivKeyEd25519) String() string {
- return Fmt("PrivKeyEd25519{*****}")
+ return hex.EncodeToString(privKey[:])
}
func GenPrivKeyEd25519() PrivKeyEd25519 {