zcash: fix blacklist behavior

Previously, the blacklist would never be retried since we queued the
wrong list of addresses. New logic also drops peers from the blacklist
if they've been continuously retried without success for a while.
This commit is contained in:
George Tankersley 2020-06-01 13:33:18 -04:00
parent 716bdf4573
commit de1dc1644d
2 changed files with 38 additions and 4 deletions

View File

@ -123,8 +123,22 @@ func (bk *AddressBook) Blacklist(s PeerKey) {
}
}
// Redeem removes an address from the blacklist.
// Redeem removes an address from the blacklist and adds it to the peer list.
func (bk *AddressBook) Redeem(s PeerKey) {
bk.addrState.Lock()
if addr, ok := bk.blacklist[s]; ok {
delete(bk.blacklist, s)
addr.lastUpdate = time.Now()
bk.peers[s] = addr
}
bk.addrState.Unlock()
// Wake anyone who was waiting on us to receive an address.
bk.addrRecvCond.Broadcast()
}
// DropFromBlacklist removes an address from the blacklist.
func (bk *AddressBook) DropFromBlacklist(s PeerKey) {
bk.addrState.Lock()
defer bk.addrState.Unlock()
@ -179,6 +193,17 @@ func (bk *AddressBook) enqueueAddrs(addrQueue *chan *Address) {
}
}
// enqueueBlacklist puts all of our blacklisted peers into a channel.
func (bk *AddressBook) enqueueBlacklist(addrQueue *chan *Address) {
bk.addrState.RLock()
defer bk.addrState.RUnlock()
*addrQueue = make(chan *Address, len(bk.blacklist))
for _, v := range bk.blacklist {
*addrQueue <- v
}
}
// WaitForAddresses waits for n addresses to be received and their initial
// connection attempts to resolve. There is no escape if that does not happen -
// this is intended for test runners or goroutines with a timeout.

View File

@ -53,6 +53,9 @@ var (
// The amount of space we allocate to keep things moving smoothly.
incomingAddressBufferSize = 1024
// The amount of time a peer can spend on the blacklist before we forget about it entirely.
blacklistDropTime = 3 * 24 * time.Hour
)
// Seeder contains all of the state and configuration needed to request addresses from Zcash peers and present them to a DNS provider.
@ -443,7 +446,7 @@ func (s *Seeder) RetryBlacklist() {
var wg sync.WaitGroup
// XXX lil awkward to allocate a channel whose size we can't determine without a lock here
s.addrBook.enqueueAddrs(&blacklistQueue)
s.addrBook.enqueueBlacklist(&blacklistQueue)
for i := 0; i < crawlerGoroutineCount; i++ {
wg.Add(1)
@ -460,12 +463,18 @@ func (s *Seeder) RetryBlacklist() {
if err != nil {
// Connection failed. Peer remains blacklisted.
if time.Since(next.lastUpdate) > blacklistDropTime {
// If we've been retrying for a while, forget about this peer entirely.
// This would deadlock if enqueueBlacklist still held the RLock.
s.addrBook.DropFromBlacklist(next.asPeerKey())
}
continue
}
s.DisconnectPeer(next.asPeerKey())
// This would deadlock if enqueueAddrs still held the RLock.
// Remove the peer from the blacklist and add it back to the address book.
// This would deadlock if enqueueBlacklist still held the RLock.
s.addrBook.Redeem(next.asPeerKey())
}
wg.Done()
@ -515,5 +524,5 @@ func (s *Seeder) testBlacklist(pk PeerKey) {
// testRedeen adds a peer to the blacklist directly, for testing.
func (s *Seeder) testRedeem(pk PeerKey) {
s.addrBook.Redeem(pk)
s.addrBook.DropFromBlacklist(pk)
}