func (m *DB) LayerBlockIds(index types.LayerID) ([]types.BlockID, error) {
	layerBuf := index.Bytes()
	zero := false
	ids := []types.BlockID{}
	it := m.layers.Find(layerBuf)
	defer it.Release()
	for it.Next() {
		if len(it.Key()) == len(layerBuf) {
			zero = true
			continue
		}
		var id types.BlockID
		copy(id[:], it.Key()[len(layerBuf):])
		ids = append(ids, id)
	}
	if it.Error() != nil {
		return nil, fmt.Errorf("iterator: %w", it.Error())
	}
	if zero || len(ids) > 0 {
		return ids, nil
	}
	return nil, database.ErrNotFound
}
LayerBlockIds retrieves all block ids from a layer by layer index.
package mesh
import (
	"bytes"
	"container/list"
	"context"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"path/filepath"
	"sync"
	"github.com/spacemeshos/go-spacemesh/codec"
	"github.com/spacemeshos/go-spacemesh/common/types"
	"github.com/spacemeshos/go-spacemesh/database"
	"github.com/spacemeshos/go-spacemesh/log"
	"github.com/spacemeshos/go-spacemesh/pendingtxs"
)
type layerMutex struct {
	m            sync.Mutex
	layerWorkers uint32
}
var ErrInvalidLayer = errors.New("layer invalid")
type DB struct {
	log.Log
	blockCache            blockCache
	layers                database.Database
	blocks                database.Database
	transactions          database.Database
	contextualValidity    database.Database
	general               database.Database
	unappliedTxs          database.Database
	inputVector           database.Database
	blockMutex            sync.RWMutex
	orphanBlocks          map[types.LayerID]map[types.BlockID]struct{}
	invalidatedLayers     map[types.LayerID]struct{}  
	coinflips             map[types.LayerID]bool      
	lhMutex               sync.Mutex
	InputVectorBackupFunc func(id types.LayerID) ([]types.BlockID, error)
	exit                  chan struct{}
}
func NewPersistentMeshDB(path string, blockCacheSize int, logger log.Log) (*DB, error) {
	bdb, err := database.NewLDBDatabase(filepath.Join(path, "blocks"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize blocks db: %v", err)
	}
	ldb, err := database.NewLDBDatabase(filepath.Join(path, "layers"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize layers db: %v", err)
	}
	vdb, err := database.NewLDBDatabase(filepath.Join(path, "validity"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize validity db: %v", err)
	}
	tdb, err := database.NewLDBDatabase(filepath.Join(path, "transactions"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize transactions db: %v", err)
	}
	gdb, err := database.NewLDBDatabase(filepath.Join(path, "general"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize general db: %v", err)
	}
	utx, err := database.NewLDBDatabase(filepath.Join(path, "unappliedTxs"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize mesh unappliedTxs db: %v", err)
	}
	iv, err := database.NewLDBDatabase(filepath.Join(path, "inputvector"), 0, 0, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize mesh unappliedTxs db: %v", err)
	}
	ll := &DB{
		Log:                logger,
		blockCache:         newBlockCache(blockCacheSize * layerSize),
		blocks:             bdb,
		layers:             ldb,
		transactions:       tdb,
		general:            gdb,
		contextualValidity: vdb,
		unappliedTxs:       utx,
		inputVector:        iv,
		orphanBlocks:       make(map[types.LayerID]map[types.BlockID]struct{}),
		invalidatedLayers:  make(map[types.LayerID]struct{}),
		coinflips:          make(map[types.LayerID]bool),
		exit:               make(chan struct{}),
	}
	for _, blk := range GenesisLayer().Blocks() {
		ll.Log.With().Info("adding genesis block", blk.ID(), blk.LayerIndex)
		if err = ll.AddBlock(blk); err != nil {
			ll.Log.With().Error("error inserting genesis block to db", blk.ID(), blk.LayerIndex, log.Err(err))
		}
		if err = ll.SaveContextualValidity(blk.ID(), blk.LayerIndex, true); err != nil {
			ll.Log.With().Error("error inserting genesis block to db", blk.ID(), blk.LayerIndex, log.Err(err))
		}
	}
	if err = ll.SaveLayerInputVectorByID(context.Background(), GenesisLayer().Index(), types.BlockIDs(GenesisLayer().Blocks())); err != nil {
		log.With().Error("error inserting genesis input vector to db", GenesisLayer().Index(), log.Err(err))
	}
	return ll, err
}
func (m *DB) PersistentData() bool {
	if _, err := m.general.Get(constLATEST); err == nil {
		m.Info("found data to recover on disk")
		return true
	}
	m.Info("did not find data to recover on disk")
	return false
}
func NewMemMeshDB(logger log.Log) *DB {
	ll := &DB{
		Log:                logger,
		blockCache:         newBlockCache(100 * layerSize),
		blocks:             database.NewMemDatabase(),
		layers:             database.NewMemDatabase(),
		general:            database.NewMemDatabase(),
		contextualValidity: database.NewMemDatabase(),
		transactions:       database.NewMemDatabase(),
		unappliedTxs:       database.NewMemDatabase(),
		inputVector:        database.NewMemDatabase(),
		orphanBlocks:       make(map[types.LayerID]map[types.BlockID]struct{}),
		invalidatedLayers:  make(map[types.LayerID]struct{}),
		coinflips:          make(map[types.LayerID]bool),
		exit:               make(chan struct{}),
	}
	for _, blk := range GenesisLayer().Blocks() {
		_ = ll.AddBlock(blk)
		_ = ll.SaveContextualValidity(blk.ID(), blk.LayerIndex, true)
	}
	if err := ll.SaveLayerInputVectorByID(context.Background(), GenesisLayer().Index(), types.BlockIDs(GenesisLayer().Blocks())); err != nil {
		logger.With().Error("error inserting genesis input vector to db", GenesisLayer().Index(), log.Err(err))
	}
	return ll
}
func (m *DB) Close() {
	close(m.exit)
	m.blocks.Close()
	m.layers.Close()
	m.transactions.Close()
	m.unappliedTxs.Close()
	m.inputVector.Close()
	m.general.Close()
	m.contextualValidity.Close()
}
func (m *DB) Blocks() database.Getter {
	m.blockMutex.RLock()
	defer m.blockMutex.RUnlock()
	return NewBlockFetcherDB(m)
}
func (m *DB) Transactions() database.Getter {
	return m.transactions
}
var ErrAlreadyExist = errors.New("block already exists in database")
func (m *DB) AddBlock(bl *types.Block) error {
	m.blockMutex.Lock()
	defer m.blockMutex.Unlock()
	if _, err := m.getBlockBytes(bl.ID()); err == nil {
		m.With().Warning(ErrAlreadyExist.Error(), bl.ID())
		return ErrAlreadyExist
	}
	if err := m.writeBlock(bl); err != nil {
		return fmt.Errorf("write block: %w", err)
	}
	return nil
}
func (m *DB) GetBlock(id types.BlockID) (*types.Block, error) {
	if blkh := m.blockCache.Get(id); blkh != nil {
		return blkh, nil
	}
	b, err := m.getBlockBytes(id)
	if err != nil {
		return nil, err
	}
	mbk := &types.DBBlock{}
	if err := types.BytesToInterface(b, mbk); err != nil {
		return nil, fmt.Errorf("parse block: %w", err)
	}
	return mbk.ToBlock(), nil
}
func (m *DB) LayerBlocks(index types.LayerID) ([]*types.Block, error) {
	ids, err := m.LayerBlockIds(index)
	if err != nil {
		return nil, fmt.Errorf("layer block IDs: %w", err)
	}
	blocks := make([]*types.Block, 0, len(ids))
	for _, k := range ids {
		block, err := m.GetBlock(k)
		if err != nil {
			return nil, fmt.Errorf("could not retrieve block %s %s", k.String(), err)
		}
		blocks = append(blocks, block)
	}
	return blocks, nil
}
func (m *DB) ForBlockInView(view map[types.BlockID]struct{}, layer types.LayerID, blockHandler func(block *types.Block) (bool, error)) error {
	blocksToVisit := list.New()
	for id := range view {
		blocksToVisit.PushBack(id)
	}
	seenBlocks := make(map[types.BlockID]struct{})
	for blocksToVisit.Len() > 0 {
		block, err := m.GetBlock(blocksToVisit.Remove(blocksToVisit.Front()).(types.BlockID))
		if err != nil {
			return fmt.Errorf("get block: %w", err)
		}
		if block.LayerIndex.Before(layer) {
			continue
		}
		stop, err := blockHandler(block)
		if err != nil {
			return fmt.Errorf("block handler: %w", err)
		}
		if stop {
			m.Log.With().Debug("ForBlockInView stopped", block.ID())
			break
		}
		if block.LayerIndex == layer {
			continue
		}
		for _, id := range append(block.ForDiff, append(block.AgainstDiff, block.NeutralDiff...)...) {
			if _, found := seenBlocks[id]; !found {
				seenBlocks[id] = struct{}{}
				blocksToVisit.PushBack(id)
			}
		}
	}
	return nil
}