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 }