func writeBlock(f *os.File, tag tagType, txs []*transactionData) error {
	buffer := make([]byte, 0, 65535)
	for _, tx := range txs {
		buffer = append(buffer, tx.packed...)
	}
	return writeRecord(f, tag, buffer)
}
write a tagged block record
package reservoir
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"github.com/bitmark-inc/bitmarkd/asset"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/pay"
	"github.com/bitmark-inc/bitmarkd/transactionrecord"
	"github.com/bitmark-inc/logger"
)
type tagType byte
const (
	taggedBOF         tagType = iota
	taggedEOF         tagType = iota
	taggedTransaction tagType = iota
	taggedProof       tagType = iota
)
var bofData = []byte("bitmark-cache v1.0")
func LoadFromFile(handles Handles) error {
	Disable()
	defer Enable()
	log := globalData.log
	log.Info("starting…")
	f, err := os.Open(globalData.filename)
	if nil != err {
		return err
	}
	defer f.Close()
	tag, packed, err := readRecord(f)
	if nil != err {
		return err
	}
	if taggedBOF != tag {
		return fmt.Errorf("expected BOF: %d but read: %d", taggedBOF, tag)
	}
	if !bytes.Equal(bofData, packed) {
		return fmt.Errorf("expected BOF: %q but read: %q", bofData, packed)
	}
	log.Infof("restore from file: %s", globalData.filename)
restore_loop:
	for {
		tag, packed, err := readRecord(f)
		if nil != err {
			log.Errorf("read record with error: %s\n", err)
			continue restore_loop
		}
		switch tag {
		case taggedEOF:
			break restore_loop
		case taggedTransaction:
			unpacked, _, err := packed.Unpack(mode.IsTesting())
			if nil != err {
				log.Errorf("unable to unpack asset: %s", err)
				continue restore_loop
			}
			restorer, err := NewTransactionRestorer(unpacked, packed, handles)
			if nil != err {
				log.Errorf("create transaction restorer with error: %s", err)
				continue restore_loop
			}
			err = restorer.Restore()
			if nil != err {
				log.Errorf("restore %s with error: %s", restorer, err)
				continue restore_loop
			}
		case taggedProof:
			var payId pay.PayId
			pn := len(payId)
			if len(packed) <= pn {
				log.Errorf("unable to unpack proof: record too short: %d  expected > %d", len(packed), pn)
				continue restore_loop
			}
			copy(payId[:], packed[:pn])
			nonce := packed[pn:]
			tryProof(payId, nonce)
		default:
			msg := fmt.Errorf("abort, read invalid tag: 0x%02x", tag)
			log.Error(msg.Error())
			return msg
		}
	}
	log.Info("restore completed")
	return nil
}
func saveToFile() error {
	globalData.Lock()
	defer globalData.Unlock()
	log := globalData.log
	if !globalData.initialised {
		log.Error("save when not initialised")
		return fault.NotInitialised
	}
	log.Info("saving…")
	f, err := os.OpenFile(globalData.filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	if nil != err {
		return err
	}
	defer f.Close()
	err = writeRecord(f, taggedBOF, bofData)
	if nil != err {
		return err
	}
	err = backupAssets(f)
	if nil != err {
		return err
	}
	for _, item := range globalData.verifiedTransactions {
		err := writeRecord(f, taggedTransaction, item.packed)
		if nil != err {
			return err
		}
	}
	for _, item := range globalData.verifiedFreeIssues {
		err := writeBlock(f, taggedTransaction, item.txs)
		if nil != err {
			return err
		}
		err = writeRecord(f, taggedProof, packProof(item.payId, item.nonce))
		if nil != err {
			return err
		}
	}
	for _, item := range globalData.verifiedPaidIssues {
		err := writeBlock(f, taggedTransaction, item.txs)
		if nil != err {
			return err
		}
	}
	for _, item := range globalData.pendingTransactions {
		err := writeRecord(f, taggedTransaction, item.tx.packed)
		if nil != err {
			return err
		}
	}
	for _, item := range globalData.pendingFreeIssues {
		err := writeBlock(f, taggedTransaction, item.txs)
		if nil != err {
			return err
		}
		err = writeRecord(f, taggedProof, packProof(item.payId, item.nonce))
		if nil != err {
			return err
		}
	}
	for _, item := range globalData.pendingPaidIssues {
		err := writeBlock(f, taggedTransaction, item.txs)
		if nil != err {
			return err
		}
	}
	err = writeRecord(f, taggedEOF, []byte("EOF"))
	if nil != err {
		return err
	}
	log.Info("save completed")
	return nil
}
func backupAssets(f *os.File) error {
	allAssets := make(map[transactionrecord.AssetIdentifier]struct{})
	for _, item := range globalData.verifiedFreeIssues {
		for _, tx := range item.txs {
			if tx, ok := tx.transaction.(*transactionrecord.BitmarkIssue); ok {
				allAssets[tx.AssetId] = struct{}{}
			}
		}
	}
	for _, item := range globalData.verifiedPaidIssues {
		for _, tx := range item.txs {
			if tx, ok := tx.transaction.(*transactionrecord.BitmarkIssue); ok {
				allAssets[tx.AssetId] = struct{}{}
			}
		}
	}
	for _, item := range globalData.pendingFreeIssues {
		for _, tx := range item.txs {
			if tx, ok := tx.transaction.(*transactionrecord.BitmarkIssue); ok {
				allAssets[tx.AssetId] = struct{}{}
			}
		}
	}
	for _, item := range globalData.pendingPaidIssues {
		for _, tx := range item.txs {
			if tx, ok := tx.transaction.(*transactionrecord.BitmarkIssue); ok {
				allAssets[tx.AssetId] = struct{}{}
			}
		}
	}
backup_loop:
	for assetId := range allAssets {
		packedAsset := asset.Get(assetId)
		if nil == packedAsset {
			globalData.log.Errorf("asset [%s]: not in pending buffer", assetId)
			continue backup_loop  
		}
		err := writeRecord(f, taggedTransaction, packedAsset)
		if nil != err {
			return err
		}
	}
	return nil
}
func packProof(payId pay.PayId, nonce PayNonce) []byte {
	lp := len(payId)
	ln := len(nonce)
	packed := make([]byte, lp+ln)
	copy(packed[:], payId[:])
	copy(packed[lp:], nonce[:])
	return packed
}