func (t *BadgerStoreTxn) AddUncheckedBlock(parentHash block.Hash, blk block.Block, kind UncheckedKind) error {
	blockBytes, err := blk.MarshalBinary()
	if err != nil {
		return err
	}
	var key [1 + block.HashSize]byte
	key[0] = uncheckedKindToPrefix(kind)
	copy(key[1:], parentHash[:])
	if _, err := t.txn.Get(key[:]); err != nil && err != badger.ErrKeyNotFound {
		return err
	} else if err == nil {
		return ErrBlockExists
	}
	return t.txn.SetEntry(badger.NewEntry(key[:], blockBytes).WithMeta(blk.ID()))
}
AddUncheckedBlock adds the given block to the database.
package store
import (
	"errors"
	"os"
	"github.com/alexbakker/gonano/nano"
	"github.com/alexbakker/gonano/nano/block"
	"github.com/dgraph-io/badger"
	badgerOpts "github.com/dgraph-io/badger/options"
)
const (
	idPrefixBlock byte = iota
	idPrefixUncheckedBlockPrevious
	idPrefixUncheckedBlockSource
	idPrefixAddress
	idPrefixFrontier
	idPrefixPending
	idPrefixRepresentation
)
const (
	badgerMaxOps = 10000
)
type BadgerStore struct {
	db *badger.DB
}
type BadgerStoreTxn struct {
	txn *badger.Txn
	db  *badger.DB
	ops uint64
}
func NewBadgerStore(dir string) (*BadgerStore, error) {
	opts := badger.DefaultOptions(dir)
	opts.ValueLogLoadingMode = badgerOpts.FileIO
	if _, err := os.Stat(dir); err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}
		if err := os.Mkdir(dir, 0700); err != nil {
			return nil, err
		}
	}
	db, err := badger.Open(opts)
	if err != nil {
		return nil, err
	}
	return &BadgerStore{db: db}, nil
}
func (s *BadgerStore) Close() error {
	return s.db.Close()
}
func (s *BadgerStore) View(fn func(txn StoreTxn) error) error {
	return s.db.View(func(txn *badger.Txn) error {
		return fn(&BadgerStoreTxn{txn: txn, db: s.db})
	})
}
func (s *BadgerStore) Update(fn func(txn StoreTxn) error) error {
	t := &BadgerStoreTxn{txn: s.db.NewTransaction(true), db: s.db}
	defer t.txn.Discard()
	if err := fn(t); err != nil {
		return err
	}
	return t.txn.Commit()
}
func (t *BadgerStoreTxn) set(key []byte, val []byte) error {
	if err := t.txn.Set(key, val); err != nil {
		return err
	}
	t.ops++
	return nil
}
func (t *BadgerStoreTxn) setWithMeta(key []byte, val []byte, meta byte) error {
	if err := t.txn.SetEntry(badger.NewEntry(key, val).WithMeta(meta)); err != nil {
		return err
	}
	t.ops++
	return nil
}
func (t *BadgerStoreTxn) delete(key []byte) error {
	if err := t.txn.Delete(key); err != nil {
		return err
	}
	t.ops++
	return nil
}
func (t *BadgerStoreTxn) Empty() (bool, error) {
	opts := badger.DefaultIteratorOptions
	opts.PrefetchValues = false
	it := t.txn.NewIterator(opts)
	defer it.Close()
	prefix := [...]byte{idPrefixBlock}
	for it.Seek(prefix[:]); it.ValidForPrefix(prefix[:]); it.Next() {
		return false, nil
	}
	return true, nil
}
func (t *BadgerStoreTxn) Flush() error {
	if t.ops >= badgerMaxOps {
		if err := t.txn.Commit(); err != nil {
			return err
		}
		t.ops = 0
		t.txn = t.db.NewTransaction(true)
	}
	return nil
}
func (t *BadgerStoreTxn) AddBlock(blk block.Block) error {
	hash := blk.Hash()
	blockBytes, err := blk.MarshalBinary()
	if err != nil {
		return err
	}
	var key [1 + block.HashSize]byte
	key[0] = idPrefixBlock
	copy(key[1:], hash[:])
	if _, err := t.txn.Get(key[:]); err != nil && err != badger.ErrKeyNotFound {
		return err
	} else if err == nil {
		return ErrBlockExists
	}
	return t.txn.SetEntry(badger.NewEntry(key[:], blockBytes).WithMeta(blk.ID()))
}
func (t *BadgerStoreTxn) GetBlock(hash block.Hash) (block.Block, error) {
	var key [1 + block.HashSize]byte
	key[0] = idPrefixBlock
	copy(key[1:], hash[:])
	item, err := t.txn.Get(key[:])
	if err != nil {
		return nil, err
	}
	blockType := item.UserMeta()
	blockBytes, err := item.ValueCopy(nil)
	if err != nil {
		return nil, err
	}
	blk, err := block.New(blockType)
	if err != nil {
		return nil, err
	}
	if err := blk.UnmarshalBinary(blockBytes); err != nil {
		return nil, err
	}
	return blk, nil
}
func (t *BadgerStoreTxn) DeleteBlock(hash block.Hash) error {
	var key [1 + block.HashSize]byte
	key[0] = idPrefixBlock
	copy(key[1:], hash[:])
	return t.delete(key[:])
}