func (s *ShardMempool) RemoveTransactionsFromBlock(block *primitives.ShardBlock) {
	s.mempoolLock.Lock()
	defer s.mempoolLock.Unlock()
	newOrder := make([]*shardMempoolItem, 0, len(s.mempoolOrder))
	for _, tx := range block.Body.Transactions {
		txHash := chainhash.HashH(tx.TransactionData)
		delete(s.mempool, txHash)
	}
	for _, tx := range s.mempoolOrder {
		txHash := chainhash.HashH(tx.tx)
		if _, found := s.mempool[txHash]; found {
			newOrder = append(newOrder, tx)
		}
	}
	s.mempoolOrder = newOrder
}
RemoveTransactionsFromBlock removes transactions from the mempool that were included in a block.
package mempool
import (
	"sync"
	"github.com/phoreproject/synapse/chainhash"
	"github.com/phoreproject/synapse/csmt"
	"github.com/phoreproject/synapse/pb"
	"github.com/phoreproject/synapse/primitives"
	"github.com/phoreproject/synapse/shard/state"
	"github.com/sirupsen/logrus"
)
type shardMempoolItem struct {
	tx []byte
}
type ShardMempool struct {
	mempoolLock *sync.RWMutex
	shardInfo   state.ShardInfo
	mempool      map[chainhash.Hash]*shardMempoolItem
	mempoolOrder []*shardMempoolItem
	stateManager *state.ShardStateManager
}
func NewShardMempool(stateDB csmt.TreeDatabase, stateSlot uint64, tipBlockHash chainhash.Hash, info state.ShardInfo) *ShardMempool {
	return &ShardMempool{
		mempool:      make(map[chainhash.Hash]*shardMempoolItem),
		mempoolOrder: nil,
		mempoolLock:  new(sync.RWMutex),
		stateManager: state.NewShardStateManager(stateDB, stateSlot, tipBlockHash, info),
		shardInfo: info,
	}
}
func (s *ShardMempool) GetTipState() (state.State, csmt.TreeDatabase) {
	return s.stateManager.GetTip()
}
func (s *ShardMempool) check(tx []byte) error {
	_, db := s.GetTipState()
	treeCache, err := csmt.NewTreeMemoryCache(db)
	if err != nil {
		return err
	}
	tree := csmt.NewTree(treeCache)
	return tree.Update(func(treeTx csmt.TreeTransactionAccess) error {
		_, err := state.Transition(treeTx, tx, s.shardInfo)
		return err
	})
}
func (s *ShardMempool) Add(tx []byte) error {
	txHash := chainhash.HashH(tx)
	s.mempoolLock.Lock()
	defer s.mempoolLock.Unlock()
	logrus.WithField("hash", txHash).Info("adding new transaction to mempool")
	if _, found := s.mempool[txHash]; found {
		logrus.WithField("hash", txHash).Debug("transaction already exists")
		return nil
	}
	if err := s.check(tx); err != nil {
		return err
	}
	poolItem := &shardMempoolItem{
		tx: tx,
	}
	s.mempool[txHash] = poolItem
	s.mempoolOrder = append(s.mempoolOrder, poolItem)
	return nil
}
func (s *ShardMempool) AcceptAction(action *pb.ShardChainAction) error {
	if action.AddBlockAction != nil {
		blockToAdd, err := primitives.ShardBlockFromProto(action.AddBlockAction.Block)
		if err != nil {
			return err
		}
		if _, err := s.stateManager.Add(blockToAdd); err != nil {
			return err
		}
		s.RemoveTransactionsFromBlock(blockToAdd)
	} else if action.FinalizeBlockAction != nil {
		toFinalizeHash, err := chainhash.NewHash(action.FinalizeBlockAction.Hash)
		if err != nil {
			return err
		}
		if err := s.stateManager.Finalize(*toFinalizeHash, action.FinalizeBlockAction.Slot); err != nil {
			return err
		}
	} else if action.UpdateTip != nil {
		newTipHash, err := chainhash.NewHash(action.UpdateTip.Hash)
		if err != nil {
			return err
		}
		if err := s.stateManager.SetTip(*newTipHash); err != nil {
			return err
		}
	}
	return nil
}
func (s *ShardMempool) GetCurrentRoot() (*chainhash.Hash, error) {
	_, state := s.GetTipState()
	return state.Hash()
}
func (s *ShardMempool) GetTransactions(maxBytes int) (*primitives.TransactionPackage, uint64, error) {
	transactionsToInclude := make([]primitives.ShardTransaction, 0)
	s.mempoolLock.RLock()
	defer s.mempoolLock.RUnlock()
	totalBytes := 0
	_, tipState := s.GetTipState()
	startRootHash, err := tipState.Hash()
	if err != nil {
		return nil, 0, err
	}
	startSlot := s.stateManager.GetTipSlot()
	var startRoot [32]byte
	copy(startRoot[:], startRootHash[:])
	packageTreeCache, err := csmt.NewTreeMemoryCache(tipState)
	if err != nil {
		return nil, 0, err
	}
	updates := make([]primitives.UpdateWitness, 0)
	verifications := make([]primitives.VerificationWitness, 0)
	for _, tx := range s.mempoolOrder {
		if totalBytes+len(tx.tx) > maxBytes && maxBytes != -1 {
			continue
		}
		transactionTreeCache, err := csmt.NewTreeMemoryCache(packageTreeCache)
		if err != nil {
			return nil, 0, err
		}
		tree := csmt.NewTree(transactionTreeCache)
		trackingTree, err := state.NewTrackingState(tree)
		if err != nil {
			return nil, 0, err
		}
		err = trackingTree.Update(func(treeTx csmt.TreeTransactionAccess) error {
			_, err := state.Transition(treeTx, tx.tx, s.shardInfo)
			return err
		})
		if err != nil {
			continue
		}
		totalBytes += len(tx.tx)
		transactionsToInclude = append(transactionsToInclude, primitives.ShardTransaction{
			TransactionData: tx.tx,
		})
		err = transactionTreeCache.Flush()
		if err != nil {
			return nil, 0, err
		}
		_, txVerifications, txUpdates := trackingTree.GetWitnesses()
		updates = append(updates, txUpdates...)
		verifications = append(verifications, txVerifications...)
	}
	endHash := primitives.EmptyTree
	err = packageTreeCache.View(func(tx csmt.TreeDatabaseTransaction) error {
		rootNode, err := tx.Root()
		if err != nil {
			return err
		}
		if rootNode != nil {
			endHash = rootNode.GetHash()
		}
		return nil
	})
	if err != nil {
		return nil, 0, err
	}
	txPackage := &primitives.TransactionPackage{
		StartRoot:     startRoot,
		EndRoot:       endHash,
		Updates:       updates,
		Verifications: verifications,
		Transactions:  transactionsToInclude,
	}
	return txPackage, startSlot, nil
}