From 3864943adb3c2e4b218a36de3f3c45048731b79a Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 23 Aug 2023 10:51:49 -0400 Subject: [PATCH 01/16] implenting phonbook interface --- network/p2p/peerstore/peerstore.go | 289 ++++++++++++++++++++++++++++- network/phonebook.go | 6 +- 2 files changed, 291 insertions(+), 4 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index ee6bf90a65..00f437c068 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -17,16 +17,43 @@ package peerstore import ( + "errors" "fmt" + "math/rand" + "time" "github.com/libp2p/go-libp2p/core/peer" libp2p "github.com/libp2p/go-libp2p/core/peerstore" mempstore "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" + "github.com/multiformats/go-multiaddr" + "golang.org/x/exp/slices" + + "github.com/algorand/go-algorand/network" ) // PeerStore implements Peerstore and CertifiedAddrBook. type PeerStore struct { peerStoreCAB + network.Phonebook +} + +// addressData: holds the information associated with each phonebook address. +type addressData struct { + // retryAfter is the time to wait before retrying to connect to the address. + retryAfter time.Time + + // recentConnectionTimes: is the log of connection times used to observe the maximum + // connections to the address in a given time window. + recentConnectionTimes []time.Time + + // networkNames: lists the networks to which the given address belongs. + networkNames map[string]bool + + // role is the role that this address serves. + role network.PhoneBookEntryRoles + + // persistent is set true for peers whose record should not be removed for the peer list + persistent bool } // peerStoreCAB combines the libp2p Peerstore and CertifiedAddrBook interfaces. @@ -47,6 +74,266 @@ func NewPeerStore(addrInfo []*peer.AddrInfo) (*PeerStore, error) { info := addrInfo[i] ps.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) } - pstore := &PeerStore{ps} + pstore := &PeerStore{peerStoreCAB: ps} return pstore, nil } + +// GetAddresses returns up to N addresses, but may return fewer +func (ps *PeerStore) GetAddresses(n int, role network.PhoneBookEntryRoles) []string { + return shuffleSelect(ps.filterRetryTime(time.Now(), role), n) +} + +// UpdateRetryAfter updates the retryAfter time for the given address. +func (ps *PeerStore) UpdateRetryAfter(addr string, retryAfter time.Time) { + info, err := peer.AddrInfoFromString(addr) + if err != nil { + return + } + metadata, err := ps.Get(info.ID, "addressData") + if err != nil && errors.Is(err, libp2p.ErrNotFound) { + return + } else if err != nil { + panic(err) + } + ad := metadata.(addressData) + ad.retryAfter = retryAfter + _ = ps.Put(info.ID, "addressData", ad) + +} + +// GetConnectionWaitTime returns the connection wait time for the given address. +func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, time.Time) { + curTime := time.Now() + info, err := peer.AddrInfoFromString(addr) + if err != nil { + return false, 0 /* not used */, curTime /* not used */ + } + if info == nil { + // The addr is not in this phonebook. + // Will find the addr in a different phonebook. + return false, 0 /* not used */, curTime /* not used */ + } + var timeSince time.Duration + var numElmtsToRemove int + metadata, err := ps.Get(info.ID, "addressData") + if err != nil { + return false, 0 /* not used */, curTime /* not used */ + } + ad := metadata.(addressData) + // Remove from recentConnectionTimes the times later than ConnectionsRateLimitingWindowSeconds + connectionsRateLimitingWindow, err := ps.Get("peerID", "connectionsRateLimitingWindow") + if err != nil { + return false, 0 /* not used */, curTime /* not used */ + } + for numElmtsToRemove < len(ad.recentConnectionTimes) { + timeSince = curTime.Sub(ad.recentConnectionTimes[numElmtsToRemove]) + if timeSince >= connectionsRateLimitingWindow.(time.Duration) { + numElmtsToRemove++ + } else { + break // break the loop. The rest are earlier than 1 second + } + } + + // Remove the expired elements from e.data[addr].recentConnectionTimes + ps.popNElements(numElmtsToRemove, peer.ID(addr)) + // If there are max number of connections within the time window, wait + connectionsRateLimitingCount, err := ps.Get("peerID", "connectionsRateLimitingCount") + if err != nil { + return false, 0 /* not used */, curTime /* not used */ + } + numElts := len(ad.recentConnectionTimes) + if uint(numElts) >= connectionsRateLimitingCount.(uint) { + return true, /* true */ + connectionsRateLimitingWindow.(time.Duration) - timeSince, curTime /* not used */ + } + + // Else, there is space in connectionsRateLimitingCount. The + // connection request of the caller will proceed + // Update curTime, since it may have significantly changed if waited + provisionalTime := time.Now() + // Append the provisional time for the next connection request + ps.appendTime(info.ID, provisionalTime) + return true, 0 /* no wait. proceed */, provisionalTime +} + +// UpdateConnectionTime updates the connection time for the given address. +func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time) bool { + info, err := peer.AddrInfoFromString(addr) + if err != nil { + return false + } + metadata, err := ps.Get(info.ID, "addressData") + if err != nil { + return false + } + ad := metadata.(addressData) + entry := ad.recentConnectionTimes + defer func() { + _ = ps.Put(info.ID, "addressData", entry) + + }() + + // Find the provisionalTime and update it + for indx, val := range entry { + if provisionalTime == val { + entry[indx] = time.Now() + return true + } + } + + // Case where the time is not found: it was removed from the list. + // This may happen when the time expires before the connection was established with the server. + // The time should be added again. + entry = append(entry, time.Now()) + + return true +} + +// ReplacePeerList replaces the peer list for the given networkName and role. +func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, role network.PhoneBookEntryRoles) { + // prepare a map of items we'd like to remove. + removeItems := make(map[peer.ID]bool, 0) + peerIDs := ps.Peers() + for _, pid := range peerIDs { + val, _ := ps.Get(pid, "addressData") + ad := val.(*addressData) + if ad.networkNames[networkName] && ad.role == role && !ad.persistent { + removeItems[pid] = true + } + } + for _, addr := range addressesThey { + info, err := peer.AddrInfoFromString(addr) + if err != nil { + return + } + data, _ := ps.Get(info.ID, "addressData") + if data == nil { + // we already have this. + // Update the networkName + ad := data.(*addressData) + ad.networkNames[networkName] = true + + // do not remove this entry + delete(removeItems, info.ID) + } else { + // we don't have this item. add it. + entry := makePhonebookEntryData(networkName, role, false) + _ = ps.Put("peerID", "addressData", entry) + } + } + + // remove items that were missing in addressesThey + for k := range removeItems { + ps.deletePhonebookEntry(k, networkName) + } +} + +// AddPersistentPeers stores addresses of peers which are persistent. +// i.e. they won't be replaced by ReplacePeerList calls +func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName string, role network.PhoneBookEntryRoles) { + + for _, addr := range dnsAddresses { + val, err := ps.Get("peerID", "addressData") + if err == nil { + // we already have this. + // Make sure the persistence field is set to true + data := val.(*addressData) + data.persistent = true + _ = ps.Put("peerID", "addressData", data) + + } else { + // we don't have this item. add it. + ps.AddAddr("peerID", multiaddr.Cast([]byte(addr)), libp2p.PermanentAddrTTL) + data := makePhonebookEntryData(networkName, role, true) + _ = ps.Put("peerID", "addressData", data) + } + } +} + +// Length returns the number of addrs in peerstore +func (ps *PeerStore) Length() int { + return len(ps.PeersWithKeys()) +} + +// makePhonebookEntryData creates a new address entry for provided network name and role. +func makePhonebookEntryData(networkName string, role network.PhoneBookEntryRoles, persistent bool) addressData { + pbData := addressData{ + networkNames: make(map[string]bool), + recentConnectionTimes: make([]time.Time, 0), + role: role, + persistent: persistent, + } + pbData.networkNames[networkName] = true + return pbData +} + +func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { + data, err := ps.Get(peerID, "addressData") + if err != nil { + return + } + ad := data.(*addressData) + delete(ad.networkNames, networkName) + if 0 == len(ad.networkNames) { + _ = ps.Put(peerID, "addressData", nil) + } +} + +// AppendTime adds the current time to recentConnectionTimes in +// addressData of addr +func (ps *PeerStore) appendTime(peerID peer.ID, t time.Time) { + data, _ := ps.Get(peerID, "addressData") + ad := data.(*addressData) + ad.recentConnectionTimes = append(ad.recentConnectionTimes, t) + _ = ps.Put(peerID, "addressData", ad) +} + +// PopEarliestTime removes the earliest time from recentConnectionTimes in +// addressData for addr +// It is expected to be later than ConnectionsRateLimitingWindow +func (ps *PeerStore) popNElements(n int, peerID peer.ID) { + data, _ := ps.Get(peerID, "addressData") + ad := data.(*addressData) + ad.recentConnectionTimes = ad.recentConnectionTimes[n:] + _ = ps.Put(peerID, "addressData", ad) +} + +func (ps *PeerStore) filterRetryTime(t time.Time, role network.PhoneBookEntryRoles) []string { + o := make([]string, 0, len(ps.Peers())) + for _, peerID := range ps.Peers() { + data, _ := ps.Get(peerID, "addressData") + ad := data.(*addressData) + if t.After(ad.retryAfter) && role == ad.role { + o = append(o, string(peerID)) + } + } + return o +} + +func shuffleSelect(set []string, n int) []string { + if n >= len(set) || n == network.GetAllAddresses { + // return shuffled copy of everything + out := slices.Clone(set) + shuffleStrings(out) + return out + } + // Pick random indexes from the set + indexSample := make([]int, n) + for i := range indexSample { + indexSample[i] = rand.Intn(len(set)-i) + i + for oi, ois := range indexSample[:i] { + if ois == indexSample[i] { + indexSample[i] = oi + } + } + } + out := make([]string, n) + for i, index := range indexSample { + out[i] = set[index] + } + return out +} + +func shuffleStrings(set []string) { + rand.Shuffle(len(set), func(i, j int) { t := set[i]; set[i] = set[j]; set[j] = t }) +} diff --git a/network/phonebook.go b/network/phonebook.go index 0ad7be1a0c..ce0de9d3c2 100644 --- a/network/phonebook.go +++ b/network/phonebook.go @@ -25,9 +25,9 @@ import ( "golang.org/x/exp/slices" ) -// when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless +// GetAllAddresses when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless // of how many addresses the phonebook actually has. ( with the retry-after logic applied ) -const getAllAddresses = math.MaxInt32 +const GetAllAddresses = math.MaxInt32 // PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. // currently, we have two roles : relay role and archiver role, which are mutually exclusive. @@ -308,7 +308,7 @@ func shuffleStrings(set []string) { } func shuffleSelect(set []string, n int) []string { - if n >= len(set) || n == getAllAddresses { + if n >= len(set) || n == GetAllAddresses { // return shuffled copy of everything out := slices.Clone(set) shuffleStrings(out) From 8bf9cf50290bec6c7c1971d12fc3393f28a2c8ee Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 23 Aug 2023 14:51:59 -0400 Subject: [PATCH 02/16] adding tests --- network/p2p/peerstore/peerstore.go | 34 +++--- network/p2p/peerstore/peerstore_test.go | 141 ++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 15 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 00f437c068..eee648c025 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -34,7 +34,6 @@ import ( // PeerStore implements Peerstore and CertifiedAddrBook. type PeerStore struct { peerStoreCAB - network.Phonebook } // addressData: holds the information associated with each phonebook address. @@ -195,11 +194,14 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, removeItems := make(map[peer.ID]bool, 0) peerIDs := ps.Peers() for _, pid := range peerIDs { - val, _ := ps.Get(pid, "addressData") - ad := val.(*addressData) - if ad.networkNames[networkName] && ad.role == role && !ad.persistent { - removeItems[pid] = true + data, _ := ps.Get(pid, "addressData") + if data != nil { + ad := data.(addressData) + if ad.networkNames[networkName] && ad.role == role && !ad.persistent { + removeItems[pid] = true + } } + } for _, addr := range addressesThey { info, err := peer.AddrInfoFromString(addr) @@ -207,10 +209,10 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, return } data, _ := ps.Get(info.ID, "addressData") - if data == nil { + if data != nil { // we already have this. // Update the networkName - ad := data.(*addressData) + ad := data.(addressData) ad.networkNames[networkName] = true // do not remove this entry @@ -218,7 +220,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, } else { // we don't have this item. add it. entry := makePhonebookEntryData(networkName, role, false) - _ = ps.Put("peerID", "addressData", entry) + _ = ps.Put(info.ID, "addressData", entry) } } @@ -237,7 +239,7 @@ func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName strin if err == nil { // we already have this. // Make sure the persistence field is set to true - data := val.(*addressData) + data := val.(addressData) data.persistent = true _ = ps.Put("peerID", "addressData", data) @@ -272,7 +274,7 @@ func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { if err != nil { return } - ad := data.(*addressData) + ad := data.(addressData) delete(ad.networkNames, networkName) if 0 == len(ad.networkNames) { _ = ps.Put(peerID, "addressData", nil) @@ -283,7 +285,7 @@ func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { // addressData of addr func (ps *PeerStore) appendTime(peerID peer.ID, t time.Time) { data, _ := ps.Get(peerID, "addressData") - ad := data.(*addressData) + ad := data.(addressData) ad.recentConnectionTimes = append(ad.recentConnectionTimes, t) _ = ps.Put(peerID, "addressData", ad) } @@ -293,7 +295,7 @@ func (ps *PeerStore) appendTime(peerID peer.ID, t time.Time) { // It is expected to be later than ConnectionsRateLimitingWindow func (ps *PeerStore) popNElements(n int, peerID peer.ID) { data, _ := ps.Get(peerID, "addressData") - ad := data.(*addressData) + ad := data.(addressData) ad.recentConnectionTimes = ad.recentConnectionTimes[n:] _ = ps.Put(peerID, "addressData", ad) } @@ -302,9 +304,11 @@ func (ps *PeerStore) filterRetryTime(t time.Time, role network.PhoneBookEntryRol o := make([]string, 0, len(ps.Peers())) for _, peerID := range ps.Peers() { data, _ := ps.Get(peerID, "addressData") - ad := data.(*addressData) - if t.After(ad.retryAfter) && role == ad.role { - o = append(o, string(peerID)) + if data != nil { + ad := data.(addressData) + if t.After(ad.retryAfter) && role == ad.role { + o = append(o, peerID.String()) + } } } return o diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index 2debcae255..a577da79c4 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -21,6 +21,7 @@ import ( "fmt" "testing" + "github.com/algorand/go-algorand/network" "github.com/algorand/go-algorand/test/partitiontest" libp2p_crypto "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" @@ -77,3 +78,143 @@ func TestPeerstore(t *testing.T) { require.Equal(t, 7, len(peers)) } + +func testPhonebookAll(t *testing.T, set []string, ph network.Phonebook) { + actual := ph.GetAddresses(len(set), network.PhoneBookEntryRelayRole) + for _, got := range actual { + ok := false + for _, known := range set { + if got == known { + ok = true + break + } + } + if !ok { + t.Errorf("get returned junk %#v", got) + } + } + for _, known := range set { + ok := false + for _, got := range actual { + if got == known { + ok = true + break + } + } + if !ok { + t.Errorf("get missed %#v; actual=%#v; set=%#v", known, actual, set) + } + } +} + +func testPhonebookUniform(t *testing.T, set []string, ph network.Phonebook, getsize int) { + uniformityTestLength := 250000 / len(set) + expected := (uniformityTestLength * getsize) / len(set) + counts := make([]int, len(set)) + for i := 0; i < uniformityTestLength; i++ { + actual := ph.GetAddresses(getsize, network.PhoneBookEntryRelayRole) + for i, known := range set { + for _, xa := range actual { + if known == xa { + counts[i]++ + } + } + } + } + min := counts[0] + max := counts[0] + for i := 1; i < len(counts); i++ { + if counts[i] > max { + max = counts[i] + } + if counts[i] < min { + min = counts[i] + } + } + // TODO: what's a good probability-theoretic threshold for good enough? + if max-min > (expected / 5) { + t.Errorf("counts %#v", counts) + } +} + +func generateMultiAddrs(n int) ([]string, []string) { + var multiaddrs []string + var ids []string + + for i := 0; i < n; i++ { + privKey, _, _ := libp2p_crypto.GenerateEd25519Key(rand.Reader) + peerID, _ := peer.IDFromPrivateKey(privKey) + ids = append(ids, peerID.String()) + multiaddrs = append(multiaddrs, fmt.Sprintf("/ip4/198.51.100.0/tcp/4242/p2p/%s", peerID.String())) + + } + return multiaddrs, ids +} +func TestArrayPhonebookAll(t *testing.T) { + partitiontest.PartitionTest(t) + + multiaddrs, ids := generateMultiAddrs(10) + addrs, _ := PeerInfoFromAddrs(multiaddrs) + ps, err := NewPeerStore(addrs) + require.NoError(t, err) + for _, id := range ids { + entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + peerid, err := peer.Decode(id) + require.NoError(t, err) + ps.Put(peerid, "addressData", entry) + } + testPhonebookAll(t, ids, ps) +} + +func TestArrayPhonebookUniform1(t *testing.T) { + partitiontest.PartitionTest(t) + + multiaddrs, ids := generateMultiAddrs(10) + addrs, _ := PeerInfoFromAddrs(multiaddrs) + ps, _ := NewPeerStore(addrs) + for _, id := range ids { + entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + peerid, err := peer.Decode(id) + require.NoError(t, err) + ps.Put(peerid, "addressData", entry) + } + testPhonebookUniform(t, ids, ps, 1) +} + +func TestArrayPhonebookUniform3(t *testing.T) { + partitiontest.PartitionTest(t) + + multiaddrs, ids := generateMultiAddrs(10) + addrs, _ := PeerInfoFromAddrs(multiaddrs) + ps, _ := NewPeerStore(addrs) + for _, id := range ids { + entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + peerid, err := peer.Decode(id) + require.NoError(t, err) + ps.Put(peerid, "addressData", entry) + } + testPhonebookUniform(t, ids, ps, 3) +} + +func TestMultiPhonebook(t *testing.T) { + partitiontest.PartitionTest(t) + + multiaddrs, ids := generateMultiAddrs(10) + addrs, _ := PeerInfoFromAddrs(multiaddrs) + pha := make([]string, 0) + for _, e := range multiaddrs[:5] { + pha = append(pha, e) + } + phb := make([]string, 0) + for _, e := range multiaddrs[5:] { + phb = append(phb, e) + } + + ps, _ := NewPeerStore(addrs) + ps.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) + ps.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + + testPhonebookAll(t, ids, ps) + testPhonebookUniform(t, ids, ps, 1) + testPhonebookUniform(t, ids, ps, 3) +} From 4dc982e4c3e03573cbf339a5ea35b38b97c7f002 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Thu, 24 Aug 2023 16:17:24 -0400 Subject: [PATCH 03/16] support domain:port addr format --- network/p2p/peerstore/peerstore.go | 78 +++++++++------- network/p2p/peerstore/peerstore_test.go | 118 +++++++++++++++++------- network/p2p/peerstore/utils.go | 18 ++++ 3 files changed, 147 insertions(+), 67 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index eee648c025..d300a3090c 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -17,7 +17,6 @@ package peerstore import ( - "errors" "fmt" "math/rand" "time" @@ -25,7 +24,6 @@ import ( "github.com/libp2p/go-libp2p/core/peer" libp2p "github.com/libp2p/go-libp2p/core/peerstore" mempstore "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" - "github.com/multiformats/go-multiaddr" "golang.org/x/exp/slices" "github.com/algorand/go-algorand/network" @@ -34,6 +32,8 @@ import ( // PeerStore implements Peerstore and CertifiedAddrBook. type PeerStore struct { peerStoreCAB + connectionsRateLimitingCount uint + connectionsRateLimitingWindow time.Duration } // addressData: holds the information associated with each phonebook address. @@ -77,6 +77,20 @@ func NewPeerStore(addrInfo []*peer.AddrInfo) (*PeerStore, error) { return pstore, nil } +// MakePhonebook creates a phonebook with the passed configuration values +func MakePhonebook(connectionsRateLimitingCount uint, + connectionsRateLimitingWindow time.Duration) (*PeerStore, error) { + ps, err := mempstore.NewPeerstore() + if err != nil { + return &PeerStore{}, fmt.Errorf("cannot initialize a peerstore: %w", err) + } + pstore := &PeerStore{peerStoreCAB: ps, + connectionsRateLimitingCount: connectionsRateLimitingCount, + connectionsRateLimitingWindow: connectionsRateLimitingWindow, + } + return pstore, nil +} + // GetAddresses returns up to N addresses, but may return fewer func (ps *PeerStore) GetAddresses(n int, role network.PhoneBookEntryRoles) []string { return shuffleSelect(ps.filterRetryTime(time.Now(), role), n) @@ -84,34 +98,30 @@ func (ps *PeerStore) GetAddresses(n int, role network.PhoneBookEntryRoles) []str // UpdateRetryAfter updates the retryAfter time for the given address. func (ps *PeerStore) UpdateRetryAfter(addr string, retryAfter time.Time) { - info, err := peer.AddrInfoFromString(addr) + info, err := PeerInfoFromDomainPort(addr) if err != nil { return } - metadata, err := ps.Get(info.ID, "addressData") - if err != nil && errors.Is(err, libp2p.ErrNotFound) { - return - } else if err != nil { - panic(err) + metadata, _ := ps.Get(info.ID, "addressData") + if metadata != nil { + ad := metadata.(addressData) + ad.retryAfter = retryAfter + _ = ps.Put(info.ID, "addressData", ad) } - ad := metadata.(addressData) - ad.retryAfter = retryAfter - _ = ps.Put(info.ID, "addressData", ad) } -// GetConnectionWaitTime returns the connection wait time for the given address. +// GetConnectionWaitTime will calculate and return the wait +// time to prevent exceeding connectionsRateLimitingCount. +// The connection should be established when the waitTime is 0. +// It will register a provisional next connection time when the waitTime is 0. +// The provisional time should be updated after the connection with UpdateConnectionTime func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, time.Time) { curTime := time.Now() - info, err := peer.AddrInfoFromString(addr) + info, err := PeerInfoFromDomainPort(addr) if err != nil { return false, 0 /* not used */, curTime /* not used */ } - if info == nil { - // The addr is not in this phonebook. - // Will find the addr in a different phonebook. - return false, 0 /* not used */, curTime /* not used */ - } var timeSince time.Duration var numElmtsToRemove int metadata, err := ps.Get(info.ID, "addressData") @@ -120,13 +130,9 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti } ad := metadata.(addressData) // Remove from recentConnectionTimes the times later than ConnectionsRateLimitingWindowSeconds - connectionsRateLimitingWindow, err := ps.Get("peerID", "connectionsRateLimitingWindow") - if err != nil { - return false, 0 /* not used */, curTime /* not used */ - } for numElmtsToRemove < len(ad.recentConnectionTimes) { timeSince = curTime.Sub(ad.recentConnectionTimes[numElmtsToRemove]) - if timeSince >= connectionsRateLimitingWindow.(time.Duration) { + if timeSince >= ps.connectionsRateLimitingWindow { numElmtsToRemove++ } else { break // break the loop. The rest are earlier than 1 second @@ -143,7 +149,7 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti numElts := len(ad.recentConnectionTimes) if uint(numElts) >= connectionsRateLimitingCount.(uint) { return true, /* true */ - connectionsRateLimitingWindow.(time.Duration) - timeSince, curTime /* not used */ + ps.connectionsRateLimitingWindow - timeSince, curTime /* not used */ } // Else, there is space in connectionsRateLimitingCount. The @@ -157,7 +163,7 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti // UpdateConnectionTime updates the connection time for the given address. func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time) bool { - info, err := peer.AddrInfoFromString(addr) + info, err := PeerInfoFromDomainPort(addr) if err != nil { return false } @@ -204,7 +210,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, } for _, addr := range addressesThey { - info, err := peer.AddrInfoFromString(addr) + info, err := PeerInfoFromDomainPort(addr) if err != nil { return } @@ -219,6 +225,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, delete(removeItems, info.ID) } else { // we don't have this item. add it. + ps.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) entry := makePhonebookEntryData(networkName, role, false) _ = ps.Put(info.ID, "addressData", entry) } @@ -235,19 +242,23 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName string, role network.PhoneBookEntryRoles) { for _, addr := range dnsAddresses { - val, err := ps.Get("peerID", "addressData") - if err == nil { + info, err := PeerInfoFromDomainPort(addr) + if err != nil { + return + } + data, _ := ps.Get(info.ID, "addressData") + if data != nil { // we already have this. // Make sure the persistence field is set to true - data := val.(addressData) - data.persistent = true + ad := data.(addressData) + ad.persistent = true _ = ps.Put("peerID", "addressData", data) } else { // we don't have this item. add it. - ps.AddAddr("peerID", multiaddr.Cast([]byte(addr)), libp2p.PermanentAddrTTL) - data := makePhonebookEntryData(networkName, role, true) - _ = ps.Put("peerID", "addressData", data) + ps.AddAddrs(info.ID, info.Addrs, libp2p.PermanentAddrTTL) + entry := makePhonebookEntryData(networkName, role, true) + _ = ps.Put(info.ID, "addressData", entry) } } } @@ -277,6 +288,7 @@ func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { ad := data.(addressData) delete(ad.networkNames, networkName) if 0 == len(ad.networkNames) { + ps.ClearAddrs(peerID) _ = ps.Put(peerID, "addressData", nil) } } diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index a577da79c4..d90a80a57d 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -20,6 +20,7 @@ import ( "crypto/rand" "fmt" "testing" + "time" "github.com/algorand/go-algorand/network" "github.com/algorand/go-algorand/test/partitiontest" @@ -153,68 +154,117 @@ func generateMultiAddrs(n int) ([]string, []string) { func TestArrayPhonebookAll(t *testing.T) { partitiontest.PartitionTest(t) - multiaddrs, ids := generateMultiAddrs(10) - addrs, _ := PeerInfoFromAddrs(multiaddrs) - ps, err := NewPeerStore(addrs) + set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + var peerIDs []string + ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) - for _, id := range ids { + for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) - peerid, err := peer.Decode(id) - require.NoError(t, err) - ps.Put(peerid, "addressData", entry) + info, _ := PeerInfoFromDomainPort(addr) + peerIDs = append(peerIDs, info.ID.String()) + ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) + ph.Put(info.ID, "addressData", entry) } - testPhonebookAll(t, ids, ps) + testPhonebookAll(t, peerIDs, ph) } func TestArrayPhonebookUniform1(t *testing.T) { partitiontest.PartitionTest(t) - multiaddrs, ids := generateMultiAddrs(10) - addrs, _ := PeerInfoFromAddrs(multiaddrs) - ps, _ := NewPeerStore(addrs) - for _, id := range ids { + set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + var peerIDs []string + ph, err := MakePhonebook(1, 1*time.Millisecond) + require.NoError(t, err) + for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) - peerid, err := peer.Decode(id) - require.NoError(t, err) - ps.Put(peerid, "addressData", entry) + info, _ := PeerInfoFromDomainPort(addr) + peerIDs = append(peerIDs, info.ID.String()) + ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) + ph.Put(info.ID, "addressData", entry) } - testPhonebookUniform(t, ids, ps, 1) + testPhonebookUniform(t, peerIDs, ph, 1) } func TestArrayPhonebookUniform3(t *testing.T) { partitiontest.PartitionTest(t) - multiaddrs, ids := generateMultiAddrs(10) - addrs, _ := PeerInfoFromAddrs(multiaddrs) - ps, _ := NewPeerStore(addrs) - for _, id := range ids { + set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + var peerIDs []string + ph, err := MakePhonebook(1, 1*time.Millisecond) + require.NoError(t, err) + for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) - peerid, err := peer.Decode(id) - require.NoError(t, err) - ps.Put(peerid, "addressData", entry) + info, _ := PeerInfoFromDomainPort(addr) + peerIDs = append(peerIDs, info.ID.String()) + ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) + ph.Put(info.ID, "addressData", entry) } - testPhonebookUniform(t, ids, ps, 3) + testPhonebookUniform(t, peerIDs, ph, 3) } func TestMultiPhonebook(t *testing.T) { partitiontest.PartitionTest(t) - multiaddrs, ids := generateMultiAddrs(10) - addrs, _ := PeerInfoFromAddrs(multiaddrs) + set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + var peerIDs []string pha := make([]string, 0) - for _, e := range multiaddrs[:5] { + for _, e := range set[:5] { + info, _ := PeerInfoFromDomainPort(e) + peerIDs = append(peerIDs, info.ID.String()) pha = append(pha, e) } phb := make([]string, 0) - for _, e := range multiaddrs[5:] { + for _, e := range set[5:] { + info, _ := PeerInfoFromDomainPort(e) + peerIDs = append(peerIDs, info.ID.String()) phb = append(phb, e) } - ps, _ := NewPeerStore(addrs) - ps.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) - ps.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + ph, err := MakePhonebook(1, 1*time.Millisecond) + require.NoError(t, err) + ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + + testPhonebookAll(t, peerIDs, ph) + testPhonebookUniform(t, peerIDs, ph, 1) + testPhonebookUniform(t, peerIDs, ph, 3) +} + +// TestMultiPhonebookPersistentPeers validates that the peers added via Phonebook.AddPersistentPeers +// are not replaced when Phonebook.ReplacePeerList is called +func TestMultiPhonebookPersistentPeers(t *testing.T) { + partitiontest.PartitionTest(t) + + persistentPeers := []string{"a:4041"} + var persistentPeerIDs []string + for _, pp := range persistentPeers { + info, _ := PeerInfoFromDomainPort(pp) + persistentPeerIDs = append(persistentPeerIDs, info.ID.String()) + } + set := []string{"b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + var peerIDs []string + pha := make([]string, 0) + for _, e := range set[:5] { + info, _ := PeerInfoFromDomainPort(e) + peerIDs = append(peerIDs, info.ID.String()) + pha = append(pha, e) + } + phb := make([]string, 0) + for _, e := range set[5:] { + info, _ := PeerInfoFromDomainPort(e) + peerIDs = append(peerIDs, info.ID.String()) + phb = append(phb, e) + } + ph, err := MakePhonebook(1, 1*time.Millisecond) + require.NoError(t, err) + ph.AddPersistentPeers(persistentPeers, "pha", network.PhoneBookEntryRelayRole) + ph.AddPersistentPeers(persistentPeers, "phb", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) - testPhonebookAll(t, ids, ps) - testPhonebookUniform(t, ids, ps, 1) - testPhonebookUniform(t, ids, ps, 3) + testPhonebookAll(t, append(peerIDs, persistentPeerIDs...), ph) + allAddresses := ph.GetAddresses(len(set)+len(persistentPeers), network.PhoneBookEntryRelayRole) + for _, pp := range persistentPeerIDs { + require.Contains(t, allAddresses, pp) + } } diff --git a/network/p2p/peerstore/utils.go b/network/p2p/peerstore/utils.go index eabcccbdae..345bd98dd5 100644 --- a/network/p2p/peerstore/utils.go +++ b/network/p2p/peerstore/utils.go @@ -17,6 +17,9 @@ package peerstore import ( + "fmt" + "strings" + "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" ) @@ -49,3 +52,18 @@ func PeerInfoFromAddr(addr string) (*peer.AddrInfo, error) { } return info, nil } + +// PeerInfoFromDomainPort converts a string of the form domain:port to AddrInfo +func PeerInfoFromDomainPort(domainPort string) (*peer.AddrInfo, error) { + parts := strings.Split(domainPort, ":") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid domain port string %s, found %d colon-separated parts", domainPort, len(parts)) + } + maddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/dns4/%s/tcp/%s", parts[0], parts[1])) + if err != nil { + return nil, err + } + // These will never have peer IDs + transport, _ := peer.SplitAddr(maddr) + return &peer.AddrInfo{ID: peer.ID(domainPort), Addrs: []multiaddr.Multiaddr{transport}}, nil +} From 87aa4a99fcced0c57a244525664a94d7a7668776 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Mon, 28 Aug 2023 18:34:01 -0400 Subject: [PATCH 04/16] update tests --- network/p2p/peerstore/peerstore.go | 15 +- network/p2p/peerstore/peerstore_test.go | 235 +++++++++++++++++++----- 2 files changed, 199 insertions(+), 51 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index d300a3090c..4b3e430cbd 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -142,12 +142,8 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti // Remove the expired elements from e.data[addr].recentConnectionTimes ps.popNElements(numElmtsToRemove, peer.ID(addr)) // If there are max number of connections within the time window, wait - connectionsRateLimitingCount, err := ps.Get("peerID", "connectionsRateLimitingCount") - if err != nil { - return false, 0 /* not used */, curTime /* not used */ - } numElts := len(ad.recentConnectionTimes) - if uint(numElts) >= connectionsRateLimitingCount.(uint) { + if uint(numElts) >= ps.connectionsRateLimitingCount { return true, /* true */ ps.connectionsRateLimitingWindow - timeSince, curTime /* not used */ } @@ -172,13 +168,13 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time return false } ad := metadata.(addressData) - entry := ad.recentConnectionTimes defer func() { - _ = ps.Put(info.ID, "addressData", entry) + _ = ps.Put(info.ID, "addressData", ad) }() // Find the provisionalTime and update it + entry := ad.recentConnectionTimes for indx, val := range entry { if provisionalTime == val { entry[indx] = time.Now() @@ -190,6 +186,7 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time // This may happen when the time expires before the connection was established with the server. // The time should be added again. entry = append(entry, time.Now()) + ad.recentConnectionTimes = entry return true } @@ -265,7 +262,7 @@ func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName strin // Length returns the number of addrs in peerstore func (ps *PeerStore) Length() int { - return len(ps.PeersWithKeys()) + return len(ps.Peers()) } // makePhonebookEntryData creates a new address entry for provided network name and role. @@ -319,7 +316,7 @@ func (ps *PeerStore) filterRetryTime(t time.Time, role network.PhoneBookEntryRol if data != nil { ad := data.(addressData) if t.After(ad.retryAfter) && role == ad.role { - o = append(o, peerID.String()) + o = append(o, string(peerID)) } } } diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index d90a80a57d..d1e889ec35 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -138,85 +138,61 @@ func testPhonebookUniform(t *testing.T, set []string, ph network.Phonebook, gets } } -func generateMultiAddrs(n int) ([]string, []string) { - var multiaddrs []string - var ids []string - - for i := 0; i < n; i++ { - privKey, _, _ := libp2p_crypto.GenerateEd25519Key(rand.Reader) - peerID, _ := peer.IDFromPrivateKey(privKey) - ids = append(ids, peerID.String()) - multiaddrs = append(multiaddrs, fmt.Sprintf("/ip4/198.51.100.0/tcp/4242/p2p/%s", peerID.String())) - - } - return multiaddrs, ids -} func TestArrayPhonebookAll(t *testing.T) { partitiontest.PartitionTest(t) set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} - var peerIDs []string ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) - peerIDs = append(peerIDs, info.ID.String()) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) } - testPhonebookAll(t, peerIDs, ph) + testPhonebookAll(t, set, ph) } func TestArrayPhonebookUniform1(t *testing.T) { partitiontest.PartitionTest(t) set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} - var peerIDs []string ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) - peerIDs = append(peerIDs, info.ID.String()) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) } - testPhonebookUniform(t, peerIDs, ph, 1) + testPhonebookUniform(t, set, ph, 1) } func TestArrayPhonebookUniform3(t *testing.T) { partitiontest.PartitionTest(t) set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} - var peerIDs []string ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) - peerIDs = append(peerIDs, info.ID.String()) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) } - testPhonebookUniform(t, peerIDs, ph, 3) + testPhonebookUniform(t, set, ph, 3) } func TestMultiPhonebook(t *testing.T) { partitiontest.PartitionTest(t) set := []string{"a:4041", "b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} - var peerIDs []string pha := make([]string, 0) for _, e := range set[:5] { - info, _ := PeerInfoFromDomainPort(e) - peerIDs = append(peerIDs, info.ID.String()) pha = append(pha, e) } phb := make([]string, 0) for _, e := range set[5:] { - info, _ := PeerInfoFromDomainPort(e) - peerIDs = append(peerIDs, info.ID.String()) phb = append(phb, e) } @@ -225,9 +201,9 @@ func TestMultiPhonebook(t *testing.T) { ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) - testPhonebookAll(t, peerIDs, ph) - testPhonebookUniform(t, peerIDs, ph, 1) - testPhonebookUniform(t, peerIDs, ph, 3) + testPhonebookAll(t, set, ph) + testPhonebookUniform(t, set, ph, 1) + testPhonebookUniform(t, set, ph, 3) } // TestMultiPhonebookPersistentPeers validates that the peers added via Phonebook.AddPersistentPeers @@ -236,23 +212,13 @@ func TestMultiPhonebookPersistentPeers(t *testing.T) { partitiontest.PartitionTest(t) persistentPeers := []string{"a:4041"} - var persistentPeerIDs []string - for _, pp := range persistentPeers { - info, _ := PeerInfoFromDomainPort(pp) - persistentPeerIDs = append(persistentPeerIDs, info.ID.String()) - } set := []string{"b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} - var peerIDs []string pha := make([]string, 0) for _, e := range set[:5] { - info, _ := PeerInfoFromDomainPort(e) - peerIDs = append(peerIDs, info.ID.String()) pha = append(pha, e) } phb := make([]string, 0) for _, e := range set[5:] { - info, _ := PeerInfoFromDomainPort(e) - peerIDs = append(peerIDs, info.ID.String()) phb = append(phb, e) } ph, err := MakePhonebook(1, 1*time.Millisecond) @@ -262,9 +228,194 @@ func TestMultiPhonebookPersistentPeers(t *testing.T) { ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) - testPhonebookAll(t, append(peerIDs, persistentPeerIDs...), ph) + testPhonebookAll(t, append(set, persistentPeers...), ph) allAddresses := ph.GetAddresses(len(set)+len(persistentPeers), network.PhoneBookEntryRelayRole) - for _, pp := range persistentPeerIDs { + for _, pp := range persistentPeers { require.Contains(t, allAddresses, pp) } } + +func TestMultiPhonebookDuplicateFiltering(t *testing.T) { + partitiontest.PartitionTest(t) + + set := []string{"b:4042", "c:4043", "d:4044", "e:4045", "f:4046", "g:4047", "h:4048", "i:4049", "j:4010"} + pha := make([]string, 0) + for _, e := range set[:7] { + pha = append(pha, e) + } + phb := make([]string, 0) + for _, e := range set[3:] { + phb = append(phb, e) + } + ph, err := MakePhonebook(1, 1*time.Millisecond) + require.NoError(t, err) + ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + + testPhonebookAll(t, set, ph) + testPhonebookUniform(t, set, ph, 1) + testPhonebookUniform(t, set, ph, 3) +} + +func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { + partitiontest.PartitionTest(t) + + // make the connectionsRateLimitingWindow long enough to avoid triggering it when the + // test is running in a slow environment + // The test will artificially simulate time passing + timeUnit := 2000 * time.Second + connectionsRateLimitingWindow := 2 * timeUnit + entries, err := MakePhonebook(3, connectionsRateLimitingWindow) + require.NoError(t, err) + addr1 := "addrABC:4040" + addr2 := "addrXYZ:4041" + info1, _ := PeerInfoFromDomainPort(addr1) + info2, _ := PeerInfoFromDomainPort(addr2) + + // Address not in. Should return false + addrInPhonebook, _, provisionalTime := entries.GetConnectionWaitTime(addr1) + require.Equal(t, false, addrInPhonebook) + require.Equal(t, false, entries.UpdateConnectionTime(addr1, provisionalTime)) + + // Test the addresses are populated in the phonebook and a + // time can be added to one of them + entries.ReplacePeerList([]string{addr1, addr2}, "default", network.PhoneBookEntryRelayRole) + addrInPhonebook, waitTime, provisionalTime := entries.GetConnectionWaitTime(addr1) + require.Equal(t, true, addrInPhonebook) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) + data, _ := entries.Get(info1.ID, "addressData") + require.NotNil(t, data) + ad := data.(addressData) + phBookData := ad.recentConnectionTimes + require.Equal(t, 1, len(phBookData)) + + // simulate passing a unit of time + for rct := range phBookData { + phBookData[rct] = phBookData[rct].Add(-1 * timeUnit) + } + + // add another value to addr + addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr1) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) + data, _ = entries.Get(info1.ID, "addressData") + ad = data.(addressData) + phBookData = ad.recentConnectionTimes + require.Equal(t, 2, len(phBookData)) + + // simulate passing a unit of time + for rct := range phBookData { + phBookData[rct] = phBookData[rct].Add(-1 * timeUnit) + } + + // the first time should be removed and a new one added + // there should not be any wait + addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr1) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) + data, _ = entries.Get(info1.ID, "addressData") + ad = data.(addressData) + phBookData2 := ad.recentConnectionTimes + require.Equal(t, 2, len(phBookData2)) + + // make sure the right time was removed + require.Equal(t, phBookData[1], phBookData2[0]) + require.Equal(t, true, phBookData2[0].Before(phBookData2[1])) + + // try requesting from another address, make sure + // a separate array is used for these new requests + + // add 3 values to another address. should not wait + // value 1 + _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) + + // introduce a gap between the two requests so that only the first will be removed later when waited + // simulate passing a unit of time + data2, _ := entries.Get(info2.ID, "addressData") + require.NotNil(t, data2) + ad2 := data2.(addressData) + for rct := range ad2.recentConnectionTimes { + ad2.recentConnectionTimes[rct] = ad2.recentConnectionTimes[rct].Add(-1 * timeUnit) + } + + // value 2 + addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) + // value 3 + _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) + + data2, _ = entries.Get(info2.ID, "addressData") + ad2 = data2.(addressData) + phBookData = ad2.recentConnectionTimes + // all three times should be queued + require.Equal(t, 3, len(phBookData)) + + // add another element to trigger wait + _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + require.Greater(t, int64(waitTime), int64(0)) + // no element should be removed + data2, _ = entries.Get(info2.ID, "addressData") + ad2 = data2.(addressData) + phBookData2 = ad2.recentConnectionTimes + require.Equal(t, phBookData[0], phBookData2[0]) + require.Equal(t, phBookData[1], phBookData2[1]) + require.Equal(t, phBookData[2], phBookData2[2]) + + // simulate passing of the waitTime duration + for rct := range ad2.recentConnectionTimes { + ad2.recentConnectionTimes[rct] = ad2.recentConnectionTimes[rct].Add(-1 * waitTime) + } + + // The wait should be sufficient + _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + require.Equal(t, time.Duration(0), waitTime) + require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) + // only one element should be removed, and one added + data2, _ = entries.Get(info2.ID, "addressData") + ad2 = data2.(addressData) + phBookData2 = ad2.recentConnectionTimes + require.Equal(t, 3, len(phBookData2)) + + // make sure the right time was removed + require.Equal(t, phBookData[1], phBookData2[0]) + require.Equal(t, phBookData[2], phBookData2[1]) +} + +// TestPhonebookRoles tests that the filtering by roles for different +// phonebooks entries works as expected. +func TestPhonebookRoles(t *testing.T) { + partitiontest.PartitionTest(t) + + relaysSet := []string{"relay1:4040", "relay2:4041", "relay3:4042"} + archiverSet := []string{"archiver1:1111", "archiver2:1112", "archiver3:1113"} + + ph, err := MakePhonebook(1, 1) + require.NoError(t, err) + ph.ReplacePeerList(relaysSet, "default", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(archiverSet, "default", network.PhoneBookEntryArchiverRole) + require.Equal(t, len(relaysSet)+len(archiverSet), len(ph.Peers())) + require.Equal(t, len(relaysSet)+len(archiverSet), ph.Length()) + + for _, role := range []network.PhoneBookEntryRoles{network.PhoneBookEntryRelayRole, network.PhoneBookEntryArchiverRole} { + for k := 0; k < 100; k++ { + for l := 0; l < 3; l++ { + entries := ph.GetAddresses(l, role) + if role == network.PhoneBookEntryRelayRole { + for _, entry := range entries { + require.Contains(t, entry, "relay") + } + } else if role == network.PhoneBookEntryArchiverRole { + for _, entry := range entries { + require.Contains(t, entry, "archiver") + } + } + } + } + } +} From 111893db59632e3a3f4d8aed831c8fe6e6b04a4f Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Tue, 29 Aug 2023 11:59:48 -0400 Subject: [PATCH 05/16] fix failing test --- network/p2p/peerstore/peerstore.go | 2 ++ network/p2p/peerstore/peerstore_test.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 4b3e430cbd..3a11c9fa0b 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -142,6 +142,8 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti // Remove the expired elements from e.data[addr].recentConnectionTimes ps.popNElements(numElmtsToRemove, peer.ID(addr)) // If there are max number of connections within the time window, wait + metadata, _ = ps.Get(info.ID, "addressData") + ad = metadata.(addressData) numElts := len(ad.recentConnectionTimes) if uint(numElts) >= ps.connectionsRateLimitingCount { return true, /* true */ diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index d1e889ec35..d68954292f 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -342,7 +342,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { } // value 2 - addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) + _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) // value 3 From d22f5e4f2831531da2ce4350ba2353ea560359c5 Mon Sep 17 00:00:00 2001 From: shiqizng <80276844+shiqizng@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:33:02 -0400 Subject: [PATCH 06/16] Update network/p2p/peerstore/peerstore.go Co-authored-by: Zeph Grunschlag --- network/p2p/peerstore/peerstore.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 3a11c9fa0b..ae5d7886b2 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -41,8 +41,8 @@ type addressData struct { // retryAfter is the time to wait before retrying to connect to the address. retryAfter time.Time - // recentConnectionTimes: is the log of connection times used to observe the maximum - // connections to the address in a given time window. + // recentConnectionTimes is the log of connection times used to observe the maximum + // connections to the address in a given time window. recentConnectionTimes []time.Time // networkNames: lists the networks to which the given address belongs. From 39f745db68641b3767977a0681ec34184156a64e Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 30 Aug 2023 11:19:00 -0400 Subject: [PATCH 07/16] fix import cycle --- network/p2p/peerstore/peerstore.go | 65 +++++++++++++++++++++---- network/p2p/peerstore/peerstore_test.go | 45 +++++++++-------- 2 files changed, 78 insertions(+), 32 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index ae5d7886b2..3d31d1699c 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -18,6 +18,7 @@ package peerstore import ( "fmt" + "math" "math/rand" "time" @@ -25,10 +26,56 @@ import ( libp2p "github.com/libp2p/go-libp2p/core/peerstore" mempstore "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" "golang.org/x/exp/slices" - - "github.com/algorand/go-algorand/network" ) +// GetAllAddresses when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless +// of how many addresses the phonebook actually has. ( with the retry-after logic applied ) +const GetAllAddresses = math.MaxInt32 + +// PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. +// currently, we have two roles : relay role and archiver role, which are mutually exclusive. +// +//msgp:ignore PhoneBookEntryRoles +type PhoneBookEntryRoles int + +// PhoneBookEntryRelayRole used for all the relays that are provided either via the algobootstrap SRV record +// or via a configuration file. +const PhoneBookEntryRelayRole = 1 + +// PhoneBookEntryArchiverRole used for all the archivers that are provided via the archive SRV record. +const PhoneBookEntryArchiverRole = 2 + +// Phonebook stores or looks up addresses of nodes we might contact +type Phonebook interface { + // GetAddresses(N) returns up to N addresses, but may return fewer + GetAddresses(n int, role PhoneBookEntryRoles) []string + + // UpdateRetryAfter updates the retry-after field for the entries matching the given address + UpdateRetryAfter(addr string, retryAfter time.Time) + + // GetConnectionWaitTime will calculate and return the wait + // time to prevent exceeding connectionsRateLimitingCount. + // The connection should be established when the waitTime is 0. + // It will register a provisional next connection time when the waitTime is 0. + // The provisional time should be updated after the connection with UpdateConnectionTime + GetConnectionWaitTime(addr string) (addrInPhonebook bool, + waitTime time.Duration, provisionalTime time.Time) + + // UpdateConnectionTime will update the provisional connection time. + // Returns true of the addr was in the phonebook + UpdateConnectionTime(addr string, provisionalTime time.Time) bool + + // ReplacePeerList merges a set of addresses with that passed in for networkName + // new entries in dnsAddresses are being added + // existing items that aren't included in dnsAddresses are being removed + // matching entries don't change + ReplacePeerList(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) + + // AddPersistentPeers stores addresses of peers which are persistent. + // i.e. they won't be replaced by ReplacePeerList calls + AddPersistentPeers(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) +} + // PeerStore implements Peerstore and CertifiedAddrBook. type PeerStore struct { peerStoreCAB @@ -49,7 +96,7 @@ type addressData struct { networkNames map[string]bool // role is the role that this address serves. - role network.PhoneBookEntryRoles + role PhoneBookEntryRoles // persistent is set true for peers whose record should not be removed for the peer list persistent bool @@ -92,7 +139,7 @@ func MakePhonebook(connectionsRateLimitingCount uint, } // GetAddresses returns up to N addresses, but may return fewer -func (ps *PeerStore) GetAddresses(n int, role network.PhoneBookEntryRoles) []string { +func (ps *PeerStore) GetAddresses(n int, role PhoneBookEntryRoles) []string { return shuffleSelect(ps.filterRetryTime(time.Now(), role), n) } @@ -194,7 +241,7 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time } // ReplacePeerList replaces the peer list for the given networkName and role. -func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, role network.PhoneBookEntryRoles) { +func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, role PhoneBookEntryRoles) { // prepare a map of items we'd like to remove. removeItems := make(map[peer.ID]bool, 0) peerIDs := ps.Peers() @@ -238,7 +285,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, // AddPersistentPeers stores addresses of peers which are persistent. // i.e. they won't be replaced by ReplacePeerList calls -func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName string, role network.PhoneBookEntryRoles) { +func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) { for _, addr := range dnsAddresses { info, err := PeerInfoFromDomainPort(addr) @@ -268,7 +315,7 @@ func (ps *PeerStore) Length() int { } // makePhonebookEntryData creates a new address entry for provided network name and role. -func makePhonebookEntryData(networkName string, role network.PhoneBookEntryRoles, persistent bool) addressData { +func makePhonebookEntryData(networkName string, role PhoneBookEntryRoles, persistent bool) addressData { pbData := addressData{ networkNames: make(map[string]bool), recentConnectionTimes: make([]time.Time, 0), @@ -311,7 +358,7 @@ func (ps *PeerStore) popNElements(n int, peerID peer.ID) { _ = ps.Put(peerID, "addressData", ad) } -func (ps *PeerStore) filterRetryTime(t time.Time, role network.PhoneBookEntryRoles) []string { +func (ps *PeerStore) filterRetryTime(t time.Time, role PhoneBookEntryRoles) []string { o := make([]string, 0, len(ps.Peers())) for _, peerID := range ps.Peers() { data, _ := ps.Get(peerID, "addressData") @@ -326,7 +373,7 @@ func (ps *PeerStore) filterRetryTime(t time.Time, role network.PhoneBookEntryRol } func shuffleSelect(set []string, n int) []string { - if n >= len(set) || n == network.GetAllAddresses { + if n >= len(set) || n == GetAllAddresses { // return shuffled copy of everything out := slices.Clone(set) shuffleStrings(out) diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index d68954292f..c65868ffec 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -22,7 +22,6 @@ import ( "testing" "time" - "github.com/algorand/go-algorand/network" "github.com/algorand/go-algorand/test/partitiontest" libp2p_crypto "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" @@ -80,8 +79,8 @@ func TestPeerstore(t *testing.T) { } -func testPhonebookAll(t *testing.T, set []string, ph network.Phonebook) { - actual := ph.GetAddresses(len(set), network.PhoneBookEntryRelayRole) +func testPhonebookAll(t *testing.T, set []string, ph Phonebook) { + actual := ph.GetAddresses(len(set), PhoneBookEntryRelayRole) for _, got := range actual { ok := false for _, known := range set { @@ -108,12 +107,12 @@ func testPhonebookAll(t *testing.T, set []string, ph network.Phonebook) { } } -func testPhonebookUniform(t *testing.T, set []string, ph network.Phonebook, getsize int) { +func testPhonebookUniform(t *testing.T, set []string, ph Phonebook, getsize int) { uniformityTestLength := 250000 / len(set) expected := (uniformityTestLength * getsize) / len(set) counts := make([]int, len(set)) for i := 0; i < uniformityTestLength; i++ { - actual := ph.GetAddresses(getsize, network.PhoneBookEntryRelayRole) + actual := ph.GetAddresses(getsize, PhoneBookEntryRelayRole) for i, known := range set { for _, xa := range actual { if known == xa { @@ -145,7 +144,7 @@ func TestArrayPhonebookAll(t *testing.T) { ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { - entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) @@ -160,7 +159,7 @@ func TestArrayPhonebookUniform1(t *testing.T) { ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { - entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) @@ -175,7 +174,7 @@ func TestArrayPhonebookUniform3(t *testing.T) { ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) for _, addr := range set { - entry := makePhonebookEntryData("", network.PhoneBookEntryRelayRole, false) + entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) ph.Put(info.ID, "addressData", entry) @@ -198,8 +197,8 @@ func TestMultiPhonebook(t *testing.T) { ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) - ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) - ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(pha, "pha", PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", PhoneBookEntryRelayRole) testPhonebookAll(t, set, ph) testPhonebookUniform(t, set, ph, 1) @@ -223,13 +222,13 @@ func TestMultiPhonebookPersistentPeers(t *testing.T) { } ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) - ph.AddPersistentPeers(persistentPeers, "pha", network.PhoneBookEntryRelayRole) - ph.AddPersistentPeers(persistentPeers, "phb", network.PhoneBookEntryRelayRole) - ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) - ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + ph.AddPersistentPeers(persistentPeers, "pha", PhoneBookEntryRelayRole) + ph.AddPersistentPeers(persistentPeers, "phb", PhoneBookEntryRelayRole) + ph.ReplacePeerList(pha, "pha", PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", PhoneBookEntryRelayRole) testPhonebookAll(t, append(set, persistentPeers...), ph) - allAddresses := ph.GetAddresses(len(set)+len(persistentPeers), network.PhoneBookEntryRelayRole) + allAddresses := ph.GetAddresses(len(set)+len(persistentPeers), PhoneBookEntryRelayRole) for _, pp := range persistentPeers { require.Contains(t, allAddresses, pp) } @@ -249,8 +248,8 @@ func TestMultiPhonebookDuplicateFiltering(t *testing.T) { } ph, err := MakePhonebook(1, 1*time.Millisecond) require.NoError(t, err) - ph.ReplacePeerList(pha, "pha", network.PhoneBookEntryRelayRole) - ph.ReplacePeerList(phb, "phb", network.PhoneBookEntryRelayRole) + ph.ReplacePeerList(pha, "pha", PhoneBookEntryRelayRole) + ph.ReplacePeerList(phb, "phb", PhoneBookEntryRelayRole) testPhonebookAll(t, set, ph) testPhonebookUniform(t, set, ph, 1) @@ -279,7 +278,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { // Test the addresses are populated in the phonebook and a // time can be added to one of them - entries.ReplacePeerList([]string{addr1, addr2}, "default", network.PhoneBookEntryRelayRole) + entries.ReplacePeerList([]string{addr1, addr2}, "default", PhoneBookEntryRelayRole) addrInPhonebook, waitTime, provisionalTime := entries.GetConnectionWaitTime(addr1) require.Equal(t, true, addrInPhonebook) require.Equal(t, time.Duration(0), waitTime) @@ -397,20 +396,20 @@ func TestPhonebookRoles(t *testing.T) { ph, err := MakePhonebook(1, 1) require.NoError(t, err) - ph.ReplacePeerList(relaysSet, "default", network.PhoneBookEntryRelayRole) - ph.ReplacePeerList(archiverSet, "default", network.PhoneBookEntryArchiverRole) + ph.ReplacePeerList(relaysSet, "default", PhoneBookEntryRelayRole) + ph.ReplacePeerList(archiverSet, "default", PhoneBookEntryArchiverRole) require.Equal(t, len(relaysSet)+len(archiverSet), len(ph.Peers())) require.Equal(t, len(relaysSet)+len(archiverSet), ph.Length()) - for _, role := range []network.PhoneBookEntryRoles{network.PhoneBookEntryRelayRole, network.PhoneBookEntryArchiverRole} { + for _, role := range []PhoneBookEntryRoles{PhoneBookEntryRelayRole, PhoneBookEntryArchiverRole} { for k := 0; k < 100; k++ { for l := 0; l < 3; l++ { entries := ph.GetAddresses(l, role) - if role == network.PhoneBookEntryRelayRole { + if role == PhoneBookEntryRelayRole { for _, entry := range entries { require.Contains(t, entry, "relay") } - } else if role == network.PhoneBookEntryArchiverRole { + } else if role == PhoneBookEntryArchiverRole { for _, entry := range entries { require.Contains(t, entry, "archiver") } From b787852393f7ca28f336b41d961e1e8ac9950306 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 30 Aug 2023 12:11:13 -0400 Subject: [PATCH 08/16] address PR comments --- network/p2p/peerstore/peerstore.go | 22 +++++++++++++++++----- network/p2p/peerstore/utils.go | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 3d31d1699c..244c5c1ee8 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -151,7 +151,10 @@ func (ps *PeerStore) UpdateRetryAfter(addr string, retryAfter time.Time) { } metadata, _ := ps.Get(info.ID, "addressData") if metadata != nil { - ad := metadata.(addressData) + ad, ok := metadata.(addressData) + if !ok { + return + } ad.retryAfter = retryAfter _ = ps.Put(info.ID, "addressData", ad) } @@ -175,7 +178,10 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti if err != nil { return false, 0 /* not used */, curTime /* not used */ } - ad := metadata.(addressData) + ad, ok := metadata.(addressData) + if !ok { + return false, 0 /* not used */, curTime /* not used */ + } // Remove from recentConnectionTimes the times later than ConnectionsRateLimitingWindowSeconds for numElmtsToRemove < len(ad.recentConnectionTimes) { timeSince = curTime.Sub(ad.recentConnectionTimes[numElmtsToRemove]) @@ -190,7 +196,10 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti ps.popNElements(numElmtsToRemove, peer.ID(addr)) // If there are max number of connections within the time window, wait metadata, _ = ps.Get(info.ID, "addressData") - ad = metadata.(addressData) + ad, ok = metadata.(addressData) + if !ok { + return false, 0 /* not used */, curTime /* not used */ + } numElts := len(ad.recentConnectionTimes) if uint(numElts) >= ps.connectionsRateLimitingCount { return true, /* true */ @@ -216,7 +225,10 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time if err != nil { return false } - ad := metadata.(addressData) + ad, ok := metadata.(addressData) + if !ok { + return false + } defer func() { _ = ps.Put(info.ID, "addressData", ad) @@ -397,5 +409,5 @@ func shuffleSelect(set []string, n int) []string { } func shuffleStrings(set []string) { - rand.Shuffle(len(set), func(i, j int) { t := set[i]; set[i] = set[j]; set[j] = t }) + rand.Shuffle(len(set), func(i, j int) { set[i], set[j] = set[j], set[i] }) } diff --git a/network/p2p/peerstore/utils.go b/network/p2p/peerstore/utils.go index 345bd98dd5..b96fc1c8e0 100644 --- a/network/p2p/peerstore/utils.go +++ b/network/p2p/peerstore/utils.go @@ -56,7 +56,7 @@ func PeerInfoFromAddr(addr string) (*peer.AddrInfo, error) { // PeerInfoFromDomainPort converts a string of the form domain:port to AddrInfo func PeerInfoFromDomainPort(domainPort string) (*peer.AddrInfo, error) { parts := strings.Split(domainPort, ":") - if len(parts) != 2 { + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { return nil, fmt.Errorf("invalid domain port string %s, found %d colon-separated parts", domainPort, len(parts)) } maddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/dns4/%s/tcp/%s", parts[0], parts[1])) From b1449e86f37b76d5f3d1e1caaf35458842571109 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 30 Aug 2023 13:56:29 -0400 Subject: [PATCH 09/16] update test --- network/p2p/peerstore/peerstore_test.go | 27 +++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index c65868ffec..b3e5fe812a 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -19,6 +19,7 @@ package peerstore import ( "crypto/rand" "fmt" + "math" "testing" "time" @@ -110,25 +111,25 @@ func testPhonebookAll(t *testing.T, set []string, ph Phonebook) { func testPhonebookUniform(t *testing.T, set []string, ph Phonebook, getsize int) { uniformityTestLength := 250000 / len(set) expected := (uniformityTestLength * getsize) / len(set) - counts := make([]int, len(set)) + counts := make(map[string]int) + for i := 0; i < len(set); i++ { + counts[set[i]] = 0 + } for i := 0; i < uniformityTestLength; i++ { actual := ph.GetAddresses(getsize, PhoneBookEntryRelayRole) - for i, known := range set { - for _, xa := range actual { - if known == xa { - counts[i]++ - } + for _, xa := range actual { + if _, ok := counts[xa]; ok { + counts[xa]++ } } } - min := counts[0] - max := counts[0] - for i := 1; i < len(counts); i++ { - if counts[i] > max { - max = counts[i] + min, max := math.MaxInt, 0 + for _, count := range counts { + if count > max { + max = count } - if counts[i] < min { - min = counts[i] + if count < min { + min = count } } // TODO: what's a good probability-theoretic threshold for good enough? From 78973c19bbf3dc5200da5b2e1e35749aa42e15c9 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 30 Aug 2023 14:49:51 -0400 Subject: [PATCH 10/16] updates --- network/p2p/peerstore/peerstore.go | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 244c5c1ee8..260c6588a4 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -76,6 +76,8 @@ type Phonebook interface { AddPersistentPeers(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) } +const addressDataKey string = "addressData" + // PeerStore implements Peerstore and CertifiedAddrBook. type PeerStore struct { peerStoreCAB @@ -149,14 +151,14 @@ func (ps *PeerStore) UpdateRetryAfter(addr string, retryAfter time.Time) { if err != nil { return } - metadata, _ := ps.Get(info.ID, "addressData") + metadata, _ := ps.Get(info.ID, addressDataKey) if metadata != nil { ad, ok := metadata.(addressData) if !ok { return } ad.retryAfter = retryAfter - _ = ps.Put(info.ID, "addressData", ad) + _ = ps.Put(info.ID, addressDataKey, ad) } } @@ -174,7 +176,7 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti } var timeSince time.Duration var numElmtsToRemove int - metadata, err := ps.Get(info.ID, "addressData") + metadata, err := ps.Get(info.ID, addressDataKey) if err != nil { return false, 0 /* not used */, curTime /* not used */ } @@ -195,7 +197,7 @@ func (ps *PeerStore) GetConnectionWaitTime(addr string) (bool, time.Duration, ti // Remove the expired elements from e.data[addr].recentConnectionTimes ps.popNElements(numElmtsToRemove, peer.ID(addr)) // If there are max number of connections within the time window, wait - metadata, _ = ps.Get(info.ID, "addressData") + metadata, _ = ps.Get(info.ID, addressDataKey) ad, ok = metadata.(addressData) if !ok { return false, 0 /* not used */, curTime /* not used */ @@ -221,7 +223,7 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time if err != nil { return false } - metadata, err := ps.Get(info.ID, "addressData") + metadata, err := ps.Get(info.ID, addressDataKey) if err != nil { return false } @@ -230,7 +232,7 @@ func (ps *PeerStore) UpdateConnectionTime(addr string, provisionalTime time.Time return false } defer func() { - _ = ps.Put(info.ID, "addressData", ad) + _ = ps.Put(info.ID, addressDataKey, ad) }() @@ -258,7 +260,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, removeItems := make(map[peer.ID]bool, 0) peerIDs := ps.Peers() for _, pid := range peerIDs { - data, _ := ps.Get(pid, "addressData") + data, _ := ps.Get(pid, addressDataKey) if data != nil { ad := data.(addressData) if ad.networkNames[networkName] && ad.role == role && !ad.persistent { @@ -272,7 +274,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, if err != nil { return } - data, _ := ps.Get(info.ID, "addressData") + data, _ := ps.Get(info.ID, addressDataKey) if data != nil { // we already have this. // Update the networkName @@ -285,7 +287,7 @@ func (ps *PeerStore) ReplacePeerList(addressesThey []string, networkName string, // we don't have this item. add it. ps.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) entry := makePhonebookEntryData(networkName, role, false) - _ = ps.Put(info.ID, "addressData", entry) + _ = ps.Put(info.ID, addressDataKey, entry) } } @@ -304,19 +306,19 @@ func (ps *PeerStore) AddPersistentPeers(dnsAddresses []string, networkName strin if err != nil { return } - data, _ := ps.Get(info.ID, "addressData") + data, _ := ps.Get(info.ID, addressDataKey) if data != nil { // we already have this. // Make sure the persistence field is set to true ad := data.(addressData) ad.persistent = true - _ = ps.Put("peerID", "addressData", data) + _ = ps.Put(info.ID, addressDataKey, data) } else { // we don't have this item. add it. ps.AddAddrs(info.ID, info.Addrs, libp2p.PermanentAddrTTL) entry := makePhonebookEntryData(networkName, role, true) - _ = ps.Put(info.ID, "addressData", entry) + _ = ps.Put(info.ID, addressDataKey, entry) } } } @@ -339,7 +341,7 @@ func makePhonebookEntryData(networkName string, role PhoneBookEntryRoles, persis } func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { - data, err := ps.Get(peerID, "addressData") + data, err := ps.Get(peerID, addressDataKey) if err != nil { return } @@ -347,33 +349,33 @@ func (ps *PeerStore) deletePhonebookEntry(peerID peer.ID, networkName string) { delete(ad.networkNames, networkName) if 0 == len(ad.networkNames) { ps.ClearAddrs(peerID) - _ = ps.Put(peerID, "addressData", nil) + _ = ps.Put(peerID, addressDataKey, nil) } } // AppendTime adds the current time to recentConnectionTimes in // addressData of addr func (ps *PeerStore) appendTime(peerID peer.ID, t time.Time) { - data, _ := ps.Get(peerID, "addressData") + data, _ := ps.Get(peerID, addressDataKey) ad := data.(addressData) ad.recentConnectionTimes = append(ad.recentConnectionTimes, t) - _ = ps.Put(peerID, "addressData", ad) + _ = ps.Put(peerID, addressDataKey, ad) } // PopEarliestTime removes the earliest time from recentConnectionTimes in // addressData for addr // It is expected to be later than ConnectionsRateLimitingWindow func (ps *PeerStore) popNElements(n int, peerID peer.ID) { - data, _ := ps.Get(peerID, "addressData") + data, _ := ps.Get(peerID, addressDataKey) ad := data.(addressData) ad.recentConnectionTimes = ad.recentConnectionTimes[n:] - _ = ps.Put(peerID, "addressData", ad) + _ = ps.Put(peerID, addressDataKey, ad) } func (ps *PeerStore) filterRetryTime(t time.Time, role PhoneBookEntryRoles) []string { o := make([]string, 0, len(ps.Peers())) for _, peerID := range ps.Peers() { - data, _ := ps.Get(peerID, "addressData") + data, _ := ps.Get(peerID, addressDataKey) if data != nil { ad := data.(addressData) if t.After(ad.retryAfter) && role == ad.role { From 0c3224784672f011a83c8f58f1b8c253b0977c65 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Wed, 30 Aug 2023 15:07:06 -0400 Subject: [PATCH 11/16] unexport a var --- network/p2p/peerstore/peerstore.go | 6 +++--- network/phonebook.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 260c6588a4..2ed2beaf5e 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -28,9 +28,9 @@ import ( "golang.org/x/exp/slices" ) -// GetAllAddresses when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless +// when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless // of how many addresses the phonebook actually has. ( with the retry-after logic applied ) -const GetAllAddresses = math.MaxInt32 +const getAllAddresses = math.MaxInt32 // PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. // currently, we have two roles : relay role and archiver role, which are mutually exclusive. @@ -387,7 +387,7 @@ func (ps *PeerStore) filterRetryTime(t time.Time, role PhoneBookEntryRoles) []st } func shuffleSelect(set []string, n int) []string { - if n >= len(set) || n == GetAllAddresses { + if n >= len(set) || n == getAllAddresses { // return shuffled copy of everything out := slices.Clone(set) shuffleStrings(out) diff --git a/network/phonebook.go b/network/phonebook.go index ce0de9d3c2..cf189eb6a4 100644 --- a/network/phonebook.go +++ b/network/phonebook.go @@ -25,9 +25,9 @@ import ( "golang.org/x/exp/slices" ) -// GetAllAddresses when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless +// getAllAddresses when using GetAddresses with getAllAddresses, all the addresses will be retrieved, regardless // of how many addresses the phonebook actually has. ( with the retry-after logic applied ) -const GetAllAddresses = math.MaxInt32 +const getAllAddresses = math.MaxInt32 // PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. // currently, we have two roles : relay role and archiver role, which are mutually exclusive. @@ -308,7 +308,7 @@ func shuffleStrings(set []string) { } func shuffleSelect(set []string, n int) []string { - if n >= len(set) || n == GetAllAddresses { + if n >= len(set) || n == getAllAddresses { // return shuffled copy of everything out := slices.Clone(set) shuffleStrings(out) From dcb0633d477a0068df0e73c212d8a368c977a2c1 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Thu, 31 Aug 2023 11:30:41 -0400 Subject: [PATCH 12/16] replace addressData strs --- network/p2p/peerstore/peerstore_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index b3e5fe812a..f35c1d5696 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -148,7 +148,7 @@ func TestArrayPhonebookAll(t *testing.T) { entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) - ph.Put(info.ID, "addressData", entry) + ph.Put(info.ID, addressDataKey, entry) } testPhonebookAll(t, set, ph) } @@ -163,7 +163,7 @@ func TestArrayPhonebookUniform1(t *testing.T) { entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) - ph.Put(info.ID, "addressData", entry) + ph.Put(info.ID, addressDataKey, entry) } testPhonebookUniform(t, set, ph, 1) } @@ -178,7 +178,7 @@ func TestArrayPhonebookUniform3(t *testing.T) { entry := makePhonebookEntryData("", PhoneBookEntryRelayRole, false) info, _ := PeerInfoFromDomainPort(addr) ph.AddAddrs(info.ID, info.Addrs, libp2p.AddressTTL) - ph.Put(info.ID, "addressData", entry) + ph.Put(info.ID, addressDataKey, entry) } testPhonebookUniform(t, set, ph, 3) } @@ -284,7 +284,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { require.Equal(t, true, addrInPhonebook) require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) - data, _ := entries.Get(info1.ID, "addressData") + data, _ := entries.Get(info1.ID, addressDataKey) require.NotNil(t, data) ad := data.(addressData) phBookData := ad.recentConnectionTimes @@ -299,7 +299,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr1) require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) - data, _ = entries.Get(info1.ID, "addressData") + data, _ = entries.Get(info1.ID, addressDataKey) ad = data.(addressData) phBookData = ad.recentConnectionTimes require.Equal(t, 2, len(phBookData)) @@ -314,7 +314,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { addrInPhonebook, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr1) require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr1, provisionalTime)) - data, _ = entries.Get(info1.ID, "addressData") + data, _ = entries.Get(info1.ID, addressDataKey) ad = data.(addressData) phBookData2 := ad.recentConnectionTimes require.Equal(t, 2, len(phBookData2)) @@ -334,7 +334,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { // introduce a gap between the two requests so that only the first will be removed later when waited // simulate passing a unit of time - data2, _ := entries.Get(info2.ID, "addressData") + data2, _ := entries.Get(info2.ID, addressDataKey) require.NotNil(t, data2) ad2 := data2.(addressData) for rct := range ad2.recentConnectionTimes { @@ -350,7 +350,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) - data2, _ = entries.Get(info2.ID, "addressData") + data2, _ = entries.Get(info2.ID, addressDataKey) ad2 = data2.(addressData) phBookData = ad2.recentConnectionTimes // all three times should be queued @@ -360,7 +360,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { _, waitTime, provisionalTime = entries.GetConnectionWaitTime(addr2) require.Greater(t, int64(waitTime), int64(0)) // no element should be removed - data2, _ = entries.Get(info2.ID, "addressData") + data2, _ = entries.Get(info2.ID, addressDataKey) ad2 = data2.(addressData) phBookData2 = ad2.recentConnectionTimes require.Equal(t, phBookData[0], phBookData2[0]) @@ -377,7 +377,7 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { require.Equal(t, time.Duration(0), waitTime) require.Equal(t, true, entries.UpdateConnectionTime(addr2, provisionalTime)) // only one element should be removed, and one added - data2, _ = entries.Get(info2.ID, "addressData") + data2, _ = entries.Get(info2.ID, addressDataKey) ad2 = data2.(addressData) phBookData2 = ad2.recentConnectionTimes require.Equal(t, 3, len(phBookData2)) From 47bd821ff59e6f988f86fbd7bdd19513c0be42c7 Mon Sep 17 00:00:00 2001 From: shiqizng <80276844+shiqizng@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:15:10 -0400 Subject: [PATCH 13/16] Update network/p2p/peerstore/peerstore_test.go Co-authored-by: cce <51567+cce@users.noreply.github.com> --- network/p2p/peerstore/peerstore_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index f35c1d5696..6519b290ea 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -108,7 +108,7 @@ func testPhonebookAll(t *testing.T, set []string, ph Phonebook) { } } -func testPhonebookUniform(t *testing.T, set []string, ph Phonebook, getsize int) { +func testPhonebookUniform(t *testing.T, set []string, ph *PeerStore, getsize int) { uniformityTestLength := 250000 / len(set) expected := (uniformityTestLength * getsize) / len(set) counts := make(map[string]int) From b2e222c1f5ada36df96a19e9634511304fcbc3ab Mon Sep 17 00:00:00 2001 From: shiqizng <80276844+shiqizng@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:15:18 -0400 Subject: [PATCH 14/16] Update network/p2p/peerstore/peerstore_test.go Co-authored-by: cce <51567+cce@users.noreply.github.com> --- network/p2p/peerstore/peerstore_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index 6519b290ea..ffaa2c5630 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -80,7 +80,7 @@ func TestPeerstore(t *testing.T) { } -func testPhonebookAll(t *testing.T, set []string, ph Phonebook) { +func testPhonebookAll(t *testing.T, set []string, ph *PeerStore) { actual := ph.GetAddresses(len(set), PhoneBookEntryRelayRole) for _, got := range actual { ok := false From 7693bbb6051e283661ff638aaef13f5d293feef5 Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Thu, 31 Aug 2023 15:18:03 -0400 Subject: [PATCH 15/16] remove duplicate definition --- network/p2p/peerstore/peerstore.go | 41 ------------------------- network/p2p/peerstore/peerstore_test.go | 11 ++++++- 2 files changed, 10 insertions(+), 42 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 2ed2beaf5e..46e0da347a 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -32,50 +32,9 @@ import ( // of how many addresses the phonebook actually has. ( with the retry-after logic applied ) const getAllAddresses = math.MaxInt32 -// PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. -// currently, we have two roles : relay role and archiver role, which are mutually exclusive. -// //msgp:ignore PhoneBookEntryRoles type PhoneBookEntryRoles int -// PhoneBookEntryRelayRole used for all the relays that are provided either via the algobootstrap SRV record -// or via a configuration file. -const PhoneBookEntryRelayRole = 1 - -// PhoneBookEntryArchiverRole used for all the archivers that are provided via the archive SRV record. -const PhoneBookEntryArchiverRole = 2 - -// Phonebook stores or looks up addresses of nodes we might contact -type Phonebook interface { - // GetAddresses(N) returns up to N addresses, but may return fewer - GetAddresses(n int, role PhoneBookEntryRoles) []string - - // UpdateRetryAfter updates the retry-after field for the entries matching the given address - UpdateRetryAfter(addr string, retryAfter time.Time) - - // GetConnectionWaitTime will calculate and return the wait - // time to prevent exceeding connectionsRateLimitingCount. - // The connection should be established when the waitTime is 0. - // It will register a provisional next connection time when the waitTime is 0. - // The provisional time should be updated after the connection with UpdateConnectionTime - GetConnectionWaitTime(addr string) (addrInPhonebook bool, - waitTime time.Duration, provisionalTime time.Time) - - // UpdateConnectionTime will update the provisional connection time. - // Returns true of the addr was in the phonebook - UpdateConnectionTime(addr string, provisionalTime time.Time) bool - - // ReplacePeerList merges a set of addresses with that passed in for networkName - // new entries in dnsAddresses are being added - // existing items that aren't included in dnsAddresses are being removed - // matching entries don't change - ReplacePeerList(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) - - // AddPersistentPeers stores addresses of peers which are persistent. - // i.e. they won't be replaced by ReplacePeerList calls - AddPersistentPeers(dnsAddresses []string, networkName string, role PhoneBookEntryRoles) -} - const addressDataKey string = "addressData" // PeerStore implements Peerstore and CertifiedAddrBook. diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index ffaa2c5630..7338e6beb6 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -30,6 +30,16 @@ import ( "github.com/stretchr/testify/require" ) +// PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. +// currently, we have two roles : relay role and archiver role, which are mutually exclusive. + +// PhoneBookEntryRelayRole used for all the relays that are provided either via the algobootstrap SRV record +// or via a configuration file. +const PhoneBookEntryRelayRole = 1 + +// PhoneBookEntryArchiverRole used for all the archivers that are provided via the archive SRV record. +const PhoneBookEntryArchiverRole = 2 + func TestPeerstore(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() @@ -366,7 +376,6 @@ func TestWaitAndAddConnectionTimeLongtWindow(t *testing.T) { require.Equal(t, phBookData[0], phBookData2[0]) require.Equal(t, phBookData[1], phBookData2[1]) require.Equal(t, phBookData[2], phBookData2[2]) - // simulate passing of the waitTime duration for rct := range ad2.recentConnectionTimes { ad2.recentConnectionTimes[rct] = ad2.recentConnectionTimes[rct].Add(-1 * waitTime) From f77fa12fb8af3198af9cdfb5e11e590beea3e80c Mon Sep 17 00:00:00 2001 From: "shiqi.zheng@algorand.com" Date: Thu, 31 Aug 2023 15:53:30 -0400 Subject: [PATCH 16/16] fix lint --- network/p2p/peerstore/peerstore.go | 3 +++ network/p2p/peerstore/peerstore_test.go | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/network/p2p/peerstore/peerstore.go b/network/p2p/peerstore/peerstore.go index 46e0da347a..63a88966ff 100644 --- a/network/p2p/peerstore/peerstore.go +++ b/network/p2p/peerstore/peerstore.go @@ -32,6 +32,9 @@ import ( // of how many addresses the phonebook actually has. ( with the retry-after logic applied ) const getAllAddresses = math.MaxInt32 +// PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. +// currently, we have two roles : relay role and archiver role, which are mutually exclusive. +// //msgp:ignore PhoneBookEntryRoles type PhoneBookEntryRoles int diff --git a/network/p2p/peerstore/peerstore_test.go b/network/p2p/peerstore/peerstore_test.go index 7338e6beb6..4263564c34 100644 --- a/network/p2p/peerstore/peerstore_test.go +++ b/network/p2p/peerstore/peerstore_test.go @@ -30,9 +30,6 @@ import ( "github.com/stretchr/testify/require" ) -// PhoneBookEntryRoles defines the roles that a single entry on the phonebook can take. -// currently, we have two roles : relay role and archiver role, which are mutually exclusive. - // PhoneBookEntryRelayRole used for all the relays that are provided either via the algobootstrap SRV record // or via a configuration file. const PhoneBookEntryRelayRole = 1