From 26275ba66c54486fdc28bf75c908282b05343ee1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 2 Mar 2017 22:00:50 -0500 Subject: [PATCH 01/12] dial seeds error handling --- .gitignore | 16 ++++++++++++++++ addrbook_test.go | 15 +++++++++------ listener.go | 6 +++++- netaddress.go | 14 +++++++++----- pex_reactor.go | 8 +++++++- switch.go | 46 ++++++++++++++++++++++++++++++++++++++++++---- switch_test.go | 10 ++++++++++ 7 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c4694b3e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*.swp +*.swo +.bak +*.bak +.DS_Store +build/* +rpc/test/.tendermint +.debora +.tendermint +remote_dump +.revision +vendor +.vagrant +test/p2p/data/ +test/logs +.glide diff --git a/addrbook_test.go b/addrbook_test.go index d5a83da88..5eb7c0b6a 100644 --- a/addrbook_test.go +++ b/addrbook_test.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "math/rand" "testing" + + "github.com/stretchr/testify/assert" ) const addrBookStrict = true @@ -38,7 +40,7 @@ func TestEmpty(t *testing.T) { } } -func randIPv4Address() *NetAddress { +func randIPv4Address(t *testing.T) *NetAddress { for { ip := fmt.Sprintf("%v.%v.%v.%v", rand.Intn(254)+1, @@ -47,7 +49,8 @@ func randIPv4Address() *NetAddress { rand.Intn(255), ) port := rand.Intn(65535-1) + 1 - addr := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) + addr, err := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) + assert.Nil(t, err, "error generating rand network address") if addr.Routable() { return addr } @@ -64,8 +67,8 @@ func TestSaveAddresses(t *testing.T) { src *NetAddress }{} for i := 0; i < 100; i++ { - addr := randIPv4Address() - src := randIPv4Address() + addr := randIPv4Address(t) + src := randIPv4Address(t) randAddrs = append(randAddrs, struct { addr *NetAddress src *NetAddress @@ -118,8 +121,8 @@ func TestPromoteToOld(t *testing.T) { src *NetAddress }{} for i := 0; i < 100; i++ { - addr := randIPv4Address() - src := randIPv4Address() + addr := randIPv4Address(t) + src := randIPv4Address(t) randAddrs = append(randAddrs, struct { addr *NetAddress src *NetAddress diff --git a/listener.go b/listener.go index 1d7fb9569..962c2b14c 100644 --- a/listener.go +++ b/listener.go @@ -70,7 +70,11 @@ func NewDefaultListener(protocol string, lAddr string, skipUPNP bool) Listener { log.Info("Local listener", "ip", listenerIP, "port", listenerPort) // Determine internal address... - var intAddr *NetAddress = NewNetAddressString(lAddr) + var intAddr *NetAddress + intAddr, err = NewNetAddressString(lAddr) + if err != nil { + PanicCrisis(err) + } // Determine external address... var extAddr *NetAddress diff --git a/netaddress.go b/netaddress.go index 34dc5cafb..331dc44d9 100644 --- a/netaddress.go +++ b/netaddress.go @@ -34,27 +34,31 @@ func NewNetAddress(addr net.Addr) *NetAddress { } // Also resolves the host if host is not an IP. -func NewNetAddressString(addr string) *NetAddress { +func NewNetAddressString(addr string) (*NetAddress, error) { + host, portStr, err := net.SplitHostPort(addr) if err != nil { - PanicSanity(err) + return nil, err } + ip := net.ParseIP(host) if ip == nil { if len(host) > 0 { ips, err := net.LookupIP(host) if err != nil { - PanicSanity(err) + return nil, err } ip = ips[0] } } + port, err := strconv.ParseUint(portStr, 10, 16) if err != nil { - PanicSanity(err) + return nil, err } + na := NewNetAddressIPPort(ip, uint16(port)) - return na + return na, nil } func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress { diff --git a/pex_reactor.go b/pex_reactor.go index d7ccc7613..536da3a0a 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -64,7 +64,12 @@ func (pexR *PEXReactor) GetChannels() []*ChannelDescriptor { // Implements Reactor func (pexR *PEXReactor) AddPeer(peer *Peer) { // Add the peer to the address book - netAddr := NewNetAddressString(peer.ListenAddr) + netAddr, err := NewNetAddressString(peer.ListenAddr) + if err != nil { + log.Warn("Error decoding message", "error", err) + return + } + if peer.IsOutbound() { if pexR.book.NeedMoreAddrs() { pexR.RequestPEX(peer) @@ -74,6 +79,7 @@ func (pexR *PEXReactor) AddPeer(peer *Peer) { // (For outbound peers, the address is already in the books) pexR.book.AddAddress(netAddr, netAddr) } + return } // Implements Reactor diff --git a/switch.go b/switch.go index 841c44f86..9ee933640 100644 --- a/switch.go +++ b/switch.go @@ -296,20 +296,58 @@ func (sw *Switch) startInitPeer(peer *Peer) { sw.addPeerToReactors(peer) // run AddPeer on each reactor } +//error type for seed errors +type SeedError struct { + seed string + err error +} + +type SeedErrors []SeedError + +func (se SeedErrors) Error() string { + var str string + for _, e := range se { + str += ("seed: " + e.seed + " error: " + e.err.Error() + "; ") + } + return str +} + // Dial a list of seeds in random order -// Spawns a go routine for each dial -func (sw *Switch) DialSeeds(seeds []string) { +func (sw *Switch) DialSeeds(seeds []string) error { + + ch := make(chan SeedError) //channel for collecting errors + passing := 0 //number of passing seeds + // permute the list, dial them in random order. perm := rand.Perm(len(seeds)) for i := 0; i < len(perm); i++ { + go func(i int) { time.Sleep(time.Duration(rand.Int63n(3000)) * time.Millisecond) j := perm[i] - addr := NewNetAddressString(seeds[j]) - sw.dialSeed(addr) + addr, err := NewNetAddressString(seeds[j]) + + if err != nil { + ch <- SeedError{seeds[j], err} + } else { + sw.dialSeed(addr) + passing++ + } }(i) } + + //collect any errors from the channel + var seedErrs SeedErrors + for { + seedErr := <-ch + seedErrs = append(seedErrs, seedErr) + if len(seedErrs)+passing == len(perm) { + break + } + } + + return seedErrs } func (sw *Switch) dialSeed(addr *NetAddress) { diff --git a/switch_test.go b/switch_test.go index 1b2ccd743..85a1e080e 100644 --- a/switch_test.go +++ b/switch_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + . "github.com/tendermint/go-common" cfg "github.com/tendermint/go-config" "github.com/tendermint/go-crypto" @@ -119,6 +121,14 @@ func TestSwitches(t *testing.T) { t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size()) } + //Test DialSeeds + err := s1.DialSeeds([]string{s1.NodeInfo().Network}) //"0.0.0.0:46658"}) + assert.Nil(t, err, "expected successful dial seeds") + + //Test Bad Dial Seeds + err = s1.DialSeeds([]string{"0.0.0:46658"}) + assert.NotNil(t, err, "expected unsuccessful dial seeds") + // Lets send some messages ch0Msg := "channel zero" ch1Msg := "channel foo" From 0e7baf027bec8de118b0ac52f114d1a393e3d29e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 3 Mar 2017 16:08:19 -0500 Subject: [PATCH 02/12] some dial seeds fixes --- netaddress.go | 17 +++++++++++++++-- switch.go | 48 +++++++----------------------------------------- switch_test.go | 10 ---------- 3 files changed, 22 insertions(+), 53 deletions(-) diff --git a/netaddress.go b/netaddress.go index 331dc44d9..90fcf6a43 100644 --- a/netaddress.go +++ b/netaddress.go @@ -5,11 +5,12 @@ package p2p import ( + "errors" "net" "strconv" "time" - . "github.com/tendermint/go-common" + cmn "github.com/tendermint/go-common" ) type NetAddress struct { @@ -61,6 +62,18 @@ func NewNetAddressString(addr string) (*NetAddress, error) { return na, nil } +func NewNetAddressStrings(addrs []string) ([]*NetAddress, error) { + netAddrs := make([]*NetAddress, len(addrs)) + for i, addr := range addrs { + netAddr, err := NewNetAddressString(addr) + if err != nil { + return nil, errors.New(cmn.Fmt("Error in address %s: %v", addr, err)) + } + netAddrs[i] = netAddr + } + return netAddrs, nil +} + func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress { na := &NetAddress{ IP: ip, @@ -85,7 +98,7 @@ func (na *NetAddress) Less(other interface{}) bool { if o, ok := other.(*NetAddress); ok { return na.String() < o.String() } else { - PanicSanity("Cannot compare unequal types") + cmn.PanicSanity("Cannot compare unequal types") return false } } diff --git a/switch.go b/switch.go index 9ee933640..2f7177bf0 100644 --- a/switch.go +++ b/switch.go @@ -296,58 +296,24 @@ func (sw *Switch) startInitPeer(peer *Peer) { sw.addPeerToReactors(peer) // run AddPeer on each reactor } -//error type for seed errors -type SeedError struct { - seed string - err error -} - -type SeedErrors []SeedError - -func (se SeedErrors) Error() string { - var str string - for _, e := range se { - str += ("seed: " + e.seed + " error: " + e.err.Error() + "; ") - } - return str -} - -// Dial a list of seeds in random order +// Dial a list of seeds asynchronously in random order func (sw *Switch) DialSeeds(seeds []string) error { - ch := make(chan SeedError) //channel for collecting errors - passing := 0 //number of passing seeds + netAddrs, err := NewNetAddressStrings(seeds) + if err != nil { + return err + } // permute the list, dial them in random order. perm := rand.Perm(len(seeds)) for i := 0; i < len(perm); i++ { - go func(i int) { time.Sleep(time.Duration(rand.Int63n(3000)) * time.Millisecond) j := perm[i] - - addr, err := NewNetAddressString(seeds[j]) - - if err != nil { - ch <- SeedError{seeds[j], err} - } else { - sw.dialSeed(addr) - passing++ - } + sw.dialSeed(netAddrs[j]) }(i) } - - //collect any errors from the channel - var seedErrs SeedErrors - for { - seedErr := <-ch - seedErrs = append(seedErrs, seedErr) - if len(seedErrs)+passing == len(perm) { - break - } - } - - return seedErrs + return nil } func (sw *Switch) dialSeed(addr *NetAddress) { diff --git a/switch_test.go b/switch_test.go index 85a1e080e..1b2ccd743 100644 --- a/switch_test.go +++ b/switch_test.go @@ -8,8 +8,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - . "github.com/tendermint/go-common" cfg "github.com/tendermint/go-config" "github.com/tendermint/go-crypto" @@ -121,14 +119,6 @@ func TestSwitches(t *testing.T) { t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size()) } - //Test DialSeeds - err := s1.DialSeeds([]string{s1.NodeInfo().Network}) //"0.0.0.0:46658"}) - assert.Nil(t, err, "expected successful dial seeds") - - //Test Bad Dial Seeds - err = s1.DialSeeds([]string{"0.0.0:46658"}) - assert.NotNil(t, err, "expected unsuccessful dial seeds") - // Lets send some messages ch0Msg := "channel zero" ch1Msg := "channel foo" From dab31d01661fc9a0d0993cfeec10c3ef2914bcf6 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 3 Mar 2017 17:24:48 -0500 Subject: [PATCH 03/12] version bump to 0.4.0 --- .gitignore | 11 ----------- pex_reactor.go | 5 ++--- version.go | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index c4694b3e1..c765108df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,5 @@ *.swp *.swo -.bak *.bak .DS_Store -build/* -rpc/test/.tendermint -.debora -.tendermint -remote_dump -.revision vendor -.vagrant -test/p2p/data/ -test/logs -.glide diff --git a/pex_reactor.go b/pex_reactor.go index 536da3a0a..c02d9a679 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -66,7 +66,8 @@ func (pexR *PEXReactor) AddPeer(peer *Peer) { // Add the peer to the address book netAddr, err := NewNetAddressString(peer.ListenAddr) if err != nil { - log.Warn("Error decoding message", "error", err) + // this should never happen + log.Error("Error in AddPeer: invalid peer address", "addr", peer.ListenAddr, "error", err) return } @@ -79,7 +80,6 @@ func (pexR *PEXReactor) AddPeer(peer *Peer) { // (For outbound peers, the address is already in the books) pexR.book.AddAddress(netAddr, netAddr) } - return } // Implements Reactor @@ -115,7 +115,6 @@ func (pexR *PEXReactor) Receive(chID byte, src *Peer, msgBytes []byte) { default: log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg))) } - } // Asks peer for more addresses. diff --git a/version.go b/version.go index af98bef33..c13ec447b 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package p2p -const Version = "0.3.5" // minor fixes +const Version = "0.4.0" // DialSeeds returns an error From 332f7056f721fb8bfd9359f2586e6b906a752613 Mon Sep 17 00:00:00 2001 From: Anton Kalyaev Date: Fri, 13 Jan 2017 19:33:31 +0400 Subject: [PATCH 04/12] start/stop the book with reactor Refs https://github.com/tendermint/tendermint/issues/335 --- pex_reactor.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pex_reactor.go b/pex_reactor.go index c02d9a679..ed0ab76e8 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -42,12 +42,14 @@ func NewPEXReactor(book *AddrBook) *PEXReactor { func (pexR *PEXReactor) OnStart() error { pexR.BaseReactor.OnStart() + pexR.book.OnStart() go pexR.ensurePeersRoutine() return nil } func (pexR *PEXReactor) OnStop() { pexR.BaseReactor.OnStop() + pexR.book.OnStop() } // Implements Reactor From e7656873c1f290883d3272cc5182cbf2f8890abe Mon Sep 17 00:00:00 2001 From: Anton Kalyaev Date: Fri, 13 Jan 2017 20:48:42 +0400 Subject: [PATCH 05/12] public save API --- addrbook.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addrbook.go b/addrbook.go index 2bbae64f5..c5415f022 100644 --- a/addrbook.go +++ b/addrbook.go @@ -368,6 +368,12 @@ func (a *AddrBook) loadFromFile(filePath string) bool { return true } +// Save saves the book. +func (a *AddrBook) Save() { + log.Info("Saving AddrBook to file", "size", a.Size()) + a.saveToFile(a.filePath) +} + /* Private methods */ func (a *AddrBook) saveRoutine() { From 2773410de43d48c7c1a49591ccdb194db355bd7d Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 16 Jan 2017 12:39:57 +0400 Subject: [PATCH 06/12] prevent nil addr Error: ``` Error: runtime error: invalid memoryaddress or nil pointer dereference\nStack: goroutine 549 [running]:\nruntime/debug.Stack(0x0, 0x0, 0x0)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x80\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection)._recover(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:173 +0x53\npanic(0xbe1500, 0xc820012080)\n\t/usr/local/go/src/runtime/panic.go:443 +0x4e9\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Valid(0x0, 0x0)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:125 +0x1c\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Routable(0x0, 0xc8217bb740)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:117 +0x25\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).addAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:524 +0x45\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).AddAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:160 +0x286\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*PEXReactor).Receive(0xc82000be60, 0xc820149f00, 0xc8218163f0, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/pex_reactor.go:109 +0x457\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.newPeer.func1(0xc82011d500, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/peer.go:58 +0x202\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).recvRoutine(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:439 +0x1177\ncreated by github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).OnStart\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:138 +0x1a1\n ``` --- pex_reactor.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pex_reactor.go b/pex_reactor.go index ed0ab76e8..b8cb43f80 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -112,7 +112,9 @@ func (pexR *PEXReactor) Receive(chID byte, src *Peer, msgBytes []byte) { // (We don't want to get spammed with bad peers) srcAddr := src.Connection().RemoteAddress for _, addr := range msg.Addrs { - pexR.book.AddAddress(addr, srcAddr) + if addr != nil { + pexR.book.AddAddress(addr, srcAddr) + } } default: log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg))) From 108beae7a83092692ca079f1fff17b879e71fdc3 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 16 Jan 2017 15:57:08 +0400 Subject: [PATCH 07/12] more tests for AddrBook --- addrbook_test.go | 170 +++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 93 deletions(-) diff --git a/addrbook_test.go b/addrbook_test.go index 5eb7c0b6a..7e8cb8d76 100644 --- a/addrbook_test.go +++ b/addrbook_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/assert" ) -const addrBookStrict = true - func createTempFileName(prefix string) string { f, err := ioutil.TempFile("", prefix) if err != nil { @@ -24,143 +22,129 @@ func createTempFileName(prefix string) string { return fname } -func TestEmpty(t *testing.T) { +func TestAddrBookSaveLoad(t *testing.T) { fname := createTempFileName("addrbook_test") - // t.Logf("New tempfile name: %v", fname) - // Save an empty book & load it - book := NewAddrBook(fname, addrBookStrict) + // 0 addresses + book := NewAddrBook(fname, true) book.saveToFile(fname) - book = NewAddrBook(fname, addrBookStrict) + book = NewAddrBook(fname, true) book.loadFromFile(fname) - if book.Size() != 0 { - t.Errorf("Expected 0 addresses, found %v", book.Size()) - } -} + assert.Zero(t, book.Size()) -func randIPv4Address(t *testing.T) *NetAddress { - for { - ip := fmt.Sprintf("%v.%v.%v.%v", - rand.Intn(254)+1, - rand.Intn(255), - rand.Intn(255), - rand.Intn(255), - ) - port := rand.Intn(65535-1) + 1 - addr, err := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) - assert.Nil(t, err, "error generating rand network address") - if addr.Routable() { - return addr - } - } -} + // 100 addresses + randAddrs := randNetAddressPairs(t, 100) -func TestSaveAddresses(t *testing.T) { - fname := createTempFileName("addrbook_test") - //t.Logf("New tempfile name: %v", fname) - - // Create some random addresses - randAddrs := []struct { - addr *NetAddress - src *NetAddress - }{} - for i := 0; i < 100; i++ { - addr := randIPv4Address(t) - src := randIPv4Address(t) - randAddrs = append(randAddrs, struct { - addr *NetAddress - src *NetAddress - }{ - addr: addr, - src: src, - }) - } - - // Create the book & populate & save - book := NewAddrBook(fname, addrBookStrict) for _, addrSrc := range randAddrs { book.AddAddress(addrSrc.addr, addrSrc.src) } - if book.Size() != 100 { - t.Errorf("Expected 100 addresses, found %v", book.Size()) - } + + assert.Equal(t, 100, book.Size()) book.saveToFile(fname) - // Reload the book - book = NewAddrBook(fname, addrBookStrict) + book = NewAddrBook(fname, true) book.loadFromFile(fname) - // Test ... + assert.Equal(t, 100, book.Size()) +} - if book.Size() != 100 { - t.Errorf("Expected 100 addresses, found %v", book.Size()) - } +func TestAddrBookLookup(t *testing.T) { + fname := createTempFileName("addrbook_test") + + randAddrs := randNetAddressPairs(t, 100) + book := NewAddrBook(fname, true) for _, addrSrc := range randAddrs { addr := addrSrc.addr src := addrSrc.src + book.AddAddress(addr, src) + ka := book.addrLookup[addr.String()] - if ka == nil { - t.Fatalf("Expected to find KnownAddress %v but wasn't there.", addr) - } + assert.NotNil(t, ka, "Expected to find KnownAddress %v but wasn't there.", addr) + if !(ka.Addr.Equals(addr) && ka.Src.Equals(src)) { t.Fatalf("KnownAddress doesn't match addr & src") } } } -func TestPromoteToOld(t *testing.T) { +func TestAddrBookPromoteToOld(t *testing.T) { fname := createTempFileName("addrbook_test") - t.Logf("New tempfile name: %v", fname) - - // Create some random addresses - randAddrs := []struct { - addr *NetAddress - src *NetAddress - }{} - for i := 0; i < 100; i++ { - addr := randIPv4Address(t) - src := randIPv4Address(t) - randAddrs = append(randAddrs, struct { - addr *NetAddress - src *NetAddress - }{ - addr: addr, - src: src, - }) - } - // Create the book & populate & save - book := NewAddrBook(fname, addrBookStrict) + randAddrs := randNetAddressPairs(t, 100) + + book := NewAddrBook(fname, true) for _, addrSrc := range randAddrs { book.AddAddress(addrSrc.addr, addrSrc.src) } + // Attempt all addresses. for _, addrSrc := range randAddrs { book.MarkAttempt(addrSrc.addr) } + // Promote half of them for i, addrSrc := range randAddrs { if i%2 == 0 { book.MarkGood(addrSrc.addr) } } - book.saveToFile(fname) - // Reload the book - book = NewAddrBook(fname, addrBookStrict) - book.loadFromFile(fname) + // TODO: do more testing :) - // Test ... + selection := book.GetSelection() + t.Logf("selection: %v", selection) - if book.Size() != 100 { - t.Errorf("Expected 100 addresses, found %v", book.Size()) + if len(selection) > book.Size() { + t.Errorf("selection could not be bigger than the book") } +} - // TODO: do more testing :) +func TestAddrBookHandlesDuplicates(t *testing.T) { + fname := createTempFileName("addrbook_test") - selection := book.GetSelection() - t.Logf("selection: %v", selection) + book := NewAddrBook(fname, true) + + randAddrs := randNetAddressPairs(t, 100) + + differentSrc := randIPv4Address(t) + for _, addrSrc := range randAddrs { + book.AddAddress(addrSrc.addr, addrSrc.src) + book.AddAddress(addrSrc.addr, addrSrc.src) // duplicate + book.AddAddress(addrSrc.addr, differentSrc) // different src + } + + assert.Equal(t, 100, book.Size()) +} + +type netAddressPair struct { + addr *NetAddress + src *NetAddress +} + +func randNetAddressPairs(t *testing.T, n int) []netAddressPair { + randAddrs := make([]netAddressPair, n) + for i := 0; i < n; i++ { + randAddrs[i] = netAddressPair{addr: randIPv4Address(t), src: randIPv4Address(t)} + } + return randAddrs +} + +func randIPv4Address(t *testing.T) *NetAddress { + for { + ip := fmt.Sprintf("%v.%v.%v.%v", + rand.Intn(254)+1, + rand.Intn(255), + rand.Intn(255), + rand.Intn(255), + ) + port := rand.Intn(65535-1) + 1 + addr, err := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) + assert.Nil(t, err, "error generating rand network address") + if addr.Routable() { + return addr + } + } } From 65b1756978fb6fe1c247dd361e3ef56dbd4a5165 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 16 Jan 2017 18:00:39 +0400 Subject: [PATCH 08/12] expose 2 API functions for tendermint#node/node.go --- pex_reactor.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pex_reactor.go b/pex_reactor.go index b8cb43f80..2948c58f9 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -130,6 +130,16 @@ func (pexR *PEXReactor) SendAddrs(peer *Peer, addrs []*NetAddress) { peer.Send(PexChannel, struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}}) } +// SaveAddrBook saves underlying address book +func (r *PEXReactor) SaveAddrBook() { + r.book.Save() +} + +// AddPeerAddress adds raw NetAddress to the address book +func (r *PEXReactor) AddPeerAddress(peerAddr, srcAddr *NetAddress) { + r.book.AddAddress(peerAddr, srcAddr) +} + // Ensures that sufficient peers are connected. (continuous) func (pexR *PEXReactor) ensurePeersRoutine() { // Randomize when routine starts From 88b5c724f26f99d4094e2b8dcef72fb9bf89c5c4 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 4 Mar 2017 22:55:42 -0500 Subject: [PATCH 09/12] remove public addr book funcs from pex --- addrbook.go | 1 + pex_reactor.go | 10 ---------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/addrbook.go b/addrbook.go index c5415f022..ea438120b 100644 --- a/addrbook.go +++ b/addrbook.go @@ -153,6 +153,7 @@ func (a *AddrBook) OurAddresses() []*NetAddress { return addrs } +// NOTE: addr must not be nil func (a *AddrBook) AddAddress(addr *NetAddress, src *NetAddress) { a.mtx.Lock() defer a.mtx.Unlock() diff --git a/pex_reactor.go b/pex_reactor.go index 2948c58f9..b8cb43f80 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -130,16 +130,6 @@ func (pexR *PEXReactor) SendAddrs(peer *Peer, addrs []*NetAddress) { peer.Send(PexChannel, struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}}) } -// SaveAddrBook saves underlying address book -func (r *PEXReactor) SaveAddrBook() { - r.book.Save() -} - -// AddPeerAddress adds raw NetAddress to the address book -func (r *PEXReactor) AddPeerAddress(peerAddr, srcAddr *NetAddress) { - r.book.AddAddress(peerAddr, srcAddr) -} - // Ensures that sufficient peers are connected. (continuous) func (pexR *PEXReactor) ensurePeersRoutine() { // Randomize when routine starts From c94bc2bc2b3f0fe01f6666bd059b44f1703b7844 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 5 Mar 2017 21:57:07 -0500 Subject: [PATCH 10/12] DialSeeds takes an addrbook --- switch.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/switch.go b/switch.go index 2f7177bf0..eed8ceea5 100644 --- a/switch.go +++ b/switch.go @@ -297,15 +297,29 @@ func (sw *Switch) startInitPeer(peer *Peer) { } // Dial a list of seeds asynchronously in random order -func (sw *Switch) DialSeeds(seeds []string) error { +func (sw *Switch) DialSeeds(addrBook *AddrBook, seeds []string) error { netAddrs, err := NewNetAddressStrings(seeds) if err != nil { return err } + if addrBook != nil { + // add seeds to `addrBook` + ourAddrS := sw.nodeInfo.ListenAddr + ourAddr, _ := NewNetAddressString(ourAddrS) + for _, netAddr := range netAddrs { + // do not add ourselves + if netAddr.Equals(ourAddr) { + continue + } + addrBook.AddAddress(netAddr, ourAddr) + } + addrBook.Save() + } + // permute the list, dial them in random order. - perm := rand.Perm(len(seeds)) + perm := rand.Perm(len(netAddrs)) for i := 0; i < len(perm); i++ { go func(i int) { time.Sleep(time.Duration(rand.Int63n(3000)) * time.Millisecond) From beb3eda438fbbfc3b566ead4be5705474a12e50a Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 5 Mar 2017 22:59:18 -0500 Subject: [PATCH 11/12] fix addrbook start/stop --- addrbook.go | 3 +++ pex_reactor.go | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/addrbook.go b/addrbook.go index ea438120b..ace0dba4a 100644 --- a/addrbook.go +++ b/addrbook.go @@ -135,6 +135,9 @@ func (a *AddrBook) OnStart() error { func (a *AddrBook) OnStop() { a.BaseService.OnStop() +} + +func (a *AddrBook) Wait() { a.wg.Wait() } diff --git a/pex_reactor.go b/pex_reactor.go index b8cb43f80..45c4c96d8 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -42,14 +42,14 @@ func NewPEXReactor(book *AddrBook) *PEXReactor { func (pexR *PEXReactor) OnStart() error { pexR.BaseReactor.OnStart() - pexR.book.OnStart() + pexR.book.Start() go pexR.ensurePeersRoutine() return nil } func (pexR *PEXReactor) OnStop() { pexR.BaseReactor.OnStop() - pexR.book.OnStop() + pexR.book.Stop() } // Implements Reactor From 53d777a2d54aa904a70119010e6c71a9bf367153 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 6 Mar 2017 01:30:41 -0500 Subject: [PATCH 12/12] CHANGELOG.md --- CHANGELOG.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..81e30fcca --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,57 @@ +# Changelog + +## 0.4.0 (March 6, 2017) + +BREAKING CHANGES: + +- DialSeeds now takes an AddrBook and returns an error: `DialSeeds(*AddrBook, []string) error` +- NewNetAddressString now returns an error: `NewNetAddressString(string) (*NetAddress, error)` + +FEATURES: + +- `NewNetAddressStrings([]string) ([]*NetAddress, error)` +- `AddrBook.Save()` + +IMPROVEMENTS: + +- PexReactor responsible for starting and stopping the AddrBook + +BUG FIXES: + +- DialSeeds returns an error instead of panicking on bad addresses + +## 0.3.5 (January 12, 2017) + +FEATURES + +- Toggle strict routability in the AddrBook + +BUG FIXES + +- Close filtered out connections +- Fixes for MakeConnectedSwitches and Connect2Switches + +## 0.3.4 (August 10, 2016) + +FEATURES: + +- Optionally filter connections by address or public key + +## 0.3.3 (May 12, 2016) + +FEATURES: + +- FuzzConn + +## 0.3.2 (March 12, 2016) + +IMPROVEMENTS: + +- Memory optimizations + +## 0.3.1 () + +FEATURES: + +- Configurable parameters +