feat: initial node scoring support
This commit is contained in:
parent
67be38e6c9
commit
eefbfa06d0
|
@ -1,6 +1,9 @@
|
||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import "crypto/rand"
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
func GenerateChallenge() []byte {
|
func GenerateChallenge() []byte {
|
||||||
challenge := make([]byte, 32)
|
challenge := make([]byte, 32)
|
||||||
|
@ -11,3 +14,15 @@ func GenerateChallenge() []byte {
|
||||||
|
|
||||||
return challenge
|
return challenge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CalculateNodeScore(goodResponses, badResponses int) float64 {
|
||||||
|
totalVotes := goodResponses + badResponses
|
||||||
|
if totalVotes == 0 {
|
||||||
|
return 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
average := float64(goodResponses) / float64(totalVotes)
|
||||||
|
score := average - (average-0.5)*math.Pow(2, -math.Log(float64(totalVotes+1)))
|
||||||
|
|
||||||
|
return score
|
||||||
|
}
|
||||||
|
|
|
@ -13,10 +13,13 @@ import (
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*P2P)(nil)
|
var _ Service = (*P2P)(nil)
|
||||||
|
var _ msgpack.CustomEncoder = (*nodeVotes)(nil)
|
||||||
|
var _ msgpack.CustomDecoder = (*nodeVotes)(nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errUnsupportedProtocol = errors.New("unsupported protocol")
|
errUnsupportedProtocol = errors.New("unsupported protocol")
|
||||||
|
@ -37,6 +40,42 @@ type P2P struct {
|
||||||
peers *structs.Map
|
peers *structs.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nodeVotes struct {
|
||||||
|
good int
|
||||||
|
bad int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n nodeVotes) EncodeMsgpack(enc *msgpack.Encoder) error {
|
||||||
|
err := enc.EncodeInt(int64(n.good))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = enc.EncodeInt(int64(n.bad))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *nodeVotes) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||||
|
good, err := dec.DecodeInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bad, err := dec.DecodeInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
n.good = good
|
||||||
|
n.bad = bad
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewP2P(node *libs5_go.Node) *P2P {
|
func NewP2P(node *libs5_go.Node) *P2P {
|
||||||
service := &P2P{
|
service := &P2P{
|
||||||
logger: node.Logger(),
|
logger: node.Logger(),
|
||||||
|
@ -246,7 +285,7 @@ func (p *P2P) onNewPeerListen(peer *net.Peer, verifyId bool) {
|
||||||
handler, ok := protocol.GetMessageType(imsg.GetKind())
|
handler, ok := protocol.GetMessageType(imsg.GetKind())
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
|
imsg.SetOriginal(message)
|
||||||
handler.SetIncomingMessage(imsg)
|
handler.SetIncomingMessage(imsg)
|
||||||
|
|
||||||
err := msgpack.Unmarshal(imsg.Data(), handler)
|
err := msgpack.Unmarshal(imsg.Data(), handler)
|
||||||
|
@ -265,4 +304,54 @@ func (p *P2P) onNewPeerListen(peer *net.Peer, verifyId bool) {
|
||||||
OnError: &onError,
|
OnError: &onError,
|
||||||
Logger: p.logger,
|
Logger: p.logger,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *P2P) readNodeScore(nodeId *encoding.NodeId) (nodeVotes, error) {
|
||||||
|
node := p.nodesBucket.Get(nodeId.Raw())
|
||||||
|
if node == nil {
|
||||||
|
return nodeVotes{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var score nodeVotes
|
||||||
|
err := msgpack.Unmarshal(node, &score)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return score, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *P2P) getNodeScore(nodeId *encoding.NodeId) (float64, error) {
|
||||||
|
if nodeId.Equals(p.localNodeID) {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
score, err := p.readNodeScore(nodeId)
|
||||||
|
if err != nil {
|
||||||
|
return 0.5, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return protocol.CalculateNodeScore(score.good, score.bad), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
func (p *P2P) SortNodesByScore(nodes []*encoding.NodeId) ([]*encoding.NodeId, error) {
|
||||||
|
scores := make(map[encoding.NodeIdCode]float64)
|
||||||
|
var errOccurred error
|
||||||
|
|
||||||
|
for _, nodeId := range nodes {
|
||||||
|
score, err := p.getNodeScore(nodeId)
|
||||||
|
if err != nil {
|
||||||
|
errOccurred = err
|
||||||
|
scores[nodeId.HashCode()] = 0 // You may choose a different default value for error cases
|
||||||
|
} else {
|
||||||
|
scores[nodeId.HashCode()] = score
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(nodes, func(i, j int) bool {
|
||||||
|
return scores[nodes[i].HashCode()] > scores[nodes[j].HashCode()]
|
||||||
|
})
|
||||||
|
|
||||||
|
return nodes, errOccurred
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue