dnsseed,zcash: occasionally retry blacklisted addresses
This commit is contained in:
parent
bba9f4436e
commit
e57eebd627
|
@ -1,6 +1,7 @@
|
||||||
package dnsseed
|
package dnsseed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
crypto_rand "crypto/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
@ -73,10 +74,18 @@ func setup(c *caddy.Controller) error {
|
||||||
// Start the update timer
|
// Start the update timer
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("Starting update timer. Will crawl every %.0f minutes.", updateInterval.Minutes())
|
log.Infof("Starting update timer. Will crawl every %.0f minutes.", updateInterval.Minutes())
|
||||||
|
randByte := []byte{0}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(updateInterval):
|
case <-time.After(updateInterval):
|
||||||
runCrawl(seeder)
|
runCrawl(seeder)
|
||||||
|
crypto_rand.Read(randByte[:])
|
||||||
|
if randByte[0] >= byte(192) {
|
||||||
|
// About 25% of the time, retry the blacklist.
|
||||||
|
// This stops us from losing peers forever due to
|
||||||
|
// temporary downtime.
|
||||||
|
seeder.RetryBlacklist()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -104,6 +104,7 @@ func (bk *AddressBook) Remove(s PeerKey) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Blacklist adds an address to the blacklist so we won't try to connect to it again.
|
||||||
func (bk *AddressBook) Blacklist(s PeerKey) {
|
func (bk *AddressBook) Blacklist(s PeerKey) {
|
||||||
bk.addrState.Lock()
|
bk.addrState.Lock()
|
||||||
defer bk.addrState.Unlock()
|
defer bk.addrState.Unlock()
|
||||||
|
@ -122,6 +123,16 @@ func (bk *AddressBook) Blacklist(s PeerKey) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redeem removes an address from the blacklist.
|
||||||
|
func (bk *AddressBook) Redeem(s PeerKey) {
|
||||||
|
bk.addrState.Lock()
|
||||||
|
defer bk.addrState.Unlock()
|
||||||
|
|
||||||
|
if _, ok := bk.blacklist[s]; ok {
|
||||||
|
delete(bk.blacklist, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Touch updates the last-seen timestamp if the peer is in the valid address book or does nothing if not.
|
// Touch updates the last-seen timestamp if the peer is in the valid address book or does nothing if not.
|
||||||
func (bk *AddressBook) Touch(s PeerKey) {
|
func (bk *AddressBook) Touch(s PeerKey) {
|
||||||
bk.addrState.Lock()
|
bk.addrState.Lock()
|
||||||
|
|
|
@ -426,6 +426,48 @@ func (s *Seeder) RefreshAddresses(disconnect bool) {
|
||||||
s.logger.Printf("RefreshAddresses() finished.")
|
s.logger.Printf("RefreshAddresses() finished.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RetryBlacklist checks if the addresses in our blacklist are usable again.
|
||||||
|
// If the trial connection succeeds, they're removed from the blacklist.
|
||||||
|
func (s *Seeder) RetryBlacklist() {
|
||||||
|
s.logger.Printf("Giving the blacklist another chance")
|
||||||
|
|
||||||
|
var blacklistQueue chan *Address
|
||||||
|
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)
|
||||||
|
|
||||||
|
for i := 0; i < crawlerGoroutineCount; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
for len(blacklistQueue) > 0 {
|
||||||
|
// Pull the next address off the queue
|
||||||
|
next := <-blacklistQueue
|
||||||
|
na := next.netaddr
|
||||||
|
|
||||||
|
ipString := na.IP.String()
|
||||||
|
portString := strconv.Itoa(int(na.Port))
|
||||||
|
|
||||||
|
err := s.Connect(ipString, portString)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Connection failed. Peer remains blacklisted.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.DisconnectPeer(next.asPeerKey())
|
||||||
|
|
||||||
|
// This would deadlock if enqueueAddrs still held the RLock.
|
||||||
|
s.addrBook.Redeem(next.asPeerKey())
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
s.logger.Printf("RetryBlacklist() finished.")
|
||||||
|
}
|
||||||
|
|
||||||
// WaitForAddresses waits for n addresses to be confirmed and available in the address book.
|
// WaitForAddresses waits for n addresses to be confirmed and available in the address book.
|
||||||
func (s *Seeder) WaitForAddresses(n int, timeout time.Duration) error {
|
func (s *Seeder) WaitForAddresses(n int, timeout time.Duration) error {
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
@ -462,3 +504,8 @@ func (s *Seeder) GetPeerCount() int {
|
||||||
func (s *Seeder) testBlacklist(pk PeerKey) {
|
func (s *Seeder) testBlacklist(pk PeerKey) {
|
||||||
s.addrBook.Blacklist(pk)
|
s.addrBook.Blacklist(pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testRedeen adds a peer to the blacklist directly, for testing.
|
||||||
|
func (s *Seeder) testRedeem(pk PeerKey) {
|
||||||
|
s.addrBook.Redeem(pk)
|
||||||
|
}
|
||||||
|
|
|
@ -231,4 +231,10 @@ func TestBlacklist(t *testing.T) {
|
||||||
if err != ErrBlacklistedPeer {
|
if err != ErrBlacklistedPeer {
|
||||||
t.Errorf("Blacklist did not prevent connection")
|
t.Errorf("Blacklist did not prevent connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regSeeder.testRedeem(PeerKey("127.0.0.1:12345"))
|
||||||
|
err = regSeeder.Connect("127.0.0.1", "12345")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Redeem didn't allow reconnecting")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue