Skip to content
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

change network connect way #410

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type Configuration struct {
EncryptAlg string `json:"EncryptAlg"`
MaxLogSize int64 `json:"MaxLogSize"`
MaxTxInBlock int `json:"MaxTransactionInBlock"`
DefaultMaxPeers uint `json:"DefaultMaxPeers"`
GetAddrMax uint `json:"GetAddrMax"`
MaxOutboundCnt uint `json:"MaxOutboundCnt"`
}

type ConfigFile struct {
Expand Down
7 changes: 5 additions & 2 deletions net/message/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func (msg addrReq) Handle(node Noder) error {
// lock
var addrstr []NodeAddr
var count uint64
addrstr, count = node.LocalNode().GetNeighborAddrs()

addrstr = node.LocalNode().RandSelectAddresses()
count = uint64(len(addrstr))
buf, err := NewAddrs(addrstr, count)
if err != nil {
return err
Expand Down Expand Up @@ -180,7 +182,8 @@ func (msg addr) Handle(node Noder) error {
continue
}

go node.LocalNode().Connect(address)
//save the node address in address list
node.LocalNode().AddAddressToKnownAddress(v)
}
return nil
}
4 changes: 3 additions & 1 deletion net/message/verack.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ func (msg verACK) Handle(node Noder) error {
// Fixme, there is a race condition here,
// but it doesn't matter to access the invalid
// node which will trigger a warning
node.ReqNeighborList()
if node.LocalNode().NeedMoreAddresses() {
node.ReqNeighborList()
}
addr := node.GetAddr()
port := node.GetPort()
nodeAddr := addr + ":" + strconv.Itoa(int(port))
Expand Down
10 changes: 10 additions & 0 deletions net/message/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,16 @@ func (msg version) Handle(node Noder) error {
msg.P.Port, msg.P.Nonce, msg.P.Relay, msg.P.StartHeight)
localNode.AddNbrNode(node)

ip, _ := node.GetAddr16()
addr := NodeAddr{
Time: node.GetTime(),
Services: msg.P.Services,
IpAddr: ip,
Port: msg.P.Port,
ID: msg.P.Nonce,
}
localNode.AddAddressToKnownAddress(addr)

var buf []byte
if s == INIT {
node.SetState(HANDSHAKE)
Expand Down
34 changes: 31 additions & 3 deletions net/node/infoUpdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"DNA/common/config"
"DNA/common/log"
"DNA/core/ledger"
"DNA/events"
. "DNA/net/message"
. "DNA/net/protocol"
"math/rand"
Expand Down Expand Up @@ -135,7 +136,9 @@ func (node *node) ConnectSeeds() {
node.nbrNodes.Unlock()
if found {
if n.GetState() == ESTABLISH {
n.ReqNeighborList()
if node.LocalNode().NeedMoreAddresses() {
n.ReqNeighborList()
}
}
} else { //not found
go node.Connect(nodeAddr)
Expand All @@ -144,6 +147,22 @@ func (node *node) ConnectSeeds() {
}
}

func (node *node) ConnectNode() {
cntcount := node.nbrNodes.GetConnectionCnt()
if cntcount < node.GetMaxOutboundCnt() {
nbrAddr, _ := node.GetNeighborAddrs()
addrs := node.RandGetAddresses(nbrAddr)
for _, nodeAddr := range addrs {
addr := nodeAddr.IpAddr
port := nodeAddr.Port
var ip net.IP
ip = addr[:]
na := ip.To16().String() + ":" + strconv.Itoa(int(port))
go node.Connect(na)
}
}
}

func getNodeAddr(n *node) NodeAddr {
var addr NodeAddr
addr.IpAddr, _ = n.GetAddr16()
Expand Down Expand Up @@ -227,16 +246,25 @@ func (node *node) updateNodeInfo() {
//close(quit)
}

func (node *node) CheckConnCnt() {
//compare if connect count is larger than DefaultMaxPeers, disconnect one of the connection
if node.nbrNodes.GetConnectionCnt() > node.GetDefaultMaxPeers() {
disconnNode := node.RandGetANbr()
node.eventQueue.GetEvent("disconnect").Notify(events.EventNodeDisconnect, disconnNode)
}
}

func (node *node) updateConnection() {
t := time.NewTimer(time.Second * CONNMONITOR)
for {
select {
case <-t.C:
node.ConnectSeeds()
node.TryConnect()
//node.TryConnect()
node.ConnectNode()
node.CheckConnCnt()
t.Stop()
t.Reset(time.Second * CONNMONITOR)
}
}

}
266 changes: 266 additions & 0 deletions net/node/knowaddrlist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
package node

import (
"DNA/common/log"
. "DNA/net/protocol"
"math/rand"
"sync"
"time"
)

const (
// needAddressThreshold is the number of addresses under which the
// address manager will claim to need more addresses.
needAddressThreshold = 1000
// numMissingDays is the number of days before which we assume an
// address has vanished if we have not seen it announced in that long.
numMissingDays = 30
// numRetries is the number of tried without a single success before
// we assume an address is bad.
numRetries = 10
)

type KnownAddress struct {
srcAddr NodeAddr
lastattempt time.Time
lastDisconnect time.Time
attempts int
}

type KnownAddressList struct {
sync.RWMutex
List map[uint64]*KnownAddress
addrCount uint64
}

func (ka *KnownAddress) LastAttempt() time.Time {
return ka.lastattempt
}

func (ka *KnownAddress) increaseAttempts() {
ka.attempts++
}

func (ka *KnownAddress) updateLastAttempt() {
// set last tried time to now
ka.lastattempt = time.Now()
}

func (ka *KnownAddress) updateLastDisconnect() {
// set last disconnect time to now
ka.lastDisconnect = time.Now()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the upper two function signatures have opposite function body.


// chance returns the selection probability for a known address. The priority
// depends upon how recently the address has been seen, how recently it was last
// attempted and how often attempts to connect to it have failed.
func (ka *KnownAddress) chance() float64 {
now := time.Now()
lastAttempt := now.Sub(ka.lastattempt)

if lastAttempt < 0 {
lastAttempt = 0
}

c := 1.0

// Very recent attempts are less likely to be retried.
if lastAttempt < 10*time.Minute {
c *= 0.01
}

// Failed attempts deprioritise.
for i := ka.attempts; i > 0; i-- {
c /= 1.5
}

return c
}

// isBad returns true if the address in question has not been tried in the last
// minute and meets one of the following criteria:
// 1) Just tried in one minute
// 2) It hasn't been seen in over a month
// 3) It has failed at least ten times
// 4) It has failed ten times in the last week
// All addresses that meet these criteria are assumed to be worthless and not
// worth keeping hold of.
func (ka *KnownAddress) isBad() bool {
// just tried in one minute?
if ka.lastattempt.After(time.Now().Add(-1 * time.Minute)) {
return false
}

// Over a month old?
if ka.srcAddr.Time < (time.Now().Add(-1 * numMissingDays * time.Hour * 24)).UnixNano() {
return true
}

// Just disconnected in one minute?
if ka.lastDisconnect.After(time.Now().Add(-1 * time.Minute)) {
return true
}

// tried too many times?
if ka.attempts >= numRetries {
return true
}

return false
}

func (ka *KnownAddress) SaveAddr(na NodeAddr) {
ka.srcAddr.Time = na.Time
ka.srcAddr.Services = na.Services
ka.srcAddr.IpAddr = na.IpAddr
ka.srcAddr.Port = na.Port
ka.srcAddr.ID = na.ID
}

func (ka *KnownAddress) NetAddress() NodeAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use NodeAddr directly or type KnownAddress NodeAddr to avoid redundant code ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structure will add other members in next version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

return ka.srcAddr
}

func (ka *KnownAddress) GetID() uint64 {
return ka.srcAddr.ID
}

func (al *KnownAddressList) NeedMoreAddresses() bool {
al.Lock()
defer al.Unlock()

return al.addrCount < needAddressThreshold
}

func (al *KnownAddressList) AddressExisted(uid uint64) bool {
_, ok := al.List[uid]
return ok
}

func (al *KnownAddressList) UpdateLastDisconn(id uint64) {
ka := al.List[id]
ka.updateLastDisconnect()
}

func (al *KnownAddressList) AddAddressToKnownAddress(na NodeAddr) {
al.Lock()
defer al.Unlock()

ka := new(KnownAddress)
ka.SaveAddr(na)
if al.AddressExisted(ka.GetID()) {
log.Debug("Insert a existed addr\n")
} else {
al.List[ka.GetID()] = ka
al.addrCount++
}
}

func (al *KnownAddressList) DelAddressFromList(id uint64) bool {
al.Lock()
defer al.Unlock()

_, ok := al.List[id]
if ok == false {
return false
}
delete(al.List, id)
return true
}

func (al *KnownAddressList) GetAddressCnt() uint64 {
al.RLock()
defer al.RUnlock()
if al != nil {
return al.addrCount
}
return 0
}

func (al *KnownAddressList) init() {
al.List = make(map[uint64]*KnownAddress)
}

func isInNbrList(id uint64, nbrAddrs []NodeAddr) bool {
for _, na := range nbrAddrs {
if id == na.ID {
return true
}
}
return false
}

func (al *KnownAddressList) RandGetAddresses(nbrAddrs []NodeAddr) []NodeAddr {
al.RLock()
defer al.RUnlock()
var keys []uint64
for k := range al.List {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. missing lock here.
  2. maybe it is better to directly copy out the address instead of the key to avoid unnecessary existence check in the latter code.

isInNbr := isInNbrList(k, nbrAddrs)
isBad := al.List[k].isBad()
if isInNbr == false && isBad == false {
keys = append(keys, k)
}
}
addrLen := len(keys)
var i int
addrs := []NodeAddr{}
if MAXOUTBOUNDCNT-len(nbrAddrs) > addrLen {
for _, v := range keys {
ka, ok := al.List[v]
if !ok {
continue
}
addrs = append(addrs, ka.srcAddr)
}
} else {
order := rand.Perm(addrLen)
var count int
count = MAXOUTBOUNDCNT - len(nbrAddrs)
for i = 0; i < count; i++ {
for j, v := range keys {
if j == order[j] {
ka, ok := al.List[v]
if !ok {
continue
}
ka.increaseAttempts()
ka.updateLastAttempt()
addrs = append(addrs, ka.srcAddr)
keys = append(keys[:j], keys[j+1:]...)
break
}
}
}
}

return addrs
}

func (al *KnownAddressList) RandSelectAddresses() []NodeAddr {
al.RLock()
defer al.RUnlock()
var keys []uint64
addrs := []NodeAddr{}
for k := range al.List {
keys = append(keys, k)
}
addrLen := len(keys)

var count int
if MAXOUTBOUNDCNT > addrLen {
count = addrLen
} else {
count = MAXOUTBOUNDCNT
}
for i, v := range keys {
if i < count {
ka, ok := al.List[v]
if !ok {
continue
}
addrs = append(addrs, ka.srcAddr)
}
}

return addrs
}
Loading