From 9adb5fc1393c2d2ab0f4662cbff0fcffa296d87f Mon Sep 17 00:00:00 2001 From: Ivan Kuznetsov Date: Sun, 1 Oct 2017 11:19:43 +0700 Subject: [PATCH] Implement 'getblocks' command --- blockchain.go | 18 +++++++++++++++ server.go | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/blockchain.go b/blockchain.go index 8d1cab7..0f310af 100644 --- a/blockchain.go +++ b/blockchain.go @@ -169,6 +169,24 @@ func (bc *Blockchain) Iterator() *BlockchainIterator { return bci } +// GetBlockHashes returns a list of hashes of all the blocks in the chain +func (bc *Blockchain) GetBlockHashes() [][]byte { + var blocks [][]byte + bci := bc.Iterator() + + for { + block := bci.Next() + + blocks = append(blocks, block.Hash) + + if len(block.PrevBlockHash) == 0 { + break + } + } + + return blocks +} + // MineBlock mines a new block with the provided transactions func (bc *Blockchain) MineBlock(transactions []*Transaction) *Block { var lastHash []byte diff --git a/server.go b/server.go index 37a87ac..0cbf599 100644 --- a/server.go +++ b/server.go @@ -22,6 +22,15 @@ type addr struct { AddrList []string } +type getblocks struct { + AddrFrom string +} + +type inv struct { + Type string + Items [][]byte +} + type verack struct { } @@ -57,6 +66,12 @@ func extractCommand(request []byte) []byte { return request[:commandLength] } +func requestBlocks() { + for _, node := range knownNodes { + sendGetBlocks(node) + } +} + func sendAddr(address string) { nodes := addr{knownNodes} nodes.AddrList = append(nodes.AddrList, nodeAddress) @@ -79,6 +94,21 @@ func sendData(addr string, data []byte) { } } +func sendInv(address, kind string, items [][]byte) { + inventory := inv{kind, items} + payload := gobEncode(inventory) + request := append(commandToBytes("inv"), payload...) + + sendData(address, request) +} + +func sendGetBlocks(address string) { + payload := gobEncode(getblocks{nodeAddress}) + request := append(commandToBytes("getblocks"), payload...) + + sendData(address, request) +} + func sendVersion(addr string) { payload := gobEncode(verzion{nodeVersion, nodeAddress}) @@ -108,6 +138,36 @@ func handleAddr(request []byte) { knownNodes = append(knownNodes, payload.AddrList...) fmt.Printf("There are %d known nodes now!\n", len(knownNodes)) + requestBlocks() +} + +func handleInv(request []byte) { + var buff bytes.Buffer + var payload inv + + buff.Write(request[commandLength:]) + dec := gob.NewDecoder(&buff) + err := dec.Decode(&payload) + if err != nil { + log.Panic(err) + } + + fmt.Printf("Recevied %d %s\n", len(payload.Items), payload.Type) +} + +func handleGetBlocks(request []byte, bc *Blockchain) { + var buff bytes.Buffer + var payload getblocks + + buff.Write(request[commandLength:]) + dec := gob.NewDecoder(&buff) + err := dec.Decode(&payload) + if err != nil { + log.Panic(err) + } + + blocks := bc.GetBlockHashes() + sendInv(payload.AddrFrom, "blocks", blocks) } func handleVersion(request []byte) { @@ -137,6 +197,10 @@ func handleConnection(conn net.Conn, bc *Blockchain) { switch command { case "addr": handleAddr(request) + case "inv": + handleInv(request) + case "getblocks": + handleGetBlocks(request, bc) case "version": handleVersion(request) case "verack":