github.com/aychain/blockbook@v0.1.1-0.20181121092459-6d1fc7e07c5b/bchain/mempool_nonutxo.go (about)

     1  package bchain
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/golang/glog"
     8  )
     9  
    10  // NonUTXOMempool is mempool handle of non UTXO chains
    11  type NonUTXOMempool struct {
    12  	chain           BlockChain
    13  	mux             sync.Mutex
    14  	txToInputOutput map[string][]addrIndex
    15  	addrDescToTx    map[string][]outpoint
    16  }
    17  
    18  // NewNonUTXOMempool creates new mempool handler.
    19  func NewNonUTXOMempool(chain BlockChain) *NonUTXOMempool {
    20  	return &NonUTXOMempool{chain: chain}
    21  }
    22  
    23  // GetTransactions returns slice of mempool transactions for given address
    24  func (m *NonUTXOMempool) GetTransactions(address string) ([]string, error) {
    25  	parser := m.chain.GetChainParser()
    26  	addrDesc, err := parser.GetAddrDescFromAddress(address)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	return m.GetAddrDescTransactions(addrDesc)
    31  }
    32  
    33  // GetAddrDescTransactions returns slice of mempool transactions for given address descriptor
    34  func (m *NonUTXOMempool) GetAddrDescTransactions(addrDesc AddressDescriptor) ([]string, error) {
    35  	m.mux.Lock()
    36  	defer m.mux.Unlock()
    37  	outpoints := m.addrDescToTx[string(addrDesc)]
    38  	txs := make([]string, 0, len(outpoints))
    39  	for _, o := range outpoints {
    40  		txs = append(txs, o.txid)
    41  	}
    42  	return txs, nil
    43  }
    44  
    45  func (m *NonUTXOMempool) updateMappings(newTxToInputOutput map[string][]addrIndex, newAddrDescToTx map[string][]outpoint) {
    46  	m.mux.Lock()
    47  	defer m.mux.Unlock()
    48  	m.txToInputOutput = newTxToInputOutput
    49  	m.addrDescToTx = newAddrDescToTx
    50  }
    51  
    52  // Resync gets mempool transactions and maps outputs to transactions.
    53  // Resync is not reentrant, it should be called from a single thread.
    54  // Read operations (GetTransactions) are safe.
    55  func (m *NonUTXOMempool) Resync(onNewTxAddr OnNewTxAddrFunc) (int, error) {
    56  	start := time.Now()
    57  	glog.V(1).Info("Mempool: resync")
    58  	txs, err := m.chain.GetMempool()
    59  	if err != nil {
    60  		return 0, err
    61  	}
    62  	parser := m.chain.GetChainParser()
    63  	// allocate slightly larger capacity of the maps
    64  	newTxToInputOutput := make(map[string][]addrIndex, len(m.txToInputOutput)+5)
    65  	newAddrDescToTx := make(map[string][]outpoint, len(m.addrDescToTx)+5)
    66  	for _, txid := range txs {
    67  		io, exists := m.txToInputOutput[txid]
    68  		if !exists {
    69  			tx, err := m.chain.GetTransactionForMempool(txid)
    70  			if err != nil {
    71  				glog.Error("cannot get transaction ", txid, ": ", err)
    72  				continue
    73  			}
    74  			io = make([]addrIndex, 0, len(tx.Vout)+len(tx.Vin))
    75  			for _, output := range tx.Vout {
    76  				addrDesc, err := parser.GetAddrDescFromVout(&output)
    77  				if err != nil {
    78  					if err != ErrAddressMissing {
    79  						glog.Error("error in output addrDesc in ", txid, " ", output.N, ": ", err)
    80  					}
    81  					continue
    82  				}
    83  				if len(addrDesc) > 0 {
    84  					io = append(io, addrIndex{string(addrDesc), int32(output.N)})
    85  				}
    86  				if onNewTxAddr != nil {
    87  					onNewTxAddr(tx.Txid, addrDesc, true)
    88  				}
    89  			}
    90  			for _, input := range tx.Vin {
    91  				for i, a := range input.Addresses {
    92  					if len(a) > 0 {
    93  						addrDesc, err := parser.GetAddrDescFromAddress(a)
    94  						if err != nil {
    95  							glog.Error("error in input addrDesc in ", txid, " ", a, ": ", err)
    96  							continue
    97  						}
    98  						io = append(io, addrIndex{string(addrDesc), int32(^i)})
    99  						if onNewTxAddr != nil {
   100  							onNewTxAddr(tx.Txid, addrDesc, false)
   101  						}
   102  					}
   103  				}
   104  			}
   105  		}
   106  		newTxToInputOutput[txid] = io
   107  		for _, si := range io {
   108  			newAddrDescToTx[si.addrDesc] = append(newAddrDescToTx[si.addrDesc], outpoint{txid, si.n})
   109  		}
   110  	}
   111  	m.updateMappings(newTxToInputOutput, newAddrDescToTx)
   112  	glog.Info("Mempool: resync finished in ", time.Since(start), ", ", len(m.txToInputOutput), " transactions in mempool")
   113  	return len(m.txToInputOutput), nil
   114  }