-
Notifications
You must be signed in to change notification settings - Fork 1
/
peer.go
129 lines (109 loc) · 4.52 KB
/
peer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package core
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
)
// Peer Management: Nodes add new peers to their network, avoiding duplicates, and adjust protocols (HTTP/HTTPS) as necessary.
// Peer Discovery: Nodes discover new peers by requesting peer lists from known peers and integrating the discovered peers into their own peer list.
// Blockchain Synchronization: Nodes synchronize their blockchain with peers to maintain a consistent state across the network. If a peer's blockchain is longer, the node updates its blockchain to match.
// AddPeer adds a new peer to the node's list of peers if it is not already present. This function ensures that
// the node maintains an up-to-date list of peers with which it can communicate. Duplicate addresses are ignored
// to prevent redundancy.
func (node *Node) AddPeer(peerAddress string) {
// Ensure the peer address includes the http:// scheme
if !strings.HasPrefix(peerAddress, "http://") && !strings.HasPrefix(peerAddress, "https://") {
peerAddress = "http://" + peerAddress // Defaulting to HTTP for simplicity
}
// Check for duplicates
for _, peer := range node.Peers {
if peer == peerAddress {
return // Peer is already in the list, no need to add again.
}
}
node.Peers = append(node.Peers, peerAddress) // Add new peer to the list.
fmt.Println("Peer added:", peerAddress)
}
// DiscoverPeers iterates over the node's current list of peers and requests their peer lists. This allows the node
// to discover new peers in the network dynamically. Discovered peers are added using the AddPeer method.
func (node *Node) DiscoverPeers() {
maxRetries := 5
retryInterval := time.Second * 5 // 5 seconds between retries
for i := 0; i < maxRetries; i++ {
allPeersDiscovered := true
for _, peer := range node.Peers {
resp, err := http.Get(peer + "/peers")
if err != nil {
fmt.Println("Failed to discover peers:", err)
allPeersDiscovered = false
break // Exit the inner loop, one failed attempt means retry
}
defer resp.Body.Close()
var discoveredPeers []string
if err := json.NewDecoder(resp.Body).Decode(&discoveredPeers); err != nil {
fmt.Printf("Failed to decode peers from %s: %v\n", peer, err)
allPeersDiscovered = false
break // Exit the inner loop, one failed decoding means retry
}
for _, discoveredPeer := range discoveredPeers {
node.AddPeer(discoveredPeer) // Add each discovered peer.
}
}
if allPeersDiscovered {
fmt.Println("Successfully discovered all peers.")
return // Exit the function if all peers are successfully discovered
}
fmt.Printf("Retrying peer discovery in %v... (%d/%d)\n", retryInterval, i+1, maxRetries)
time.Sleep(retryInterval)
}
fmt.Println("Failed to discover all peers after maximum retries.")
}
// SyncWithPeer fetches the blockchain from a specified peer and updates the node's blockchain if the peer's
// blockchain is longer. This function is part of the node's mechanism for maintaining consensus on the blockchain
// state across the network.
func (node *Node) SyncWithPeer(peer string) {
resp, err := http.Get(peer + "/blockchain")
if err != nil {
fmt.Println("Error fetching the blockchain:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response:", err)
return
}
peerBlockchain := &Blockchain{}
err = json.Unmarshal(body, peerBlockchain) // Unmarshal the fetched blockchain.
if err != nil {
fmt.Println("Error unmarshalling the blockchain:", err)
return
}
// Update the node's blockchain if the peer's blockchain is longer.
if len(peerBlockchain.Blocks) > len(node.Blockchain.Blocks) {
node.Blockchain.Mu.Lock()
node.Blockchain.Blocks = peerBlockchain.Blocks // Assume direct replacement for simplicity; real logic might be more complex.
node.Blockchain.Mu.Unlock()
}
}
// Broadcast serializes the node's blockchain and sends it to all known peers. This function supports the network's
// consistency by ensuring that all peers have the latest state of the blockchain.
func (node *Node) Broadcast() {
data, err := json.Marshal(node.Blockchain) // Serialize the node's blockchain.
if err != nil {
fmt.Println("Error:", err)
return
}
for _, peer := range node.Peers {
resp, err := http.Post(peer+"/blockchain", "application/json", bytes.NewBuffer(data)) // Broadcast the blockchain to each peer.
if err != nil {
fmt.Println("Failed to broadcast to peer:", peer)
continue
}
resp.Body.Close() // Close the response body to prevent resource leaks.
}
}