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