mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-28 13:41:21 +00:00
commit
97a5ed2d1a
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
.DS_Store
|
||||
vendor
|
57
CHANGELOG.md
Normal file
57
CHANGELOG.md
Normal file
@ -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
|
||||
|
10
addrbook.go
10
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()
|
||||
}
|
||||
|
||||
@ -153,6 +156,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()
|
||||
@ -368,6 +372,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() {
|
||||
|
225
addrbook_test.go
225
addrbook_test.go
@ -5,9 +5,9 @@ import (
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const addrBookStrict = true
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func createTempFileName(prefix string) string {
|
||||
f, err := ioutil.TempFile("", prefix)
|
||||
@ -22,23 +22,117 @@ 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())
|
||||
|
||||
// 100 addresses
|
||||
randAddrs := randNetAddressPairs(t, 100)
|
||||
|
||||
for _, addrSrc := range randAddrs {
|
||||
book.AddAddress(addrSrc.addr, addrSrc.src)
|
||||
}
|
||||
|
||||
assert.Equal(t, 100, book.Size())
|
||||
book.saveToFile(fname)
|
||||
|
||||
book = NewAddrBook(fname, true)
|
||||
book.loadFromFile(fname)
|
||||
|
||||
assert.Equal(t, 100, 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()]
|
||||
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 randIPv4Address() *NetAddress {
|
||||
func TestAddrBookPromoteToOld(t *testing.T) {
|
||||
fname := createTempFileName("addrbook_test")
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do more testing :)
|
||||
|
||||
selection := book.GetSelection()
|
||||
t.Logf("selection: %v", selection)
|
||||
|
||||
if len(selection) > book.Size() {
|
||||
t.Errorf("selection could not be bigger than the book")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddrBookHandlesDuplicates(t *testing.T) {
|
||||
fname := createTempFileName("addrbook_test")
|
||||
|
||||
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,
|
||||
@ -47,117 +141,10 @@ 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
src := randIPv4Address()
|
||||
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())
|
||||
}
|
||||
book.saveToFile(fname)
|
||||
|
||||
// Reload the book
|
||||
book = NewAddrBook(fname, addrBookStrict)
|
||||
book.loadFromFile(fname)
|
||||
|
||||
// Test ...
|
||||
|
||||
if book.Size() != 100 {
|
||||
t.Errorf("Expected 100 addresses, found %v", book.Size())
|
||||
}
|
||||
|
||||
for _, addrSrc := range randAddrs {
|
||||
addr := addrSrc.addr
|
||||
src := addrSrc.src
|
||||
ka := book.addrLookup[addr.String()]
|
||||
if ka == nil {
|
||||
t.Fatalf("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) {
|
||||
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()
|
||||
src := randIPv4Address()
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
|
||||
// Test ...
|
||||
|
||||
if book.Size() != 100 {
|
||||
t.Errorf("Expected 100 addresses, found %v", book.Size())
|
||||
}
|
||||
|
||||
// TODO: do more testing :)
|
||||
|
||||
selection := book.GetSelection()
|
||||
t.Logf("selection: %v", selection)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
@ -34,27 +35,43 @@ 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 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 {
|
||||
@ -81,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
|
||||
}
|
||||
}
|
||||
|
@ -42,12 +42,14 @@ func NewPEXReactor(book *AddrBook) *PEXReactor {
|
||||
|
||||
func (pexR *PEXReactor) OnStart() error {
|
||||
pexR.BaseReactor.OnStart()
|
||||
pexR.book.Start()
|
||||
go pexR.ensurePeersRoutine()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pexR *PEXReactor) OnStop() {
|
||||
pexR.BaseReactor.OnStop()
|
||||
pexR.book.Stop()
|
||||
}
|
||||
|
||||
// Implements Reactor
|
||||
@ -64,7 +66,13 @@ 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 {
|
||||
// this should never happen
|
||||
log.Error("Error in AddPeer: invalid peer address", "addr", peer.ListenAddr, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if peer.IsOutbound() {
|
||||
if pexR.book.NeedMoreAddrs() {
|
||||
pexR.RequestPEX(peer)
|
||||
@ -104,12 +112,13 @@ 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)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Asks peer for more addresses.
|
||||
|
32
switch.go
32
switch.go
@ -296,20 +296,38 @@ func (sw *Switch) startInitPeer(peer *Peer) {
|
||||
sw.addPeerToReactors(peer) // run AddPeer on each reactor
|
||||
}
|
||||
|
||||
// Dial a list of seeds in random order
|
||||
// Spawns a go routine for each dial
|
||||
func (sw *Switch) DialSeeds(seeds []string) {
|
||||
// Dial a list of seeds asynchronously in random order
|
||||
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)
|
||||
j := perm[i]
|
||||
addr := NewNetAddressString(seeds[j])
|
||||
|
||||
sw.dialSeed(addr)
|
||||
sw.dialSeed(netAddrs[j])
|
||||
}(i)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sw *Switch) dialSeed(addr *NetAddress) {
|
||||
|
@ -1,3 +1,3 @@
|
||||
package p2p
|
||||
|
||||
const Version = "0.3.5" // minor fixes
|
||||
const Version = "0.4.0" // DialSeeds returns an error
|
||||
|
Loading…
x
Reference in New Issue
Block a user