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