Skip to content

Commit c753df2

Browse files
committed
Implement the correct way of synchronizing a blockchain
1 parent a79d78a commit c753df2

File tree

2 files changed

+96
-35
lines changed

2 files changed

+96
-35
lines changed

blockchain.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,24 @@ func (bc *Blockchain) AddBlock(block *Block) {
109109
blockInDb := b.Get(block.Hash)
110110

111111
if blockInDb != nil {
112-
blockData := block.Serialize()
113-
b.Put(block.Hash, blockData)
112+
return nil
113+
}
114+
115+
blockData := block.Serialize()
116+
err := b.Put(block.Hash, blockData)
117+
if err != nil {
118+
log.Panic(err)
119+
}
120+
121+
lastHash := b.Get([]byte("l"))
122+
lastBlockData := b.Get(lastHash)
123+
lastBlock := DeserializeBlock(lastBlockData)
124+
125+
if block.Height > lastBlock.Height {
126+
err = b.Put([]byte("l"), block.Hash)
127+
if err != nil {
128+
log.Panic(err)
129+
}
114130
}
115131

116132
return nil
@@ -192,6 +208,25 @@ func (bc *Blockchain) Iterator() *BlockchainIterator {
192208
return bci
193209
}
194210

211+
// GetBestHeight returns the height of the latest block
212+
func (bc *Blockchain) GetBestHeight() int {
213+
var lastBlock Block
214+
215+
err := bc.db.View(func(tx *bolt.Tx) error {
216+
b := tx.Bucket([]byte(blocksBucket))
217+
lastHash := b.Get([]byte("l"))
218+
blockData := b.Get(lastHash)
219+
lastBlock = *DeserializeBlock(blockData)
220+
221+
return nil
222+
})
223+
if err != nil {
224+
log.Panic(err)
225+
}
226+
227+
return lastBlock.Height
228+
}
229+
195230
// GetBlock finds a block by its hash and returns it
196231
func (bc *Blockchain) GetBlock(blockHash []byte) (Block, error) {
197232
var block Block

server.go

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111
)
1212

1313
const protocol = "tcp"
14-
const dnsNodeID = "3000"
1514
const nodeVersion = 1
1615
const commandLength = 12
1716

1817
var nodeAddress string
19-
var knownNodes []string
18+
var knownNodes = []string{"localhost:3000"}
19+
var blocksInTransit = [][]byte{}
2020

2121
type addr struct {
2222
AddrList []string
@@ -43,13 +43,10 @@ type inv struct {
4343
Items [][]byte
4444
}
4545

46-
type verack struct {
47-
}
48-
4946
type verzion struct {
50-
Version int
51-
52-
AddrFrom string
47+
Version int
48+
BestHeight int
49+
AddrFrom string
5350
}
5451

5552
func commandToBytes(command string) []byte {
@@ -136,22 +133,15 @@ func sendGetData(address, kind string, id []byte) {
136133
sendData(address, request)
137134
}
138135

139-
func sendVersion(addr string) {
140-
payload := gobEncode(verzion{nodeVersion, nodeAddress})
136+
func sendVersion(addr string, bc *Blockchain) {
137+
bestHeight := bc.GetBestHeight()
138+
payload := gobEncode(verzion{nodeVersion, bestHeight, nodeAddress})
141139

142140
request := append(commandToBytes("version"), payload...)
143141

144142
sendData(addr, request)
145143
}
146144

147-
func sendVrack(addr string) {
148-
payload := gobEncode(verack{})
149-
150-
request := append(commandToBytes("verack"), payload...)
151-
152-
sendData(addr, request)
153-
}
154-
155145
func handleAddr(request []byte) {
156146
var buff bytes.Buffer
157147
var payload addr
@@ -184,6 +174,16 @@ func handleBlock(request []byte, bc *Blockchain) {
184174

185175
fmt.Println("Recevied a new block!")
186176
bc.AddBlock(block)
177+
fmt.Printf("Added block %x\n", block.Hash)
178+
fmt.Printf("Added block %d\n", block.Height)
179+
180+
fmt.Println(blocksInTransit)
181+
if len(blocksInTransit) > 0 {
182+
blockHash := blocksInTransit[0]
183+
sendGetData(payload.AddrFrom, "block", blockHash)
184+
185+
blocksInTransit = blocksInTransit[1:]
186+
}
187187
}
188188

189189
func handleInv(request []byte, bc *Blockchain) {
@@ -198,12 +198,20 @@ func handleInv(request []byte, bc *Blockchain) {
198198
}
199199

200200
fmt.Printf("Recevied inventory with %d %s\n", len(payload.Items), payload.Type)
201-
blocks := bc.GetBlockHashes()
202201

203-
if len(blocks) < len(payload.Items) {
204-
for _, blockHash := range payload.Items {
205-
sendGetData(payload.AddrFrom, "block", blockHash)
202+
if payload.Type == "blocks" {
203+
blocksInTransit = payload.Items
204+
205+
blockHash := payload.Items[0]
206+
sendGetData(payload.AddrFrom, "block", blockHash)
207+
208+
newInTransit := [][]byte{}
209+
for _, b := range blocksInTransit {
210+
if bytes.Compare(b, blockHash) != 0 {
211+
newInTransit = append(newInTransit, b)
212+
}
206213
}
214+
blocksInTransit = newInTransit
207215
}
208216
}
209217

@@ -243,7 +251,7 @@ func handleGetData(request []byte, bc *Blockchain) {
243251
}
244252
}
245253

246-
func handleVersion(request []byte) {
254+
func handleVersion(request []byte, bc *Blockchain) {
247255
var buff bytes.Buffer
248256
var payload verzion
249257

@@ -254,9 +262,19 @@ func handleVersion(request []byte) {
254262
log.Panic(err)
255263
}
256264

257-
sendVrack(payload.AddrFrom)
258-
sendAddr(payload.AddrFrom)
259-
knownNodes = append(knownNodes, payload.AddrFrom)
265+
myBestHeight := bc.GetBestHeight()
266+
foreignerBestHeight := payload.BestHeight
267+
268+
if myBestHeight < foreignerBestHeight {
269+
sendGetBlocks(payload.AddrFrom)
270+
} else {
271+
sendVersion(payload.AddrFrom, bc)
272+
}
273+
274+
// sendAddr(payload.AddrFrom)
275+
if !nodeIsKnown(payload.AddrFrom) {
276+
knownNodes = append(knownNodes, payload.AddrFrom)
277+
}
260278
}
261279

262280
func handleConnection(conn net.Conn, bc *Blockchain) {
@@ -279,9 +297,7 @@ func handleConnection(conn net.Conn, bc *Blockchain) {
279297
case "getdata":
280298
handleGetData(request, bc)
281299
case "version":
282-
handleVersion(request)
283-
case "verack":
284-
//
300+
handleVersion(request, bc)
285301
default:
286302
fmt.Println("Unknown command!")
287303
}
@@ -298,12 +314,12 @@ func StartServer(nodeID string) {
298314
}
299315
defer ln.Close()
300316

301-
if nodeID != dnsNodeID {
302-
sendVersion(fmt.Sprintf("localhost:%s", dnsNodeID))
303-
}
304-
305317
bc := NewBlockchain(nodeID)
306318

319+
if nodeAddress != knownNodes[0] {
320+
sendVersion(knownNodes[0], bc)
321+
}
322+
307323
for {
308324
conn, err := ln.Accept()
309325
if err != nil {
@@ -324,3 +340,13 @@ func gobEncode(data interface{}) []byte {
324340

325341
return buff.Bytes()
326342
}
343+
344+
func nodeIsKnown(addr string) bool {
345+
for _, node := range knownNodes {
346+
if node == addr {
347+
return true
348+
}
349+
}
350+
351+
return false
352+
}

0 commit comments

Comments
 (0)