github.com/bchainhub/blockbook@v0.3.2/bchain/mempool_ethereum_type.go (about) 1 package bchain 2 3 import ( 4 "time" 5 6 "github.com/golang/glog" 7 ) 8 9 const mempoolTimeoutRunPeriod = 10 * time.Minute 10 11 // MempoolEthereumType is mempool handle of EthereumType chains 12 type MempoolEthereumType struct { 13 BaseMempool 14 mempoolTimeoutTime time.Duration 15 queryBackendOnResync bool 16 nextTimeoutRun time.Time 17 } 18 19 // NewMempoolEthereumType creates new mempool handler. 20 func NewMempoolEthereumType(chain BlockChain, mempoolTxTimeoutHours int, queryBackendOnResync bool) *MempoolEthereumType { 21 mempoolTimeoutTime := time.Duration(mempoolTxTimeoutHours) * time.Hour 22 return &MempoolEthereumType{ 23 BaseMempool: BaseMempool{ 24 chain: chain, 25 txEntries: make(map[string]txEntry), 26 addrDescToTx: make(map[string][]Outpoint), 27 }, 28 mempoolTimeoutTime: mempoolTimeoutTime, 29 queryBackendOnResync: queryBackendOnResync, 30 nextTimeoutRun: time.Now().Add(mempoolTimeoutTime), 31 } 32 } 33 34 func appendAddress(io []addrIndex, i int32, a string, parser BlockChainParser) []addrIndex { 35 if len(a) > 0 { 36 addrDesc, err := parser.GetAddrDescFromAddress(a) 37 if err != nil { 38 glog.Error("error in input addrDesc in ", a, ": ", err) 39 return io 40 } 41 io = append(io, addrIndex{string(addrDesc), i}) 42 } 43 return io 44 } 45 46 func (m *MempoolEthereumType) createTxEntry(txid string, txTime uint32) (txEntry, bool) { 47 tx, err := m.chain.GetTransactionForMempool(txid) 48 if err != nil { 49 if err != ErrTxNotFound { 50 glog.Warning("cannot get transaction ", txid, ": ", err) 51 } 52 return txEntry{}, false 53 } 54 parser := m.chain.GetChainParser() 55 addrIndexes := make([]addrIndex, 0, len(tx.Vout)+len(tx.Vin)) 56 for _, output := range tx.Vout { 57 addrDesc, err := parser.GetAddrDescFromVout(&output) 58 if err != nil { 59 if err != ErrAddressMissing { 60 glog.Error("error in output addrDesc in ", txid, " ", output.N, ": ", err) 61 } 62 continue 63 } 64 if len(addrDesc) > 0 { 65 addrIndexes = append(addrIndexes, addrIndex{string(addrDesc), int32(output.N)}) 66 } 67 } 68 for _, input := range tx.Vin { 69 for i, a := range input.Addresses { 70 addrIndexes = appendAddress(addrIndexes, ^int32(i), a, parser) 71 } 72 } 73 t, err := parser.EthereumTypeGetErc20FromTx(tx) 74 if err != nil { 75 glog.Error("GetErc20FromTx for tx ", txid, ", ", err) 76 } else { 77 for i := range t { 78 addrIndexes = appendAddress(addrIndexes, ^int32(i+1), t[i].From, parser) 79 addrIndexes = appendAddress(addrIndexes, int32(i+1), t[i].To, parser) 80 } 81 } 82 if m.OnNewTxAddr != nil { 83 sent := make(map[string]struct{}) 84 for _, si := range addrIndexes { 85 if _, found := sent[si.addrDesc]; !found { 86 m.OnNewTxAddr(tx, AddressDescriptor(si.addrDesc)) 87 sent[si.addrDesc] = struct{}{} 88 } 89 } 90 } 91 return txEntry{addrIndexes: addrIndexes, time: txTime}, true 92 } 93 94 // Resync ethereum type removes timed out transactions and returns number of transactions in mempool. 95 // Transactions are added/removed by AddTransactionToMempool/RemoveTransactionFromMempool methods 96 func (m *MempoolEthereumType) Resync() (int, error) { 97 if m.queryBackendOnResync { 98 txs, err := m.chain.GetMempoolTransactions() 99 if err != nil { 100 return 0, err 101 } 102 for _, txid := range txs { 103 m.AddTransactionToMempool(txid) 104 } 105 } 106 m.mux.Lock() 107 entries := len(m.txEntries) 108 now := time.Now() 109 if m.nextTimeoutRun.Before(now) { 110 threshold := now.Add(-m.mempoolTimeoutTime) 111 for txid, entry := range m.txEntries { 112 if time.Unix(int64(entry.time), 0).Before(threshold) { 113 m.removeEntryFromMempool(txid, entry) 114 } 115 } 116 removed := entries - len(m.txEntries) 117 entries = len(m.txEntries) 118 glog.Info("Mempool: cleanup, removed ", removed, " transactions from mempool") 119 m.nextTimeoutRun = now.Add(mempoolTimeoutRunPeriod) 120 } 121 m.mux.Unlock() 122 glog.Info("Mempool: resync ", entries, " transactions in mempool") 123 return entries, nil 124 } 125 126 // AddTransactionToMempool adds transactions to mempool 127 func (m *MempoolEthereumType) AddTransactionToMempool(txid string) { 128 m.mux.Lock() 129 _, exists := m.txEntries[txid] 130 m.mux.Unlock() 131 if glog.V(1) { 132 glog.Info("AddTransactionToMempool ", txid, ", existed ", exists) 133 } 134 if !exists { 135 entry, ok := m.createTxEntry(txid, uint32(time.Now().Unix())) 136 if !ok { 137 return 138 } 139 m.mux.Lock() 140 m.txEntries[txid] = entry 141 for _, si := range entry.addrIndexes { 142 m.addrDescToTx[si.addrDesc] = append(m.addrDescToTx[si.addrDesc], Outpoint{txid, si.n}) 143 } 144 m.mux.Unlock() 145 } 146 } 147 148 // RemoveTransactionFromMempool removes transaction from mempool 149 func (m *MempoolEthereumType) RemoveTransactionFromMempool(txid string) { 150 m.mux.Lock() 151 entry, exists := m.txEntries[txid] 152 if glog.V(1) { 153 glog.Info("RemoveTransactionFromMempool ", txid, ", existed ", exists) 154 } 155 if exists { 156 m.removeEntryFromMempool(txid, entry) 157 } 158 m.mux.Unlock() 159 }