2024-01-06 11:33:46 +00:00
package service
import (
2024-01-29 04:39:40 +00:00
"bytes"
"context"
2024-01-24 07:53:56 +00:00
ed25519p "crypto/ed25519"
2024-01-06 11:33:46 +00:00
"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"
"git.lumeweb.com/LumeWeb/libs5-go/net"
2024-01-29 04:59:43 +00:00
_node "git.lumeweb.com/LumeWeb/libs5-go/node"
2024-01-06 11:33:46 +00:00
"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-29 04:59:43 +00:00
"git.lumeweb.com/LumeWeb/libs5-go/storage"
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-29 04:59:43 +00:00
var _ Service = ( * P2PService ) ( 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-29 04:59:43 +00:00
type P2PService struct {
2024-01-15 15:54:31 +00:00
logger * zap . Logger
nodeKeyPair * ed25519 . KeyPairEd25519
localNodeID * encoding . NodeId
networkID string
nodesBucket * bolt . Bucket
2024-01-29 04:59:43 +00:00
node * _node . Node
2024-01-15 15:54:31 +00:00
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-29 04:59:43 +00:00
func NewP2P ( node * _node . Node ) * P2PService {
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-29 04:59:43 +00:00
service := & P2PService {
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-29 04:59:43 +00:00
func ( p * P2PService ) SelfConnectionUris ( ) [ ] * url . URL {
2024-01-10 14:36:55 +00:00
return p . selfConnectionUris
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) Node ( ) * _node . Node {
2024-01-06 11:33:46 +00:00
return p . node
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) Peers ( ) structs . Map {
2024-01-06 11:33:46 +00:00
return p . peers
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) 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-29 04:59:43 +00:00
func ( p * P2PService ) Stop ( ) error {
2024-01-06 11:33:46 +00:00
panic ( "implement me" )
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) 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-29 04:59:43 +00:00
func ( p * P2PService ) 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 18:19:46 +00:00
p . logger . Debug ( "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 18:19:46 +00:00
blocked := false
2024-01-15 17:13:17 +00:00
if fromPeer . Id ( ) != nil {
fromPeerId , err = fromPeer . Id ( ) . ToString ( )
if err != nil {
return err
}
2024-01-15 18:19:46 +00:00
if ! p . incomingPeerBlockList . Contains ( fromPeerId ) {
p . incomingPeerBlockList . Put ( fromPeerId , true )
blocked = true
}
2024-01-15 16:04:41 +00:00
}
fromPeerIP := fromPeer . GetIP ( )
2024-01-15 18:19:46 +00:00
if ! p . incomingIPBlocklist . Contains ( fromPeerIP ) {
p . incomingIPBlocklist . Put ( fromPeerIP , true )
blocked = true
}
2024-01-15 18:37:49 +00:00
err = fromPeer . EndForAbuse ( )
2024-01-15 16:04:41 +00:00
if err != nil {
return err
}
2024-01-15 18:19:46 +00:00
if blocked {
p . logger . Debug ( "blocking peer for sending peer on blocklist" , zap . String ( "node" , connectionUri . String ( ) ) , zap . String ( "peer" , fromPeerId ) , zap . String ( "ip" , fromPeerIP ) )
}
2024-01-15 16:04:41 +00:00
}
2024-01-15 15:54:31 +00:00
return nil
}
2024-01-15 18:10:15 +00:00
reconnectDelay := p . reconnectDelay . GetUInt ( idString )
2024-01-06 11:33:46 +00:00
if reconnectDelay == nil {
2024-01-15 18:10:15 +00:00
delay := uint ( 1 )
2024-01-07 10:31:24 +00:00
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 ) {
2024-01-15 17:58:46 +00:00
tmp := * p . outgoingPeerFailures . GetUInt ( idString )
2024-01-15 18:19:46 +00:00
counter = tmp
2024-01-15 15:54:31 +00:00
}
counter ++
2024-01-15 17:58:46 +00:00
p . outgoingPeerFailures . PutUInt ( idString , counter )
2024-01-15 15:54:31 +00:00
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 18:19:46 +00:00
blocked := false
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
}
2024-01-15 18:19:46 +00:00
if ! p . incomingPeerBlockList . Contains ( fromPeerId ) {
p . incomingPeerBlockList . Put ( fromPeerId , true )
blocked = 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 ( )
2024-01-15 18:19:46 +00:00
if ! p . incomingIPBlocklist . Contains ( fromPeerIP ) {
p . incomingIPBlocklist . Put ( fromPeerIP , true )
blocked = true
}
2024-01-15 18:37:49 +00:00
err = fromPeer . EndForAbuse ( )
2024-01-15 16:38:38 +00:00
if err != nil {
return err
}
2024-01-15 16:45:25 +00:00
2024-01-15 18:19:46 +00:00
if blocked {
p . logger . Debug ( "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 18:19:46 +00:00
p . logger . Debug ( "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-15 18:03:49 +00:00
delay := p . reconnectDelay . GetUInt ( idString )
2024-01-08 15:51:38 +00:00
if delay == nil {
2024-01-15 18:03:49 +00:00
tmp := uint ( 1 )
2024-01-08 15:51:38 +00:00
delay = & tmp
}
delayDeref := * delay
2024-01-15 18:03:49 +00:00
p . reconnectDelay . PutUInt ( 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 )
2024-01-15 18:50:04 +00:00
if err != nil && ! peer . Abuser ( ) {
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-29 04:59:43 +00:00
func ( p * P2PService ) 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 ) )
2024-01-15 18:37:49 +00:00
err := peer . EndForAbuse ( )
2024-01-15 15:54:31 +00:00
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 ) )
2024-01-15 18:37:49 +00:00
err := peer . EndForAbuse ( )
2024-01-15 15:54:31 +00:00
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-29 04:59:43 +00:00
func ( p * P2PService ) OnNewPeerListen ( peer net . Peer , verifyId bool ) {
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 { } ) {
2024-01-15 18:50:04 +00:00
if ! peer . Abuser ( ) {
2024-01-15 18:49:07 +00:00
p . logger . Error ( "peer error" , zap . Any ( "args" , args ) )
}
2024-01-06 11:33:46 +00:00
} )
2024-01-07 11:35:41 +00:00
peer . ListenForMessages ( func ( message [ ] byte ) error {
2024-01-29 04:39:40 +00:00
var reader base . IncomingMessageReader
2024-01-06 11:33:46 +00:00
2024-01-29 04:39:40 +00:00
err := msgpack . Unmarshal ( message , & reader )
2024-01-06 11:33:46 +00:00
if err != nil {
2024-01-29 04:39:40 +00:00
p . logger . Error ( "Error decoding basic message info" , zap . Error ( err ) )
2024-01-06 11:33:46 +00:00
return err
}
2024-01-29 04:39:40 +00:00
// Now, get the specific message handler based on the message kind
handler , ok := protocol . GetMessageType ( reader . Kind )
if ! ok {
p . logger . Error ( "Unknown message type" , zap . Int ( "type" , reader . Kind ) )
return fmt . Errorf ( "unknown message type: %d" , reader . Kind )
}
2024-01-06 11:33:46 +00:00
2024-01-29 04:39:40 +00:00
data := base . IncomingMessageData {
Original : message ,
Data : reader . Data ,
Ctx : context . Background ( ) ,
2024-01-29 04:59:43 +00:00
Node : p . node ,
2024-01-29 04:39:40 +00:00
Peer : peer ,
VerifyId : verifyId ,
}
dec := msgpack . NewDecoder ( bytes . NewReader ( reader . Data ) )
err = handler . DecodeMessage ( dec , data )
if err != nil {
p . logger . Error ( "Error decoding message" , zap . Error ( err ) )
return err
}
// Directly decode and handle the specific message type
if err := handler . HandleMessage ( data ) ; err != nil {
p . logger . Error ( "Error handling message" , zap . Error ( err ) )
return err
2024-01-06 11:33:46 +00:00
}
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-29 04:59:43 +00:00
func ( p * P2PService ) readNodeVotes ( nodeId * encoding . NodeId ) ( 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-29 04:59:43 +00:00
var score 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-29 04:59:43 +00:00
func ( p * P2PService ) saveNodeVotes ( nodeId * encoding . NodeId , votes NodeVotes ) error {
2024-01-09 20:49:23 +00:00
// 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-29 04:59:43 +00:00
func ( p * P2PService ) 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-29 04:59:43 +00:00
func ( p * P2PService ) 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-29 04:59:43 +00:00
func ( p * P2PService ) SignMessageSimple ( message [ ] byte ) ( [ ] byte , error ) {
2024-01-07 14:07:37 +00:00
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
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) AddPeer ( peer net . Peer ) error {
2024-01-08 15:51:38 +00:00
peerId , err := peer . Id ( ) . ToString ( )
if err != nil {
return err
}
p . peers . Put ( peerId , peer )
2024-01-15 19:13:27 +00:00
p . reconnectDelay . PutUInt ( peerId , 1 )
2024-01-08 15:51:38 +00:00
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
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) SendPublicPeersToPeer ( peer net . Peer , peersToSend [ ] net . Peer ) error {
2024-01-08 15:51:38 +00:00
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-29 04:59:43 +00:00
func ( p * P2PService ) SendHashRequest ( hash * encoding . Multihash , kinds [ ] types . StorageLocationType ) error {
2024-01-09 11:59:12 +00:00
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
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) UpVote ( nodeId * encoding . NodeId ) error {
2024-01-09 11:59:12 +00:00
err := p . vote ( nodeId , true )
if err != nil {
return err
}
return nil
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) DownVote ( nodeId * encoding . NodeId ) error {
2024-01-09 11:59:12 +00:00
err := p . vote ( nodeId , false )
if err != nil {
return err
}
return nil
}
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) vote ( nodeId * encoding . NodeId , upvote bool ) error {
2024-01-09 11:59:12 +00:00
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-29 04:59:43 +00:00
func ( p * P2PService ) NodeId ( ) * encoding . NodeId {
2024-01-09 15:42:21 +00:00
return p . localNodeID
}
2024-01-24 07:53:56 +00:00
2024-01-29 04:59:43 +00:00
func ( p * P2PService ) PrepareProvideMessage ( hash * encoding . Multihash , location storage . StorageLocation ) [ ] byte {
2024-01-24 07:53:56 +00:00
// Initialize the list with the record type.
list := [ ] byte { byte ( types . RecordTypeStorageLocation ) }
// Append the full bytes of the hash.
list = append ( list , hash . FullBytes ( ) ... )
// Append the location type.
list = append ( list , byte ( location . Type ( ) ) )
// Append the expiry time of the location, encoded as 4 bytes.
list = append ( list , utils . EncodeEndian ( uint64 ( location . Expiry ( ) ) , 4 ) ... )
// Append the number of parts in the location.
list = append ( list , byte ( len ( location . Parts ( ) ) ) )
// Iterate over each part in the location.
for _ , part := range location . Parts ( ) {
// Convert part to bytes.
bytes := [ ] byte ( part )
// Encode the length of the part as 4 bytes and append.
2024-01-24 21:33:31 +00:00
list = append ( list , utils . EncodeEndian ( uint64 ( len ( bytes ) ) , 2 ) ... )
2024-01-24 07:53:56 +00:00
// Append the actual part bytes.
list = append ( list , bytes ... )
}
// Append a null byte at the end of the list.
list = append ( list , 0 )
// Sign the list using the node's private key.
2024-01-24 16:57:48 +00:00
signature := ed25519p . Sign ( p . nodeKeyPair . ExtractBytes ( ) , list )
2024-01-24 07:53:56 +00:00
// Append the public key and signature to the list.
finalList := append ( list , p . nodeKeyPair . PublicKey ( ) ... )
finalList = append ( finalList , signature ... )
// Return the final byte slice.
return finalList
}