func (b *BlockchainForest) GetBlock(peerId []byte, blockId []byte, blockOnly bool) BlockP2P {
	var block *blockchain.Block
	var blockP2P BlockP2P
	var blockchainDb *bolt.DB
	if bytes.Compare(peerId, b.Local.PeerId) == 0 {
		blockchainDb = b.Local.Db
	} else if !funk.IsEmpty(b.Peers[fmt.Sprintf("%x", peerId)]) {
		blockchainDb = b.Peers[fmt.Sprintf("%x", peerId)].Db
	} else {
		log.Warnf("peerId %x does not exist", peerId)
		return blockP2P
	}
	err := blockchainDb.View(func(dbtx *bolt.Tx) error {
		blockBucket := dbtx.Bucket([]byte(blockchain.BlocksBucket))
		if blockBucket == nil {
			return errors.New("block bucket doesn't exist")
		}
		encodedBlock := blockBucket.Get(blockId)
		if encodedBlock == nil {
			return nil
		}
		block = blockchain.DeserializeBlock(encodedBlock)
		return nil
	})
	if err != nil {
		log.Error(err)
		return blockP2P
	}
	if block == nil {
		return blockP2P
	} else if blockOnly {
		return BlockP2P{PeerId: peerId, Timestamp: block.Timestamp, PrevBlockHash: block.PrevBlockHash, Height: block.Height, Hash: block.Hash,
			TotalTransactions: block.TotalTransactions}
	}
	var transactions []blockchain.Transaction
	err = blockchainDb.View(func(dbtx *bolt.Tx) error {
		c := dbtx.Bucket([]byte(blockchain.TransactionsBucket)).Cursor()
		prefix := block.Hash
		for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
			transactions = append(transactions, *blockchain.DeserializeTransaction(v))
		}
		return nil
	})
	if err != nil {
		log.Error(err)
		return blockP2P
	}
	return BlockP2P{PeerId: peerId, Timestamp: block.Timestamp, PrevBlockHash: block.PrevBlockHash, Height: block.Height, Hash: block.Hash,
		TotalTransactions: block.TotalTransactions, Transactions: transactions}
}
GetBlock returns a local or peer block as requested
package p2p
import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"time"
	"github.com/boltdb/bolt"
	"github.com/codingpeasant/blocace/blockchain"
	"github.com/thoas/go-funk"
	log "github.com/sirupsen/logrus"
)
const peerBlockchainDir = "peers"
type BlockchainForest struct {
	Local *blockchain.Blockchain
	Peers map[string]*blockchain.Blockchain
}
func (b *BlockchainForest) AddBlock(blockP2p BlockP2P) {
	peerIdStr := fmt.Sprintf("%x", blockP2p.PeerId)
	block, err := blockP2p.MapToBlock()
	if err != nil {
		log.Error(err)
		return
	}
	if bytes.Compare(block.Hash, block.SetHash()) != 0 {
		log.Errorf("block hash verification failed, abandon this block")
		return
	}
	if b.Peers[peerIdStr] == nil {
		log.Infof("peer %s blockchain db not found, creating one...", peerIdStr)
		peerBlockchainsDbFile := b.Local.DataDir + filepath.Dir("/") + peerBlockchainDir + filepath.Dir("/") + fmt.Sprintf("%x", blockP2p.PeerId) + ".db"
		db, err := bolt.Open(peerBlockchainsDbFile, 0600, nil)
		if err != nil {
			log.Panic(err)
		}
		err = db.Update(func(dbtx *bolt.Tx) error {
			bBucket, err := dbtx.CreateBucket([]byte(blockchain.BlocksBucket))
			if err != nil {
				log.Panic(err)
			}
			_, err = dbtx.CreateBucket([]byte(blockchain.TransactionsBucket))
			if err != nil {
				log.Panic(err)
			}
			err = bBucket.Put([]byte("peerId"), blockP2p.PeerId)
			if err != nil {
				return err
			}
			return nil
		})
		if blockP2p.IsTip {
			b.Peers[peerIdStr] = &blockchain.Blockchain{Tip: blockP2p.Hash, PeerId: blockP2p.PeerId, Db: db, Search: b.Local.Search, DataDir: b.Local.DataDir}
		} else {
			b.Peers[peerIdStr] = &blockchain.Blockchain{PeerId: blockP2p.PeerId, Db: db, Search: b.Local.Search, DataDir: b.Local.DataDir}
		}
	} else if bytes.Compare(b.Peers[peerIdStr].Tip, block.Hash) == 0 {
		log.Infof("peer %s tip is already up-to-date: %x", peerIdStr, b.Peers[peerIdStr].Tip)
		return
	}
	if blockP2p.IsTip {
		b.Peers[peerIdStr].Tip = blockP2p.Hash
	}
	_, err = block.Persist(b.Peers[peerIdStr].Db, blockP2p.IsTip)
	if err != nil {
		log.Error(err)
	}
	start := time.Now().UnixNano()
	log.Debugf("start indexing the block at %d for peer blockchain %s...", start, peerIdStr)
	b.Local.Search.IndexBlock(block, blockP2p.PeerId)
	end := time.Now().UnixNano()
	log.Debug("end indexing the block:" + strconv.FormatInt(end, 10) + ", duration:" + strconv.FormatInt((end-start)/1000000, 10) + "ms")
}