func (hb *HoneyBadger) removeOldEpochs(epoch uint64) {
	for i, acs := range hb.acsInstances {
		if i >= hb.epoch-1 {
			continue
		}
		for _, t := range acs.bbaInstances {
			t.stop()
		}
		for _, t := range acs.rbcInstances {
			t.stop()
		}
		acs.stop()
		delete(hb.acsInstances, i)
	}
}
removeOldEpochs removes the ACS instances that have already been terminated.
package hbbft
import (
	"bytes"
	"encoding/gob"
	"math"
	"sync"
	"time"
	log "github.com/sirupsen/logrus"
)
type HBMessage struct {
	Epoch   uint64
	Payload interface{}
}
type Config struct {
	N int
	F int
	ID uint64
	Nodes []uint64
	BatchSize int
}
type HoneyBadger struct {
	Config
	acsInstances map[uint64]*ACS
	txBuffer *buffer
	epoch uint64
	lock sync.RWMutex
	outputs map[uint64][]Transaction
	messageQue *messageQue
	msgCount int
}
func NewHoneyBadger(cfg Config) *HoneyBadger {
	return &HoneyBadger{
		Config:       cfg,
		acsInstances: make(map[uint64]*ACS),
		txBuffer:     newBuffer(),
		outputs:      make(map[uint64][]Transaction),
		messageQue:   newMessageQue(),
	}
}
func (hb *HoneyBadger) Messages() []MessageTuple {
	return hb.messageQue.messages()
}
func (hb *HoneyBadger) AddTransaction(tx Transaction) {
	hb.txBuffer.push(tx)
}
func (hb *HoneyBadger) HandleMessage(sid, epoch uint64, msg *ACSMessage) error {
	hb.msgCount++
	acs, ok := hb.acsInstances[epoch]
	if !ok {
		if epoch < hb.epoch {
			log.Warnf("ignoring old epoch")
			return nil
		}
		acs = NewACS(hb.Config)
		hb.acsInstances[epoch] = acs
	}
	if err := acs.HandleMessage(sid, msg); err != nil {
		return err
	}
	hb.addMessages(acs.messageQue.messages())
	if hb.epoch == epoch {
		return hb.maybeProcessOutput()
	}
	hb.removeOldEpochs(epoch)
	return nil
}
func (hb *HoneyBadger) Start() error {
	return hb.propose()
}
func (hb *HoneyBadger) LenMempool() int {
	return hb.txBuffer.len()
}
func (hb *HoneyBadger) Outputs() map[uint64][]Transaction {
	hb.lock.RLock()
	out := hb.outputs
	hb.lock.RUnlock()
	hb.lock.Lock()
	defer hb.lock.Unlock()
	hb.outputs = make(map[uint64][]Transaction)
	return out
}
func (hb *HoneyBadger) propose() error {
	if hb.txBuffer.len() == 0 {
		time.Sleep(2 * time.Second)
		return hb.propose()
	}
	batchSize := hb.BatchSize
	if batchSize == 0 {
		scalar := 20
		batchSize = (len(hb.Nodes) * 2) * scalar
	}
	batchSize = int(math.Min(float64(batchSize), float64(hb.txBuffer.len())))
	n := int(math.Max(float64(1), float64(batchSize/len(hb.Nodes))))
	batch := sample(hb.txBuffer.data[:batchSize], n)
	buf := new(bytes.Buffer)
	if err := gob.NewEncoder(buf).Encode(batch); err != nil {
		return err
	}
	acs := hb.getOrNewACSInstance(hb.epoch)
	if err := acs.InputValue(buf.Bytes()); err != nil {
		return err
	}
	hb.addMessages(acs.messageQue.messages())
	return nil
}
func (hb *HoneyBadger) maybeProcessOutput() error {
	start := time.Now()
	acs, ok := hb.acsInstances[hb.epoch]
	if !ok {
		return nil
	}
	outputs := acs.Output()
	if outputs == nil || len(outputs) == 0 {
		return nil
	}
	txMap := make(map[string]Transaction)
	for _, output := range outputs {
		var txx []Transaction
		if err := gob.NewDecoder(bytes.NewReader(output)).Decode(&txx); err != nil {
			return err
		}
		for _, tx := range txx {
			txMap[string(tx.Hash())] = tx
		}
	}
	txBatch := make([]Transaction, len(txMap))
	i := 0
	for _, tx := range txMap {
		txBatch[i] = tx
		i++
	}
	hb.txBuffer.delete(txBatch)
	hb.outputs[hb.epoch] = txBatch
	hb.epoch++
	if hb.epoch%100 == 0 {
		log.Debugf("node (%d) commited (%d) transactions in epoch (%d) took %v",
			hb.ID, len(txBatch), hb.epoch, time.Since(start))
	}
	hb.msgCount = 0
	return hb.propose()
}
func (hb *HoneyBadger) getOrNewACSInstance(epoch uint64) *ACS {
	if acs, ok := hb.acsInstances[epoch]; ok {
		return acs
	}
	acs := NewACS(hb.Config)
	hb.acsInstances[epoch] = acs
	return acs
}