2024-01-06 11:33:46 +00:00
package service
import (
"errors"
2024-01-07 15:37:42 +00:00
"fmt"
2024-01-06 11:33:46 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/ed25519"
"git.lumeweb.com/LumeWeb/libs5-go/encoding"
2024-01-07 08:57:46 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/interfaces"
2024-01-06 11:33:46 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/net"
"git.lumeweb.com/LumeWeb/libs5-go/protocol"
2024-01-07 10:12:43 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/protocol/base"
2024-01-07 14:07:37 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/protocol/signed"
2024-01-06 11:33:46 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/structs"
2024-01-09 11:58:03 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/types"
2024-01-06 14:46:01 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/utils"
2024-01-06 11:33:46 +00:00
"github.com/vmihailenco/msgpack/v5"
bolt "go.etcd.io/bbolt"
"go.uber.org/zap"
"net/url"
2024-01-06 15:54:03 +00:00
"sort"
2024-01-08 17:06:53 +00:00
"sync"
2024-01-06 11:33:46 +00:00
"time"
)
2024-01-07 08:57:46 +00:00
var _ interfaces . P2PService = ( * P2PImpl ) ( nil )
var _ interfaces . NodeVotes = ( * NodeVotesImpl ) ( nil )
2024-01-06 11:33:46 +00:00
var (
errUnsupportedProtocol = errors . New ( "unsupported protocol" )
errConnectionIdMissingNodeID = errors . New ( "connection id missing node id" )
)
const nodeBucketName = "nodes"
2024-01-07 08:57:46 +00:00
type P2PImpl struct {
2024-01-15 15:54:31 +00:00
logger * zap . Logger
nodeKeyPair * ed25519 . KeyPairEd25519
localNodeID * encoding . NodeId
networkID string
nodesBucket * bolt . Bucket
node interfaces . Node
inited bool
reconnectDelay structs . Map
peers structs . Map
peersPending structs . Map
selfConnectionUris [ ] * url . URL
outgoingPeerBlocklist structs . Map
incomingPeerBlockList structs . Map
incomingIPBlocklist structs . Map
outgoingPeerFailures structs . Map
maxOutgoingPeerFailures uint
2024-01-06 11:33:46 +00:00
}
2024-01-07 08:57:46 +00:00
func NewP2P ( node interfaces . Node ) * P2PImpl {
2024-01-12 20:10:24 +00:00
uri , err := url . Parse ( fmt . Sprintf ( "wss://%s:%d/s5/p2p" , node . Config ( ) . HTTP . API . Domain , node . Config ( ) . HTTP . API . Port ) )
2024-01-10 14:36:55 +00:00
if err != nil {
node . Logger ( ) . Fatal ( "failed to HTTP API URL Config" , zap . Error ( err ) )
}
2024-01-07 08:57:46 +00:00
service := & P2PImpl {
2024-01-15 15:54:31 +00:00
logger : node . Logger ( ) ,
nodeKeyPair : node . Config ( ) . KeyPair ,
networkID : node . Config ( ) . P2P . Network ,
node : node ,
inited : false ,
reconnectDelay : structs . NewMap ( ) ,
peers : structs . NewMap ( ) ,
peersPending : structs . NewMap ( ) ,
selfConnectionUris : [ ] * url . URL { uri } ,
outgoingPeerBlocklist : structs . NewMap ( ) ,
incomingPeerBlockList : structs . NewMap ( ) ,
incomingIPBlocklist : structs . NewMap ( ) ,
2024-01-15 15:58:03 +00:00
outgoingPeerFailures : structs . NewMap ( ) ,
2024-01-15 15:54:31 +00:00
maxOutgoingPeerFailures : node . Config ( ) . P2P . MaxOutgoingPeerFailures ,
2024-01-06 11:33:46 +00:00
}
return service
}
2024-01-10 14:36:55 +00:00
func ( p * P2PImpl ) SelfConnectionUris ( ) [ ] * url . URL {
return p . selfConnectionUris
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) Node ( ) interfaces . Node {
2024-01-06 11:33:46 +00:00
return p . node
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) Peers ( ) structs . Map {
2024-01-06 11:33:46 +00:00
return p . peers
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) Start ( ) error {
2024-01-06 11:33:46 +00:00
config := p . Node ( ) . Config ( )
if len ( config . P2P . Peers . Initial ) > 0 {
initialPeers := config . P2P . Peers . Initial
for _ , peer := range initialPeers {
u , err := url . Parse ( peer )
if err != nil {
return err
}
2024-01-10 12:42:04 +00:00
peer := peer
go func ( ) {
2024-01-15 15:54:31 +00:00
err := p . ConnectToNode ( [ ] * url . URL { u } , false , nil )
2024-01-10 12:42:04 +00:00
if err != nil {
p . logger . Error ( "failed to connect to initial peer" , zap . Error ( err ) , zap . String ( "peer" , peer ) )
}
} ( )
2024-01-06 11:33:46 +00:00
}
}
return nil
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) Stop ( ) error {
2024-01-06 11:33:46 +00:00
panic ( "implement me" )
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) Init ( ) error {
2024-01-06 11:33:46 +00:00
if p . inited {
return nil
}
p . localNodeID = encoding . NewNodeId ( p . nodeKeyPair . PublicKey ( ) )
2024-01-09 20:50:43 +00:00
err := utils . CreateBucket ( nodeBucketName , p . Node ( ) . Db ( ) )
2024-01-06 14:46:01 +00:00
2024-01-06 11:33:46 +00:00
if err != nil {
return err
}
2024-01-07 10:23:11 +00:00
p . inited = true
2024-01-06 11:33:46 +00:00
return nil
}
2024-01-15 15:54:31 +00:00
func ( p * P2PImpl ) ConnectToNode ( connectionUris [ ] * url . URL , retried bool , fromPeer net . Peer ) error {
2024-01-06 11:33:46 +00:00
if ! p . Node ( ) . IsStarted ( ) {
return nil
}
unsupported , _ := url . Parse ( "http://0.0.0.0" )
unsupported . Scheme = "unsupported"
var connectionUri * url . URL
for _ , uri := range connectionUris {
2024-01-07 10:28:05 +00:00
if uri . Scheme == "ws" || uri . Scheme == "wss" {
2024-01-06 11:33:46 +00:00
connectionUri = uri
break
}
}
if connectionUri == nil {
for _ , uri := range connectionUris {
2024-01-07 10:28:05 +00:00
if uri . Scheme == "tcp" {
2024-01-06 11:33:46 +00:00
connectionUri = uri
break
}
}
}
if connectionUri == nil {
connectionUri = unsupported
}
if connectionUri . Scheme == "unsupported" {
return errUnsupportedProtocol
}
scheme := connectionUri . Scheme
if connectionUri . User == nil {
return errConnectionIdMissingNodeID
}
username := connectionUri . User . Username ( )
id , err := encoding . DecodeNodeId ( username )
if err != nil {
return err
}
idString , err := id . ToString ( )
if err != nil {
return err
}
2024-01-09 15:42:21 +00:00
if p . peersPending . Contains ( idString ) || p . peers . Contains ( idString ) {
p . logger . Debug ( "already connected" , zap . String ( "node" , connectionUri . String ( ) ) )
return nil
}
2024-01-15 17:09:25 +00:00
if p . outgoingPeerBlocklist . Contains ( idString ) {
2024-01-15 15:54:31 +00:00
p . logger . Error ( "outgoing peer is on blocklist" , zap . String ( "node" , connectionUri . String ( ) ) )
2024-01-15 16:04:41 +00:00
2024-01-15 17:13:17 +00:00
var fromPeerId string
2024-01-15 16:04:41 +00:00
if fromPeer != nil {
2024-01-15 17:13:17 +00:00
if fromPeer . Id ( ) != nil {
fromPeerId , err = fromPeer . Id ( ) . ToString ( )
if err != nil {
return err
}
p . incomingPeerBlockList . Put ( fromPeerId , true )
2024-01-15 16:04:41 +00:00
}
fromPeerIP := fromPeer . GetIP ( )
p . incomingIPBlocklist . Put ( fromPeerIP , true )
err = fromPeer . End ( )
if err != nil {
return err
}
p . logger . Info ( "blocking peer for sending peer on blocklist" , zap . String ( "node" , connectionUri . String ( ) ) , zap . String ( "peer" , fromPeerId ) , zap . String ( "ip" , fromPeerIP ) )
}
2024-01-15 15:54:31 +00:00
return nil
}
2024-01-06 11:33:46 +00:00
reconnectDelay := p . reconnectDelay . GetInt ( idString )
if reconnectDelay == nil {
2024-01-07 10:31:24 +00:00
delay := 1
reconnectDelay = & delay
2024-01-06 11:33:46 +00:00
}
if id . Equals ( p . localNodeID ) {
return nil
}
p . logger . Debug ( "connect" , zap . String ( "node" , connectionUri . String ( ) ) )
socket , err := net . CreateTransportSocket ( scheme , connectionUri )
if err != nil {
if retried {
p . logger . Error ( "failed to connect, too many retries" , zap . String ( "node" , connectionUri . String ( ) ) , zap . Error ( err ) )
2024-01-15 15:54:31 +00:00
counter := uint ( 0 )
if p . outgoingPeerFailures . Contains ( idString ) {
tmp := * p . outgoingPeerFailures . GetInt ( idString )
counter = uint ( tmp )
}
counter ++
p . outgoingPeerFailures . Put ( idString , counter )
if counter >= p . maxOutgoingPeerFailures {
2024-01-15 17:13:17 +00:00
2024-01-15 16:38:38 +00:00
if fromPeer != nil {
2024-01-15 17:13:17 +00:00
var fromPeerId string
if fromPeer . Id ( ) != nil {
fromPeerId , err = fromPeer . Id ( ) . ToString ( )
if err != nil {
return err
}
p . incomingPeerBlockList . Put ( fromPeerId , true )
2024-01-15 16:38:38 +00:00
}
2024-01-15 17:13:17 +00:00
2024-01-15 16:45:25 +00:00
fromPeerIP := fromPeer . GetIP ( )
p . incomingIPBlocklist . Put ( fromPeerIP , true )
2024-01-15 16:38:38 +00:00
err = fromPeer . End ( )
if err != nil {
return err
}
2024-01-15 16:45:25 +00:00
p . logger . Info ( "blocking peer for sending peer on blocklist" , zap . String ( "node" , connectionUri . String ( ) ) , zap . String ( "peer" , fromPeerId ) , zap . String ( "ip" , fromPeerIP ) )
2024-01-15 15:54:31 +00:00
}
2024-01-15 16:38:38 +00:00
p . outgoingPeerBlocklist . Put ( idString , true )
2024-01-15 16:45:25 +00:00
p . logger . Info ( "blocking peer for too many failures" , zap . String ( "node" , connectionUri . String ( ) ) )
2024-01-15 15:54:31 +00:00
}
2024-01-06 11:33:46 +00:00
return nil
}
retried = true
p . logger . Error ( "failed to connect" , zap . String ( "node" , connectionUri . String ( ) ) , zap . Error ( err ) )
2024-01-08 15:51:38 +00:00
delay := p . reconnectDelay . GetInt ( idString )
if delay == nil {
tmp := 1
delay = & tmp
}
delayDeref := * delay
p . reconnectDelay . PutInt ( idString , delayDeref * 2 )
2024-01-06 11:33:46 +00:00
2024-01-08 15:51:38 +00:00
time . Sleep ( time . Duration ( delayDeref ) * time . Second )
2024-01-06 11:33:46 +00:00
2024-01-15 15:54:31 +00:00
return p . ConnectToNode ( connectionUris , retried , fromPeer )
}
if p . outgoingPeerFailures . Contains ( idString ) {
p . outgoingPeerFailures . Remove ( idString )
2024-01-06 11:33:46 +00:00
}
peer , err := net . CreateTransportPeer ( scheme , & net . TransportPeerConfig {
Socket : socket ,
Uris : [ ] * url . URL { connectionUri } ,
} )
if err != nil {
return err
}
2024-01-07 11:35:41 +00:00
peer . SetId ( id )
2024-01-09 13:39:52 +00:00
2024-01-09 14:11:36 +00:00
p . Node ( ) . ConnectionTracker ( ) . Add ( 1 )
2024-01-09 15:42:21 +00:00
peerId , err := peer . Id ( ) . ToString ( )
if err != nil {
return err
}
p . peersPending . Put ( peerId , peer )
2024-01-09 13:39:52 +00:00
go func ( ) {
err := p . OnNewPeer ( peer , true )
if err != nil {
2024-01-09 14:11:36 +00:00
p . logger . Error ( "peer error" , zap . Error ( err ) )
2024-01-09 13:39:52 +00:00
}
2024-01-09 14:11:36 +00:00
p . Node ( ) . ConnectionTracker ( ) . Done ( )
2024-01-09 13:39:52 +00:00
} ( )
2024-01-09 14:11:36 +00:00
2024-01-09 13:39:52 +00:00
return nil
2024-01-06 11:33:46 +00:00
}
2024-01-07 11:35:41 +00:00
func ( p * P2PImpl ) OnNewPeer ( peer net . Peer , verifyId bool ) error {
2024-01-08 17:06:53 +00:00
var wg sync . WaitGroup
2024-01-06 11:33:46 +00:00
2024-01-10 16:00:01 +00:00
var pid string
if peer . Id ( ) != nil {
pid , _ = peer . Id ( ) . ToString ( )
} else {
pid = "unknown"
}
2024-01-15 15:54:31 +00:00
pip := peer . GetIP ( )
if p . incomingIPBlocklist . Contains ( pid ) {
p . logger . Error ( "peer is on identity blocklist" , zap . String ( "peer" , pid ) )
err := peer . End ( )
if err != nil {
return err
}
return nil
}
if p . incomingPeerBlockList . Contains ( pip ) {
p . logger . Debug ( "peer is on ip blocklist" , zap . String ( "peer" , pid ) , zap . String ( "ip" , pip ) )
err := peer . End ( )
if err != nil {
return err
}
return nil
}
2024-01-09 14:11:36 +00:00
p . logger . Debug ( "OnNewPeer started" , zap . String ( "peer" , pid ) )
2024-01-08 17:06:53 +00:00
challenge := protocol . GenerateChallenge ( )
2024-01-07 11:35:41 +00:00
peer . SetChallenge ( challenge )
2024-01-06 11:33:46 +00:00
2024-01-08 17:06:53 +00:00
wg . Add ( 1 )
go func ( ) {
defer wg . Done ( )
p . OnNewPeerListen ( peer , verifyId )
} ( )
2024-01-06 11:33:46 +00:00
2024-01-08 17:07:19 +00:00
handshakeOpenMsg , err := msgpack . Marshal ( protocol . NewHandshakeOpen ( challenge , p . networkID ) )
2024-01-06 11:33:46 +00:00
if err != nil {
return err
}
2024-01-07 11:35:41 +00:00
err = peer . SendMessage ( handshakeOpenMsg )
2024-01-06 11:33:46 +00:00
if err != nil {
return err
}
2024-01-09 15:42:21 +00:00
p . logger . Debug ( "OnNewPeer sent handshake" , zap . String ( "peer" , pid ) )
2024-01-08 17:06:53 +00:00
2024-01-09 15:42:21 +00:00
p . logger . Debug ( "OnNewPeer before Wait" , zap . String ( "peer" , pid ) )
2024-01-08 17:06:53 +00:00
wg . Wait ( ) // Wait for OnNewPeerListen goroutine to finish
2024-01-09 15:42:21 +00:00
p . logger . Debug ( "OnNewPeer ended" , zap . String ( "peer" , pid ) )
2024-01-06 11:33:46 +00:00
return nil
}
2024-01-07 11:35:41 +00:00
func ( p * P2PImpl ) OnNewPeerListen ( peer net . Peer , verifyId bool ) {
2024-01-10 16:00:01 +00:00
var pid string
if peer . Id ( ) != nil {
pid , _ = peer . Id ( ) . ToString ( )
} else {
pid = "unknown"
2024-01-09 15:42:21 +00:00
}
2024-01-10 16:00:01 +00:00
2024-01-07 11:33:32 +00:00
onDone := net . CloseCallback ( func ( ) {
2024-01-10 16:00:01 +00:00
if peer . Id ( ) != nil {
pid , err := peer . Id ( ) . ToString ( )
if err != nil {
p . logger . Error ( "failed to get peer id" , zap . Error ( err ) )
return
}
// Handle closure of the connection
if p . peers . Contains ( pid ) {
p . peers . Remove ( pid )
}
if p . peersPending . Contains ( pid ) {
p . peersPending . Remove ( pid )
}
2024-01-09 15:42:21 +00:00
}
2024-01-06 11:33:46 +00:00
} )
onError := net . ErrorCallback ( func ( args ... interface { } ) {
p . logger . Error ( "peer error" , zap . Any ( "args" , args ) )
} )
2024-01-07 11:35:41 +00:00
peer . ListenForMessages ( func ( message [ ] byte ) error {
2024-01-07 10:12:43 +00:00
imsg := base . NewIncomingMessageUnknown ( )
2024-01-06 11:33:46 +00:00
err := msgpack . Unmarshal ( message , imsg )
2024-01-10 16:00:01 +00:00
p . logger . Debug ( "ListenForMessages" , zap . Any ( "message" , imsg ) , zap . String ( "peer" , pid ) )
2024-01-06 11:33:46 +00:00
if err != nil {
return err
}
2024-01-09 17:50:28 +00:00
handler , ok := protocol . GetMessageType ( imsg . Kind ( ) )
2024-01-06 11:33:46 +00:00
if ok {
2024-01-13 16:22:01 +00:00
if handler . RequiresHandshake ( ) && ! peer . IsHandshakeDone ( ) {
p . logger . Debug ( "Peer is not handshake done, ignoring message" , zap . Any ( "type" , types . ProtocolMethodMap [ types . ProtocolMethod ( imsg . Kind ( ) ) ] ) )
return nil
}
2024-01-06 15:54:03 +00:00
imsg . SetOriginal ( message )
2024-01-06 11:33:46 +00:00
handler . SetIncomingMessage ( imsg )
2024-01-07 15:37:42 +00:00
handler . SetSelf ( handler )
2024-01-06 11:33:46 +00:00
err := msgpack . Unmarshal ( imsg . Data ( ) , handler )
if err != nil {
return err
}
err = handler . HandleMessage ( p . node , peer , verifyId )
if err != nil {
return err
}
}
return nil
} , net . ListenerOptions {
2024-01-07 11:33:32 +00:00
OnClose : & onDone ,
2024-01-06 11:33:46 +00:00
OnError : & onError ,
Logger : p . logger ,
} )
2024-01-06 15:54:03 +00:00
}
2024-01-09 11:55:37 +00:00
func ( p * P2PImpl ) readNodeVotes ( nodeId * encoding . NodeId ) ( interfaces . NodeVotes , error ) {
2024-01-09 20:49:23 +00:00
var value [ ] byte
var found bool
err := p . node . Db ( ) . View ( func ( tx * bolt . Tx ) error {
b := tx . Bucket ( [ ] byte ( nodeBucketName ) )
if b == nil {
return fmt . Errorf ( "Bucket %s not found" , nodeBucketName )
}
value = b . Get ( nodeId . Raw ( ) )
if value == nil {
return nil
}
found = true
return nil
} )
if err != nil {
return nil , err
}
if ! found {
2024-01-07 09:03:36 +00:00
return NewNodeVotes ( ) , nil
2024-01-06 15:54:03 +00:00
}
2024-01-07 08:57:46 +00:00
var score interfaces . NodeVotes
2024-01-09 20:49:23 +00:00
err = msgpack . Unmarshal ( value , & score )
2024-01-06 15:54:03 +00:00
if err != nil {
2024-01-09 11:57:26 +00:00
return nil , err
2024-01-06 15:54:03 +00:00
}
return score , nil
}
2024-01-09 20:49:23 +00:00
func ( p * P2PImpl ) saveNodeVotes ( nodeId * encoding . NodeId , votes interfaces . NodeVotes ) error {
// Marshal the votes into data
2024-01-09 11:58:03 +00:00
data , err := msgpack . Marshal ( votes )
if err != nil {
2024-01-09 20:49:23 +00:00
return err
2024-01-09 11:58:03 +00:00
}
2024-01-09 20:49:23 +00:00
// Use a transaction to save the data
err = p . node . Db ( ) . Update ( func ( tx * bolt . Tx ) error {
// Get or create the bucket
b := tx . Bucket ( [ ] byte ( nodeBucketName ) )
// Put the data into the bucket
return b . Put ( nodeId . Raw ( ) , data )
} )
2024-01-09 11:58:03 +00:00
2024-01-09 20:49:23 +00:00
return err
2024-01-09 11:58:03 +00:00
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) GetNodeScore ( nodeId * encoding . NodeId ) ( float64 , error ) {
2024-01-06 15:54:03 +00:00
if nodeId . Equals ( p . localNodeID ) {
return 1 , nil
}
2024-01-09 11:55:37 +00:00
score , err := p . readNodeVotes ( nodeId )
2024-01-06 15:54:03 +00:00
if err != nil {
return 0.5 , err
}
2024-01-07 08:57:46 +00:00
return protocol . CalculateNodeScore ( score . Good ( ) , score . Bad ( ) ) , nil
2024-01-06 15:54:03 +00:00
}
2024-01-07 08:57:46 +00:00
func ( p * P2PImpl ) SortNodesByScore ( nodes [ ] * encoding . NodeId ) ( [ ] * encoding . NodeId , error ) {
2024-01-06 15:54:03 +00:00
scores := make ( map [ encoding . NodeIdCode ] float64 )
var errOccurred error
for _ , nodeId := range nodes {
2024-01-07 08:57:46 +00:00
score , err := p . GetNodeScore ( nodeId )
2024-01-06 15:54:03 +00:00
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
2024-01-06 11:33:46 +00:00
}
2024-01-07 14:07:37 +00:00
func ( p * P2PImpl ) SignMessageSimple ( message [ ] byte ) ( [ ] byte , error ) {
signedMessage := signed . NewSignedMessageRequest ( message )
signedMessage . SetNodeId ( p . localNodeID )
err := signedMessage . Sign ( p . Node ( ) )
if err != nil {
return nil , err
}
result , err := msgpack . Marshal ( signedMessage )
if err != nil {
return nil , err
}
return result , nil
}
2024-01-08 15:51:38 +00:00
func ( p * P2PImpl ) AddPeer ( peer net . Peer ) error {
peerId , err := peer . Id ( ) . ToString ( )
if err != nil {
return err
}
p . peers . Put ( peerId , peer )
p . reconnectDelay . Put ( peerId , 1 )
2024-01-09 15:42:21 +00:00
if p . peersPending . Contains ( peerId ) {
p . peersPending . Remove ( peerId )
}
2024-01-08 15:51:38 +00:00
return nil
}
func ( p * P2PImpl ) SendPublicPeersToPeer ( peer net . Peer , peersToSend [ ] net . Peer ) error {
announceRequest := signed . NewAnnounceRequest ( peer , peersToSend )
message , err := msgpack . Marshal ( announceRequest )
if err != nil {
return err
}
signedMessage , err := p . SignMessageSimple ( message )
if err != nil {
return err
}
err = peer . SendMessage ( signedMessage )
return nil
}
2024-01-09 11:59:12 +00:00
func ( p * P2PImpl ) SendHashRequest ( hash * encoding . Multihash , kinds [ ] types . StorageLocationType ) error {
hashRequest := protocol . NewHashRequest ( hash , kinds )
message , err := msgpack . Marshal ( hashRequest )
if err != nil {
return err
}
for _ , peer := range p . peers . Values ( ) {
peerValue , ok := peer . ( net . Peer )
if ! ok {
p . node . Logger ( ) . Error ( "failed to cast peer to net.Peer" )
continue
}
err = peerValue . SendMessage ( message )
}
return nil
}
func ( p * P2PImpl ) UpVote ( nodeId * encoding . NodeId ) error {
err := p . vote ( nodeId , true )
if err != nil {
return err
}
return nil
}
func ( p * P2PImpl ) DownVote ( nodeId * encoding . NodeId ) error {
err := p . vote ( nodeId , false )
if err != nil {
return err
}
return nil
}
func ( p * P2PImpl ) vote ( nodeId * encoding . NodeId , upvote bool ) error {
votes , err := p . readNodeVotes ( nodeId )
if err != nil {
return err
}
if upvote {
votes . Upvote ( )
} else {
votes . Downvote ( )
}
2024-01-09 20:51:02 +00:00
err = p . saveNodeVotes ( nodeId , votes )
if err != nil {
return err
}
2024-01-09 11:59:12 +00:00
return nil
}
2024-01-09 15:42:21 +00:00
func ( p * P2PImpl ) NodeId ( ) * encoding . NodeId {
return p . localNodeID
}