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  }