dione/blockchain/pool/blockpool.go

102 lines
2.6 KiB
Go

package pool
import (
"bytes"
"encoding/hex"
"fmt"
"time"
"github.com/asaskevich/EventBus"
"github.com/sirupsen/logrus"
"github.com/Secured-Finance/dione/blockchain/types"
"github.com/Secured-Finance/dione/cache"
)
// BlockPool is pool for blocks that isn't not validated or committed yet
type BlockPool struct {
mempool *Mempool
knownBlocks cache.Cache
acceptedBlocks cache.Cache
bus EventBus.Bus
}
func NewBlockPool(mp *Mempool, bus EventBus.Bus) (*BlockPool, error) {
bp := &BlockPool{
acceptedBlocks: cache.NewInMemoryCache(), // here we need to use separate cache
knownBlocks: cache.NewInMemoryCache(),
mempool: mp,
bus: bus,
}
return bp, nil
}
func (bp *BlockPool) AddBlock(block *types.Block) error {
err := bp.knownBlocks.StoreWithTTL(hex.EncodeToString(block.Header.Hash), block, 10*time.Minute)
if err != nil {
return err
}
logrus.WithField("hash", fmt.Sprintf("%x", block.Header.Hash)).Debug("New block discovered")
bp.bus.Publish("blockpool:knownBlockAdded", block)
return nil
}
func (bp *BlockPool) GetBlock(blockhash []byte) (*types.Block, error) {
var block types.Block
err := bp.knownBlocks.Get(hex.EncodeToString(blockhash), &block)
return &block, err
}
// PruneBlocks cleans known blocks list. It is called when new consensus round starts.
func (bp *BlockPool) PruneBlocks() {
for k := range bp.knownBlocks.Items() {
bp.knownBlocks.Delete(k)
}
bp.bus.Publish("blockpool:pruned")
}
func (bp *BlockPool) AddAcceptedBlock(block *types.Block) error {
err := bp.acceptedBlocks.Store(hex.EncodeToString(block.Header.Hash), block)
if err != nil {
return err
}
bp.bus.Publish("blockpool:acceptedBlockAdded", block)
return nil
}
func (bp *BlockPool) GetAllAcceptedBlocks() []*types.Block {
var blocks []*types.Block
for _, v := range bp.acceptedBlocks.Items() {
blocks = append(blocks, v.(*types.Block))
}
return blocks
}
// PruneAcceptedBlocks cleans accepted blocks list. It is called when new consensus round starts.
func (bp *BlockPool) PruneAcceptedBlocks(committedBlock *types.Block) {
for k, v := range bp.acceptedBlocks.Items() {
block := v.(*types.Block)
for _, v := range block.Data {
if !containsTx(committedBlock.Data, v) {
v.MerkleProof = nil
err := bp.mempool.StoreTx(v) // return transactions back to mempool
if err != nil {
logrus.Error(err)
}
}
}
bp.acceptedBlocks.Delete(k)
}
}
func containsTx(s []*types.Transaction, e *types.Transaction) bool {
for _, a := range s {
if bytes.Equal(a.Hash, e.Hash) {
return true
}
}
return false
}