func (idx *ExistsAddrIndex) addUnconfirmedTx(tx *wire.MsgTx) {
	isSStx, _ := stake.IsSStx(tx)
	for _, txIn := range tx.TxIn {
		if txscript.IsMultisigSigScript(txIn.SignatureScript) {
			rs, err :=
				txscript.MultisigRedeemScriptFromScriptSig(
					txIn.SignatureScript)
			if err != nil {
				continue
			}
			class, addrs, _, err := txscript.ExtractPkScriptAddrs(
				txscript.DefaultScriptVersion, rs, idx.chainParams)
			if err != nil {
				continue
			}
			if class != txscript.MultiSigTy {
				continue
			}
			for _, addr := range addrs {
				k, err := addrToKey(addr, idx.chainParams)
				if err != nil {
					continue
				}
				if _, exists := idx.mpExistsAddr[k]; !exists {
					idx.mpExistsAddr[k] = struct{}{}
				}
			}
		}
	}
	for _, txOut := range tx.TxOut {
		class, addrs, _, err := txscript.ExtractPkScriptAddrs(txOut.Version,
			txOut.PkScript, idx.chainParams)
		if err != nil {
			continue
		}
		if isSStx && class == txscript.NullDataTy {
			addr, err := stake.AddrFromSStxPkScrCommitment(txOut.PkScript,
				idx.chainParams)
			if err != nil {
				continue
			}
			addrs = append(addrs, addr)
		}
		for _, addr := range addrs {
			k, err := addrToKey(addr, idx.chainParams)
			if err != nil {
				continue
			}
			if _, exists := idx.mpExistsAddr[k]; !exists {
				idx.mpExistsAddr[k] = struct{}{}
			}
		}
	}
}
addUnconfirmedTx adds all addresses related to the transaction to the
unconfirmed (memory-only) exists address index.
package indexers
import (
	"sync"
	"github.com/HcashOrg/hcashd/blockchain"
	"github.com/HcashOrg/hcashd/blockchain/stake"
	"github.com/HcashOrg/hcashd/chaincfg"
	"github.com/HcashOrg/hcashd/database"
	"github.com/HcashOrg/hcashd/txscript"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
)
var (
	existsAddressIndexName = "exists address index"
	existsAddrIndexKey = []byte("existsaddridx")
)
type ExistsAddrIndex struct {
	db          database.DB
	chainParams *chaincfg.Params
	unconfirmedLock sync.RWMutex
	mpExistsAddr    map[[addrKeySize]byte]struct{}
}
func NewExistsAddrIndex(db database.DB, chainParams *chaincfg.Params) *ExistsAddrIndex {
	return &ExistsAddrIndex{
		db:           db,
		chainParams:  chainParams,
		mpExistsAddr: make(map[[addrKeySize]byte]struct{}),
	}
}
var _ Indexer = (*ExistsAddrIndex)(nil)
var _ NeedsInputser = (*ExistsAddrIndex)(nil)
func (idx *ExistsAddrIndex) NeedsInputs() bool {
	return false
}
func (idx *ExistsAddrIndex) Init() error {
	return nil
}
func (idx *ExistsAddrIndex) Key() []byte {
	return existsAddrIndexKey
}
func (idx *ExistsAddrIndex) Name() string {
	return existsAddressIndexName
}
func (idx *ExistsAddrIndex) Create(dbTx database.Tx) error {
	_, err := dbTx.Metadata().CreateBucket(existsAddrIndexKey)
	return err
}
func dbPutExistsAddr(bucket database.Bucket, addrKey [addrKeySize]byte) error {
	return bucket.Put(addrKey[:], nil)
}
func (idx *ExistsAddrIndex) existsAddress(bucket database.Bucket, k [addrKeySize]byte) bool {
	if bucket.Get(k[:]) != nil {
		return true
	}
	idx.unconfirmedLock.RLock()
	_, exists := idx.mpExistsAddr[k]
	idx.unconfirmedLock.RUnlock()
	return exists
}
func (idx *ExistsAddrIndex) ExistsAddress(addr hcashutil.Address) (bool, error) {
	k, err := addrToKey(addr, idx.chainParams)
	if err != nil {
		return false, err
	}
	var exists bool
	err = idx.db.View(func(dbTx database.Tx) error {
		meta := dbTx.Metadata()
		existsAddrIndex := meta.Bucket(existsAddrIndexKey)
		exists = existsAddrIndex.Get(k[:]) != nil
		return nil
	})
	if err != nil {
		return false, err
	}
	if !exists {
		idx.unconfirmedLock.RLock()
		_, exists = idx.mpExistsAddr[k]
		idx.unconfirmedLock.RUnlock()
	}
	return exists, nil
}
func (idx *ExistsAddrIndex) ExistsAddresses(addrs []hcashutil.Address) ([]bool, error) {
	exists := make([]bool, len(addrs))
	addrKeys := make([][addrKeySize]byte, len(addrs))
	for i := range addrKeys {
		var err error
		addrKeys[i], err = addrToKey(addrs[i], idx.chainParams)
		if err != nil {
			return nil, err
		}
	}
	err := idx.db.View(func(dbTx database.Tx) error {
		for i := range addrKeys {
			meta := dbTx.Metadata()
			existsAddrIndex := meta.Bucket(existsAddrIndexKey)
			exists[i] = existsAddrIndex.Get(addrKeys[i][:]) != nil
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	idx.unconfirmedLock.RLock()
	for i := range addrKeys {
		if !exists[i] {
			_, exists[i] = idx.mpExistsAddr[addrKeys[i]]
		}
	}
	idx.unconfirmedLock.RUnlock()
	return exists, nil
}
func (idx *ExistsAddrIndex) ConnectBlock(dbTx database.Tx, block, parent *hcashutil.Block, view *blockchain.UtxoViewpoint) error {
	var parentTxs []*hcashutil.Tx
	if approvesParent(block) && block.Height() > 1 {
		parentTxs = parent.Transactions()
	}
	blockTxns := block.STransactions()
	allTxns := append(parentTxs, blockTxns...)
	usedAddrs := make(map[[addrKeySize]byte]struct{})
	for _, tx := range allTxns {
		msgTx := tx.MsgTx()
		isSStx, _ := stake.IsSStx(msgTx)
		for _, txIn := range msgTx.TxIn {
			if txscript.IsMultisigSigScript(txIn.SignatureScript) {
				rs, err :=
					txscript.MultisigRedeemScriptFromScriptSig(
						txIn.SignatureScript)
				if err != nil {
					continue
				}
				class, addrs, _, err := txscript.ExtractPkScriptAddrs(
					txscript.DefaultScriptVersion, rs, idx.chainParams)
				if err != nil {
					continue
				}
				if class != txscript.MultiSigTy {
					continue
				}
				for _, addr := range addrs {
					k, err := addrToKey(addr, idx.chainParams)
					if err != nil {
						continue
					}
					usedAddrs[k] = struct{}{}
				}
			}
		}
		for _, txOut := range tx.MsgTx().TxOut {
			class, addrs, _, err := txscript.ExtractPkScriptAddrs(
				txOut.Version, txOut.PkScript, idx.chainParams)
			if err != nil {
				continue
			}
			if isSStx && class == txscript.NullDataTy {
				addr, err := stake.AddrFromSStxPkScrCommitment(txOut.PkScript,
					idx.chainParams)
				if err != nil {
					continue
				}
				addrs = append(addrs, addr)
			}
			for _, addr := range addrs {
				k, err := addrToKey(addr, idx.chainParams)
				if err != nil {
					continue
				}
				usedAddrs[k] = struct{}{}
			}
		}
	}
	idx.unconfirmedLock.Lock()
	for k := range idx.mpExistsAddr {
		usedAddrs[k] = struct{}{}
	}
	idx.mpExistsAddr = make(map[[addrKeySize]byte]struct{})
	idx.unconfirmedLock.Unlock()
	meta := dbTx.Metadata()
	existsAddrIndex := meta.Bucket(existsAddrIndexKey)
	newUsedAddrs := make(map[[addrKeySize]byte]struct{})
	for k := range usedAddrs {
		if !idx.existsAddress(existsAddrIndex, k) {
			newUsedAddrs[k] = struct{}{}
		}
	}
	for k := range newUsedAddrs {
		err := dbPutExistsAddr(existsAddrIndex, k)
		if err != nil {
			return err
		}
	}
	return nil
}
func (idx *ExistsAddrIndex) DisconnectBlock(dbTx database.Tx, block, parent *hcashutil.Block, view *blockchain.UtxoViewpoint) error {
	return nil
}