From 6a330d7cc312143dc9b1a48721c07b9671102bcc Mon Sep 17 00:00:00 2001 From: yahtoo Date: Wed, 20 Feb 2019 12:06:43 +0800 Subject: [PATCH] P2P: fixed node startup id (#1573) * P2P: fixed node startup id * Add test file * Fix test error * Fix review bug * Fix test error * Add log info --- cmd/bytomd/commands/run_node.go | 1 + config/config.go | 34 +++++++++++++++++++ config/config_test.go | 38 ++++++++++++++++++++++ p2p/switch.go | 24 +++++++++++--- p2p/switch_test.go | 34 ++++++++++++------- p2p/test_util.go | 2 +- vendor/github.com/tendermint/go-crypto/priv_key.go | 7 ++-- 7 files changed, 119 insertions(+), 21 deletions(-) diff --git a/cmd/bytomd/commands/run_node.go b/cmd/bytomd/commands/run_node.go index 587b2c5d..f38407d8 100644 --- a/cmd/bytomd/commands/run_node.go +++ b/cmd/bytomd/commands/run_node.go @@ -38,6 +38,7 @@ func init() { // 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") diff --git a/config/config.go b/config/config.go index c5500c21..2e2990f6 100644 --- a/config/config.go +++ b/config/config.go @@ -1,12 +1,15 @@ package config import ( + "io" + "io/ioutil" "os" "os/user" "path/filepath" "runtime" log "github.com/sirupsen/logrus" + "github.com/tendermint/go-crypto" ) var ( @@ -47,6 +50,34 @@ func (cfg *Config) SetRoot(root string) *Config { 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 { @@ -106,6 +137,8 @@ func (b BaseConfig) KeysDir() string { 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"` @@ -119,6 +152,7 @@ type P2PConfig struct { func DefaultP2PConfig() *P2PConfig { return &P2PConfig{ ListenAddress: "tcp://0.0.0.0:46656", + NodeKeyFile: "nodekey", SkipUPNP: false, MaxNumPeers: 50, HandshakeTimeout: 30, diff --git a/config/config_test.go b/config/config_test.go index f324d40a..280f47e7 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,6 +1,9 @@ package config import ( + "io/ioutil" + "os" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -20,3 +23,38 @@ func TestDefaultConfig(t *testing.T) { 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) + } +} diff --git a/p2p/switch.go b/p2p/switch.go index 0643cbc4..ec4b73d5 100644 --- a/p2p/switch.go +++ b/p2p/switch.go @@ -1,6 +1,7 @@ package p2p import ( + "encoding/hex" "encoding/json" "fmt" "net" @@ -64,12 +65,25 @@ type Switch struct { // 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) @@ -79,11 +93,11 @@ func NewSwitch(config *cfg.Config) (*Switch, error) { } } - 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), diff --git a/p2p/switch_test.go b/p2p/switch_test.go index ce505a54..3851521f 100644 --- a/p2p/switch_test.go +++ b/p2p/switch_test.go @@ -1,14 +1,12 @@ 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" @@ -145,7 +143,7 @@ func TestFiltersOutItself(t *testing.T) { } //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) } @@ -180,7 +178,7 @@ func TestDialBannedPeer(t *testing.T) { } } -func TestDuplicatePeer(t *testing.T) { +func TestDuplicateOutBoundPeer(t *testing.T) { dirPath, err := ioutil.TempDir(".", "") if err != nil { t.Fatal(err) @@ -201,9 +199,22 @@ func TestDuplicatePeer(t *testing.T) { 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) } @@ -218,9 +229,8 @@ func TestDuplicatePeer(t *testing.T) { 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) } } @@ -239,7 +249,7 @@ func TestAddInboundPeer(t *testing.T) { 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) } @@ -280,7 +290,7 @@ func TestStopPeer(t *testing.T) { 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) } diff --git a/p2p/test_util.go b/p2p/test_util.go index 02a300df..18128430 100644 --- a/p2p/test_util.go +++ b/p2p/test_util.go @@ -121,7 +121,7 @@ func MakeSwitch(cfg *cfg.Config, testdb dbm.DB, initSwitch func(*Switch) *Switch // 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 diff --git a/vendor/github.com/tendermint/go-crypto/priv_key.go b/vendor/github.com/tendermint/go-crypto/priv_key.go index 233563fe..accc773d 100644 --- a/vendor/github.com/tendermint/go-crypto/priv_key.go +++ b/vendor/github.com/tendermint/go-crypto/priv_key.go @@ -1,10 +1,11 @@ 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) { @@ -68,7 +69,7 @@ func (p *PrivKeyEd25519) UnmarshalJSON(enc []byte) error { } func (privKey PrivKeyEd25519) String() string { - return Fmt("PrivKeyEd25519{*****}") + return hex.EncodeToString(privKey[:]) } func GenPrivKeyEd25519() PrivKeyEd25519 { -- 2.11.0