func Get(assetId transactionrecord.AssetIdentifier) transactionrecord.Packed {
	globalData.RLock()
	item := globalData.cache[assetId]
	globalData.RUnlock()
	if nil == item {
		return nil
	}
	return item.packed
}
Get - get packed asset data from cache (nil if not present)
package asset
import (
	"sync"
	"sync/atomic"
	"github.com/bitmark-inc/bitmarkd/background"
	"github.com/bitmark-inc/bitmarkd/fault"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/storage"
	"github.com/bitmark-inc/bitmarkd/transactionrecord"
	"github.com/bitmark-inc/logger"
)
type assetState int
const (
	pendingState assetState = iota
	expiringState
	verifiedState
)
type cacheData struct {
	packed transactionrecord.Packed  
	state  assetState                
	ttl    uint64                    
}
type expiryData struct {
	log   *logger.L
	queue chan transactionrecord.AssetIdentifier
}
type globalDataType struct {
	sync.RWMutex
	log        *logger.L
	expiry     expiryData
	background *background.T
	cache      map[transactionrecord.AssetIdentifier]*cacheData
	initialised bool
}
var globalData globalDataType
func Initialise() error {
	globalData.Lock()
	defer globalData.Unlock()
	if globalData.initialised {
		return fault.AlreadyInitialised
	}
	globalData.log = logger.New("asset")
	globalData.log.Info("starting…")
	globalData.expiry.log = logger.New("asset-expiry")
	globalData.expiry.queue = make(chan transactionrecord.AssetIdentifier, 10)
	globalData.cache = make(map[transactionrecord.AssetIdentifier]*cacheData)
	globalData.initialised = true
	globalData.log.Info("start background…")
	processes := background.Processes{
		&globalData.expiry,
	}
	globalData.background = background.Start(processes, globalData.log)
	return nil
}
func Finalise() error {
	if !globalData.initialised {
		return fault.NotInitialised
	}
	globalData.log.Info("shutting down…")
	globalData.log.Flush()
	globalData.background.Stop()
	globalData.initialised = false
	globalData.log.Info("finished")
	globalData.log.Flush()
	return nil
}
func Cache(asset *transactionrecord.AssetData, assetHandle storage.Handle) (*transactionrecord.AssetIdentifier, transactionrecord.Packed, error) {
	if nil == assetHandle {
		return nil, transactionrecord.Packed{}, fault.NilPointer
	}
	packedAsset, err := asset.Pack(asset.Registrant)
	if nil != err {
		return nil, nil, err
	}
	_, _, err = transactionrecord.Packed(packedAsset).Unpack(mode.IsTesting())
	if nil != err {
		return nil, nil, err
	}
	assetId := asset.AssetId()
	if assetHandle.Has(assetId[:]) {
		return &assetId, nil, nil
	}
	d := &cacheData{
		packed: packedAsset,
		state:  pendingState,
	}
	dataWouldChange := false
	globalData.Lock()
	if r, ok := globalData.cache[assetId]; !ok {
		globalData.cache[assetId] = d
	} else {
		transaction, _, err := transactionrecord.Packed(r.packed).Unpack(mode.IsTesting())
		logger.PanicIfError("asset: bad packed record", err)
		switch tx := transaction.(type) {
		case *transactionrecord.AssetData:
			if tx.Name == asset.Name &&
				tx.Fingerprint == asset.Fingerprint &&
				tx.Metadata == asset.Metadata &&
				tx.Registrant.String() == asset.Registrant.String() {
				r.state = pendingState  
				packedAsset = nil       
			} else {
				dataWouldChange = true
			}
		default:
			logger.Panicf("asset: non asset record in cache: %v", tx)
		}
	}
	globalData.Unlock()
	if dataWouldChange {
		return nil, nil, fault.AssetsAlreadyRegistered
	}
	globalData.expiry.queue <- assetId
	return &assetId, packedAsset, nil
}
func Exists(assetId transactionrecord.AssetIdentifier, assetHandle storage.Handle) bool {
	if nil == assetHandle {
		return false
	}
	if assetHandle.Has(assetId[:]) {
		return true
	}
	globalData.RLock()
	_, ok := globalData.cache[assetId]
	globalData.RUnlock()
	return ok
}