-
Notifications
You must be signed in to change notification settings - Fork 8
feat(SPV-742): add peer manager #247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
arkadiuszos4chain
wants to merge
35
commits into
main
Choose a base branch
from
feat-742-peer-manager
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
8c1d575
feat(SPV-742): improve peer logs
arkadiuszos4chain c222d04
feat(SPV-742): make server responsible for peers
arkadiuszos4chain d8f6b67
feat(SPV-742): make multiple outbound connection
arkadiuszos4chain 3118c13
feat(SPV-742): add address book and store active peer addresses there
arkadiuszos4chain c2a5e82
feat(SPV-742): ask peers for known addresses on connection
arkadiuszos4chain 6d495d1
feat(SPV-742): ban peer/addresse on error (naive 24h ban)
arkadiuszos4chain 45919ea
feat(SPV-742): observe active outbound connections and keep them at dβ¦
arkadiuszos4chain 2fee765
feat(SPV-742): handle incoming connections
arkadiuszos4chain 8f11329
feat(SPV-742): accept peers from local network
arkadiuszos4chain a2e3723
feat(SPV-742): fix address book
arkadiuszos4chain 18c04d8
feat(SPV-742): add unit tests
arkadiuszos4chain adb4dec
feat(SPV-742): chnage DefaultPort type to uint16
arkadiuszos4chain 9b214c4
feat(SPV-742): fix linter errors
arkadiuszos4chain 5f5d06f
feat(SPV-742): fix linter errors
arkadiuszos4chain c2ec406
feat(SPV-742): fix linter errors
arkadiuszos4chain 41c272a
feat(SPV-742): fix linter errors
arkadiuszos4chain 7bab33f
feat(SPV-742): fix linter errors
arkadiuszos4chain 4be1d5e
feat(SPV-742): adjust to review; add comments; minor server refactoriβ¦
arkadiuszos4chain d53cddc
feat(SPV-742): remove comments
arkadiuszos4chain a2b499c
feat(SPV-742): remove comments
arkadiuszos4chain 66cc4e1
feat(SPV-742): remove comments
arkadiuszos4chain dc5d944
feat(SPV-742): fix error handling on server start
arkadiuszos4chain 279a15c
feat(SPV-742): fix deadlock when disconnect peer
arkadiuszos4chain a560d91
feat(SPV-742): revert withCancelHandle() for clarity
arkadiuszos4chain 0439f2f
feat(SPV-742): fix linter
arkadiuszos4chain be18961
feat(SPV-742): adjust to some comments
arkadiuszos4chain ff09468
feat(SPV-742): adjust to some comments
arkadiuszos4chain 4a7dea9
feat(SPV-742): adjust comments- replace log helper funcitons with newβ¦
arkadiuszos4chain 558038c
feat(SPV-742): adjust comments- remove unnecessary peer address string
arkadiuszos4chain bb1004c
feat(SPV-742): adjust comments- improve peer collection implementation
arkadiuszos4chain 25f2fbb
feat(SPV-742): adjust comments- move network to wire package; reimpleβ¦
arkadiuszos4chain c28cbec
feat(SPV-742): fix linter
arkadiuszos4chain 8089afc
feat(SPV-742): adjust comments- filter seed address
arkadiuszos4chain 0b0acf0
feat(SPV-742): adjust comments- use only ONE peer to sync with chain,β¦
arkadiuszos4chain d0f50bb
feat(SPV-742): fix linter
arkadiuszos4chain File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,165 @@ | ||||||
package network | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
"math/rand" | ||||||
"sync" | ||||||
"time" | ||||||
|
||||||
"github.com/bitcoin-sv/block-headers-service/internal/wire" | ||||||
) | ||||||
|
||||||
type addressBucketType string | ||||||
|
||||||
const ( | ||||||
freeBucket addressBucketType = "free" | ||||||
usedBucket addressBucketType = "used" | ||||||
bannedBucket addressBucketType = "banned" | ||||||
) | ||||||
|
||||||
arkadiuszos4chain marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
// AddressBook represents a collection of known network addresses. | ||||||
type AddressBook struct { | ||||||
banDuration time.Duration | ||||||
addrs map[addressBucketType]*addrBucket | ||||||
mu sync.Mutex | ||||||
addrFitlerFn func(*wire.NetAddress) bool | ||||||
} | ||||||
|
||||||
// NewAddressBook creates and initializes a new AddressBook instance. | ||||||
func NewAddressBook(banDuration time.Duration, acceptLocalAddresses bool) *AddressBook { | ||||||
// Set the address filter function based on whether local addresses are accepted | ||||||
addrFilterFn := wire.IsRoutable | ||||||
if acceptLocalAddresses { | ||||||
addrFilterFn = wire.IsRoutableWithLocal | ||||||
} | ||||||
|
||||||
const addressesInitCapacity = 500 | ||||||
const usedAddressesInitCapacity = 8 | ||||||
|
||||||
knownAddress := make(map[addressBucketType]*addrBucket, 3) | ||||||
knownAddress[freeBucket] = newAddrBucket(addressesInitCapacity) | ||||||
knownAddress[bannedBucket] = newAddrBucket(addressesInitCapacity) | ||||||
knownAddress[usedBucket] = newAddrBucket(usedAddressesInitCapacity) | ||||||
|
||||||
return &AddressBook{ | ||||||
banDuration: banDuration, | ||||||
addrFitlerFn: addrFilterFn, | ||||||
addrs: knownAddress, | ||||||
} | ||||||
} | ||||||
|
||||||
// UpsertAddrs updates or adds multiple addresses. | ||||||
func (a *AddressBook) UpsertAddrs(address []*wire.NetAddress) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
a.mu.Lock() | ||||||
defer a.mu.Unlock() | ||||||
|
||||||
for _, addr := range address { | ||||||
if !a.addrFitlerFn(addr) { | ||||||
continue | ||||||
} | ||||||
|
||||||
key, ka, _ := a.findAddr(addr) | ||||||
// If the address is not found, add it to the AddressBook. | ||||||
if ka == nil { | ||||||
a.addrs[freeBucket].add(key, &knownAddress{addr: addr}) | ||||||
} else if addr.Timestamp.After(ka.addr.Timestamp) { | ||||||
// Otherwise, update the timestamp if the new one is newer. | ||||||
ka.addr.Timestamp = addr.Timestamp | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
// MarkUsedAddr updates or adds a peer's address. | ||||||
func (a *AddressBook) MarkUsedAddr(pa *wire.NetAddress) { | ||||||
a.mu.Lock() | ||||||
defer a.mu.Unlock() | ||||||
|
||||||
key := addrKey(pa) | ||||||
// remove from free if exists | ||||||
a.addrs[freeBucket].rm(key) | ||||||
// add to used | ||||||
a.addrs[usedBucket].add(key, &knownAddress{addr: pa}) | ||||||
|
||||||
} | ||||||
|
||||||
// BanAddr bans a network address. Ignores address if doesn't exist in the AddressBook. | ||||||
func (a *AddressBook) BanAddr(addr *wire.NetAddress) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
a.mu.Lock() | ||||||
defer a.mu.Unlock() | ||||||
|
||||||
if key, ka, bucket := a.findAddr(addr); ka != nil { | ||||||
switch bucket { | ||||||
case freeBucket: | ||||||
a.ban(bucket, key, ka) | ||||||
case usedBucket: | ||||||
a.ban(bucket, key, ka) | ||||||
case bannedBucket: | ||||||
default: | ||||||
// Do nothing | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
// GetRandFreeAddr returns a randomly chosen unused network address. | ||||||
func (a *AddressBook) GetRandFreeAddr() *wire.NetAddress { | ||||||
a.mu.Lock() | ||||||
defer a.mu.Unlock() | ||||||
|
||||||
freeAddres := a.addrs[freeBucket].items | ||||||
fLen := len(freeAddres) | ||||||
if fLen == 0 { | ||||||
return nil | ||||||
} | ||||||
|
||||||
// #nosec G404 | ||||||
randIndx := rand.Intn(fLen) | ||||||
return freeAddres[randIndx].addr | ||||||
} | ||||||
|
||||||
func (a *AddressBook) findAddr(addr *wire.NetAddress) (key string, ka *knownAddress, bucket addressBucketType) { | ||||||
key = addrKey(addr) | ||||||
|
||||||
// search in free addresses | ||||||
if ka = a.addrs[freeBucket].find(key); ka != nil { | ||||||
bucket = freeBucket | ||||||
return | ||||||
} | ||||||
|
||||||
// search in used | ||||||
if ka = a.addrs[usedBucket].find(key); ka != nil { | ||||||
bucket = usedBucket | ||||||
return | ||||||
} | ||||||
|
||||||
// search in banned | ||||||
if ka = a.addrs[bannedBucket].find(key); ka != nil { | ||||||
bucket = bannedBucket | ||||||
return | ||||||
} | ||||||
|
||||||
return key, nil, "" | ||||||
} | ||||||
|
||||||
func (a *AddressBook) ban(bucket addressBucketType, key string, ka *knownAddress) { | ||||||
a.addrs[bucket].rm(key) | ||||||
a.addrs[bannedBucket].add(key, ka) | ||||||
go a.unban(key, ka) | ||||||
} | ||||||
|
||||||
func (a *AddressBook) unban(key string, ka *knownAddress) { | ||||||
time.Sleep(a.banDuration) | ||||||
|
||||||
a.mu.Lock() | ||||||
defer a.mu.Unlock() | ||||||
|
||||||
a.addrs[bannedBucket].rm(key) | ||||||
a.addrs[freeBucket].add(key, ka) | ||||||
} | ||||||
|
||||||
func addrKey(addr *wire.NetAddress) string { | ||||||
return fmt.Sprintf("%s:%d", addr.IP, addr.Port) | ||||||
} | ||||||
|
||||||
type knownAddress struct { | ||||||
addr *wire.NetAddress | ||||||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it a good practice to stay with error return when shutting down? Probably we can't do anything with that, but at least we have a message and we can possibly kill it manually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can see that neither implementation returns any error - so... why stay here with an error?