-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.go
189 lines (155 loc) · 5.82 KB
/
handlers.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package p2p
import (
"bytes"
"encoding/gob"
"fmt"
"github.com/chezky/blemflarck/core"
)
//L -> R: Send version message with the local peer's version
//R -> L: Send version message back
//R -> L: Send verack message
//R: Sets version to the minimum of the 2 versions
//L -> R: Send verack message after receiving version message from R
//L: Sets version to the minimum of the 2 versions
var (
blocksNeeded = make(map[int32][]byte)
)
func handleVersion(req []byte, bc *core.Blockchain) {
var (
payload Version
)
dec := gob.NewDecoder(bytes.NewReader(req))
if err := dec.Decode(&payload); err != nil {
fmt.Printf("error decoding handleVersion with payload of length %d: %v\n", len(req), err)
return
}
fmt.Printf("version payload is %v\n", payload)
if !nodeIsKnow(payload.AddrFrom.IP) {
fmt.Printf("New node found with address: %s\n", payload.AddrFrom)
// If it is a new node, respond with your own version message before you can confirm it is valid
sendVersion(payload.AddrFrom, bc)
knownNodes[payload.AddrFrom.IP.String()] = createNewAddress(payload.AddrFrom)
}
// If successfully received the Version message, confirm with the sender that it has been received, to update the this receiving node as successful handshake on
// the sender node.
sendVerack(payload.AddrFrom.String())
myBlockHeight, err := bc.GetChainHeight()
if err != nil {
return
}
if myBlockHeight > payload.BlockHeight {
fmt.Printf("my block height is higher haha!\n")
} else if myBlockHeight < payload.BlockHeight {
sendGetBlocks(payload.AddrFrom, bc)
} else {
fmt.Println("Blockchain is up to date!")
}
// Update version to lower of the two nodes
if payload.Version > nodeVersion {
fmt.Printf("switching version \"%d\" to match node %s\n", payload.Version, payload.AddrFrom.String())
nodeVersion = payload.Version
}
}
// handleVerack is responsible for setting a nodes status to successful handshake if a verack message is received.
func handleVerack(address NetAddress) {
// make sure it is actually coming from the right place
fmt.Println("verack from:", address.String())
if knownNodes[address.IP.String()] != nil {
fmt.Printf("Successfully sent version message, and received verack!\n")
knownNodes[address.IP.String()].Handshake = true
}
fmt.Println("known nodes", knownNodes)
}
// What I want to do, is when I get a "getblocks" command, verify that the
func handleGetBlocks(req []byte, address NetAddress, bc *core.Blockchain) {
var payload GetBlocks
dec := gob.NewDecoder(bytes.NewReader(req))
if err := dec.Decode(&payload); err != nil {
fmt.Printf("error decoding GetBlocks of length %d: %v\n", len(req), err)
return
}
fmt.Printf("getting blocks starting with height %d for address %s\n", payload.Height+1, address.String())
blk, err := core.ReadBlockFromFile(int(payload.Height))
if err != nil {
fmt.Printf("error reading block height %d from file: %v\n", payload.Height, err)
return
}
if bytes.Compare(blk.Hash, payload.Hash) != 0 {
// TODO: handle this MUCH better
fmt.Printf("ERROR: block height \"%d\" on address %s has a different hash than this node does!\n", payload.Height, address.String())
return
}
myHeight, err := bc.GetChainHeight()
if err != nil {
fmt.Printf("error getting chain height for handleGetBlocks: %v\n", err)
return
}
inv := &Inventory{
Kind: "blocks",
}
for i:=payload.Height; i < myHeight; i++ {
// over here is i+1 since if i starts at their height we want to start with the next block up
blk, err := core.ReadBlockFromFile(int(i+1))
if err != nil {
fmt.Printf("error reading in block height \"%d\" for handleGetBlocks: %v\n", i, err)
return
}
// same here, we start with their height +1
inv.Height = append(inv.Height, i+1)
inv.Items = append(inv.Items, blk.Hash)
}
sendInv(address, inv)
}
// handleInventory handles calls to inventory. This can be triggered unsolicited, or in response to getblocks. When handling blocks, store the list of blocks you need to get,
// and then get the blocks from multiple places.
func handleInventory(req []byte, address NetAddress, bc *core.Blockchain) {
var payload Inventory
dec := gob.NewDecoder(bytes.NewReader(req))
if err := dec.Decode(&payload); err != nil {
fmt.Printf("error decoding handleInventory of length %d: %v\n", len(req), err)
return
}
if payload.Kind == "blocks" {
// populate the map blocksNeeded with all the new blocks to get
for idx, height := range payload.Height {
blocksNeeded[height] = payload.Items[idx]
}
sendGetData("blocks")
}
}
func handleGetData(req []byte, address NetAddress) {
var payload GetData
dec := gob.NewDecoder(bytes.NewReader(req))
if err := dec.Decode(&payload); err != nil {
fmt.Printf("error deocding during handleGetData: %v\n", err)
return
}
if payload.Kind == "blocks" {
fmt.Printf("Address %s requested block \"%d\"\n", address.IP.String(), payload.Height)
blk, err := core.ReadBlockFromFile(int(payload.Height))
if err != nil {
fmt.Printf("error reading in block height \"%d\" for handleGetData: %v\n", payload.Height, err)
return
}
if bytes.Compare(blk.Hash, payload.Hash) != 0 {
//TODO:// handle this. Maybe have some sort of way to send back errors
fmt.Printf("ERROR: block #%d and requested block #%d don't have matching hashes\n", blk.Height, payload.Height)
return
}
sendBlock(blk, address)
}
}
func handleBlock(req []byte, bc *core.Blockchain) {
// TODO: wow i need tons of block verification work here
var block core.Block
dec := gob.NewDecoder(bytes.NewReader(req))
if err := dec.Decode(&block); err != nil {
fmt.Printf("error decoding block for handleBlock, with request of length %d: %v", len(req), err)
return
}
if err := bc.UpdateWithNewBlock(block); err != nil {
fmt.Printf("error updating blockchain with new block #%d: %v\n", block.Height, err)
return
}
fmt.Printf("successfully added block #%d\n", block.Height)
}