Implement 'block' and 'getdata' commands

This commit is contained in:
Ivan Kuznetsov 2017-10-01 11:50:27 +07:00
parent 9adb5fc139
commit 470adef2c3
2 changed files with 112 additions and 6 deletions

View File

@ -97,6 +97,11 @@ func NewBlockchain(nodeID string) *Blockchain {
return &bc return &bc
} }
// Reset removes all blockchain data
func (bc *Blockchain) Reset() {
}
// FindTransaction finds a transaction by its ID // FindTransaction finds a transaction by its ID
func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) { func (bc *Blockchain) FindTransaction(ID []byte) (Transaction, error) {
bci := bc.Iterator() bci := bc.Iterator()
@ -169,6 +174,30 @@ func (bc *Blockchain) Iterator() *BlockchainIterator {
return bci return bci
} }
// GetBlock finds a block by its hash and returns it
func (bc *Blockchain) GetBlock(blockHash []byte) (Block, error) {
var block Block
err := bc.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blocksBucket))
blockData := b.Get(blockHash)
if blockData == nil {
return errors.New("Block is not found.")
}
block = *DeserializeBlock(blockData)
return nil
})
if err != nil {
return block, err
}
return block, nil
}
// GetBlockHashes returns a list of hashes of all the blocks in the chain // GetBlockHashes returns a list of hashes of all the blocks in the chain
func (bc *Blockchain) GetBlockHashes() [][]byte { func (bc *Blockchain) GetBlockHashes() [][]byte {
var blocks [][]byte var blocks [][]byte

View File

@ -22,13 +22,25 @@ type addr struct {
AddrList []string AddrList []string
} }
type block struct {
AddrFrom string
Block []byte
}
type getblocks struct { type getblocks struct {
AddrFrom string AddrFrom string
} }
type getdata struct {
AddrFrom string
Type string
ID []byte
}
type inv struct { type inv struct {
Type string AddrFrom string
Items [][]byte Type string
Items [][]byte
} }
type verack struct { type verack struct {
@ -81,6 +93,14 @@ func sendAddr(address string) {
sendData(address, request) sendData(address, request)
} }
func sendBlock(addr string, b *Block) {
data := block{nodeAddress, b.Serialize()}
payload := gobEncode(data)
request := append(commandToBytes("block"), payload...)
sendData(addr, request)
}
func sendData(addr string, data []byte) { func sendData(addr string, data []byte) {
conn, err := net.Dial(protocol, addr) conn, err := net.Dial(protocol, addr)
if err != nil { if err != nil {
@ -95,7 +115,7 @@ func sendData(addr string, data []byte) {
} }
func sendInv(address, kind string, items [][]byte) { func sendInv(address, kind string, items [][]byte) {
inventory := inv{kind, items} inventory := inv{nodeAddress, kind, items}
payload := gobEncode(inventory) payload := gobEncode(inventory)
request := append(commandToBytes("inv"), payload...) request := append(commandToBytes("inv"), payload...)
@ -109,6 +129,13 @@ func sendGetBlocks(address string) {
sendData(address, request) sendData(address, request)
} }
func sendGetData(address, kind string, id []byte) {
payload := gobEncode(getdata{nodeAddress, kind, id})
request := append(commandToBytes("getdata"), payload...)
sendData(address, request)
}
func sendVersion(addr string) { func sendVersion(addr string) {
payload := gobEncode(verzion{nodeVersion, nodeAddress}) payload := gobEncode(verzion{nodeVersion, nodeAddress})
@ -141,7 +168,25 @@ func handleAddr(request []byte) {
requestBlocks() requestBlocks()
} }
func handleInv(request []byte) { func handleBlock(request []byte, bc *Blockchain) {
var buff bytes.Buffer
var payload block
buff.Write(request[commandLength:])
dec := gob.NewDecoder(&buff)
err := dec.Decode(&payload)
if err != nil {
log.Panic(err)
}
blockData := payload.Block
block := DeserializeBlock(blockData)
fmt.Println("Recevied a new block!")
fmt.Println(block)
}
func handleInv(request []byte, bc *Blockchain) {
var buff bytes.Buffer var buff bytes.Buffer
var payload inv var payload inv
@ -152,7 +197,14 @@ func handleInv(request []byte) {
log.Panic(err) log.Panic(err)
} }
fmt.Printf("Recevied %d %s\n", len(payload.Items), payload.Type) fmt.Printf("Recevied inventory with %d %s\n", len(payload.Items), payload.Type)
blocks := bc.GetBlockHashes()
if len(blocks) < len(payload.Items) {
for _, blockHash := range invResponse.Items {
sendGetData(sourceNode, "block", blockHash)
}
}
} }
func handleGetBlocks(request []byte, bc *Blockchain) { func handleGetBlocks(request []byte, bc *Blockchain) {
@ -170,6 +222,27 @@ func handleGetBlocks(request []byte, bc *Blockchain) {
sendInv(payload.AddrFrom, "blocks", blocks) sendInv(payload.AddrFrom, "blocks", blocks)
} }
func handleGetData(request []byte, bc *Blockchain) {
var buff bytes.Buffer
var payload getdata
buff.Write(request[commandLength:])
dec := gob.NewDecoder(&buff)
err := dec.Decode(&payload)
if err != nil {
log.Panic(err)
}
if payload.Type == "block" {
block, err := bc.GetBlock([]byte(payload.ID))
if err != nil {
return
}
sendBlock(payload.AddrFrom, &block)
}
}
func handleVersion(request []byte) { func handleVersion(request []byte) {
var buff bytes.Buffer var buff bytes.Buffer
var payload verzion var payload verzion
@ -197,10 +270,14 @@ func handleConnection(conn net.Conn, bc *Blockchain) {
switch command { switch command {
case "addr": case "addr":
handleAddr(request) handleAddr(request)
case "block":
handleBlock(request, bc)
case "inv": case "inv":
handleInv(request) handleInv(request, bc)
case "getblocks": case "getblocks":
handleGetBlocks(request, bc) handleGetBlocks(request, bc)
case "getdata":
handleGetData(request, bc)
case "version": case "version":
handleVersion(request) handleVersion(request)
case "verack": case "verack":