github.com/viacoin/blockbook@v0.3.2-0.20200124170434-77b4f2555a4b/db/txcache.go (about)

     1  package db
     2  
     3  import (
     4  	"blockbook/bchain"
     5  	"blockbook/bchain/coins/eth"
     6  	"blockbook/common"
     7  
     8  	"github.com/golang/glog"
     9  	"github.com/juju/errors"
    10  )
    11  
    12  // TxCache is handle to TxCacheServer
    13  type TxCache struct {
    14  	db        *RocksDB
    15  	chain     bchain.BlockChain
    16  	metrics   *common.Metrics
    17  	is        *common.InternalState
    18  	enabled   bool
    19  	chainType bchain.ChainType
    20  }
    21  
    22  // NewTxCache creates new TxCache interface and returns its handle
    23  func NewTxCache(db *RocksDB, chain bchain.BlockChain, metrics *common.Metrics, is *common.InternalState, enabled bool) (*TxCache, error) {
    24  	if !enabled {
    25  		glog.Info("txcache: disabled")
    26  	}
    27  	return &TxCache{
    28  		db:        db,
    29  		chain:     chain,
    30  		metrics:   metrics,
    31  		is:        is,
    32  		enabled:   enabled,
    33  		chainType: chain.GetChainParser().GetChainType(),
    34  	}, nil
    35  }
    36  
    37  // GetTransaction returns transaction either from RocksDB or if not present from blockchain
    38  // it the transaction is confirmed, it is stored in the RocksDB
    39  func (c *TxCache) GetTransaction(txid string) (*bchain.Tx, int, error) {
    40  	var tx *bchain.Tx
    41  	var h uint32
    42  	var err error
    43  	if c.enabled {
    44  		tx, h, err = c.db.GetTx(txid)
    45  		if err != nil {
    46  			return nil, 0, err
    47  		}
    48  		if tx != nil {
    49  			// number of confirmations is not stored in cache, they change all the time
    50  			_, bestheight, _ := c.is.GetSyncState()
    51  			tx.Confirmations = bestheight - h + 1
    52  			c.metrics.TxCacheEfficiency.With(common.Labels{"status": "hit"}).Inc()
    53  			return tx, int(h), nil
    54  		}
    55  	}
    56  	tx, err = c.chain.GetTransaction(txid)
    57  	if err != nil {
    58  		return nil, 0, err
    59  	}
    60  	c.metrics.TxCacheEfficiency.With(common.Labels{"status": "miss"}).Inc()
    61  	// cache only confirmed transactions
    62  	if tx.Confirmations > 0 {
    63  		if c.chainType == bchain.ChainBitcoinType {
    64  			ta, err := c.db.GetTxAddresses(txid)
    65  			if err != nil {
    66  				return nil, 0, err
    67  			}
    68  			switch {
    69  			case ta == nil:
    70  				// the transaction may not yet be indexed, in that case:
    71  				if tx.BlockHeight > 0 {
    72  					// Check if the tx height value is set.
    73  					h = tx.BlockHeight
    74  				} else {
    75  					// Get the height from the backend's bestblock.
    76  					h, err = c.chain.GetBestBlockHeight()
    77  					if err != nil {
    78  						return nil, 0, err
    79  					}
    80  				}
    81  			default:
    82  				h = ta.Height
    83  			}
    84  		} else if c.chainType == bchain.ChainEthereumType {
    85  			h, err = eth.GetHeightFromTx(tx)
    86  			if err != nil {
    87  				return nil, 0, err
    88  			}
    89  		} else {
    90  			return nil, 0, errors.New("Unknown chain type")
    91  		}
    92  		if c.enabled {
    93  			err = c.db.PutTx(tx, h, tx.Blocktime)
    94  			// do not return caching error, only log it
    95  			if err != nil {
    96  				glog.Error("PutTx error ", err)
    97  			}
    98  		}
    99  	} else {
   100  		return tx, -1, nil
   101  	}
   102  	return tx, int(h), nil
   103  }