github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/api/ethereumtype.go (about)

     1  package api
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/golang/glog"
     7  	"github.com/linxGnu/grocksdb"
     8  	"github.com/trezor/blockbook/bchain"
     9  	"github.com/trezor/blockbook/db"
    10  )
    11  
    12  // refetch internal data
    13  var refetchingInternalData = false
    14  var refetchInternalDataMux sync.Mutex
    15  
    16  func (w *Worker) IsRefetchingInternalData() bool {
    17  	refetchInternalDataMux.Lock()
    18  	defer refetchInternalDataMux.Unlock()
    19  	return refetchingInternalData
    20  }
    21  
    22  func (w *Worker) RefetchInternalData() error {
    23  	refetchInternalDataMux.Lock()
    24  	defer refetchInternalDataMux.Unlock()
    25  	if !refetchingInternalData {
    26  		refetchingInternalData = true
    27  		go w.RefetchInternalDataRoutine()
    28  	}
    29  	return nil
    30  }
    31  
    32  const maxNumberOfRetires = 25
    33  
    34  func (w *Worker) incrementRefetchInternalDataRetryCount(ie *db.BlockInternalDataError) {
    35  	wb := grocksdb.NewWriteBatch()
    36  	defer wb.Destroy()
    37  	err := w.db.StoreBlockInternalDataErrorEthereumType(wb, &bchain.Block{
    38  		BlockHeader: bchain.BlockHeader{
    39  			Hash:   ie.Hash,
    40  			Height: ie.Height,
    41  		},
    42  	}, ie.ErrorMessage, ie.Retries+1)
    43  	if err != nil {
    44  		glog.Errorf("StoreBlockInternalDataErrorEthereumType %d %s, error %v", ie.Height, ie.Hash, err)
    45  	} else {
    46  		w.db.WriteBatch(wb)
    47  	}
    48  }
    49  
    50  func (w *Worker) RefetchInternalDataRoutine() {
    51  	internalErrors, err := w.db.GetBlockInternalDataErrorsEthereumType()
    52  	if err == nil {
    53  		for i := range internalErrors {
    54  			ie := &internalErrors[i]
    55  			if ie.Retries >= maxNumberOfRetires {
    56  				glog.Infof("Refetching internal data for %d %s, retries exceeded", ie.Height, ie.Hash)
    57  				continue
    58  			}
    59  			glog.Infof("Refetching internal data for %d %s, retries %d", ie.Height, ie.Hash, ie.Retries)
    60  			block, err := w.chain.GetBlock(ie.Hash, ie.Height)
    61  			var blockSpecificData *bchain.EthereumBlockSpecificData
    62  			if block != nil {
    63  				blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
    64  			}
    65  			if err != nil || block == nil || blockSpecificData == nil || blockSpecificData.InternalDataError != "" {
    66  				glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err)
    67  				// try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success
    68  				// probably something to do with data preloaded to cache on the backend
    69  				block, err = w.chain.GetBlock(ie.Hash, ie.Height)
    70  				if err != nil || block == nil {
    71  					glog.Errorf("Refetching internal data for %d %s, error %v", ie.Height, ie.Hash, err)
    72  					continue
    73  				}
    74  			}
    75  			blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
    76  			if blockSpecificData != nil && blockSpecificData.InternalDataError != "" {
    77  				glog.Errorf("Refetching internal data for %d %s, internal data error %v", ie.Height, ie.Hash, blockSpecificData.InternalDataError)
    78  				w.incrementRefetchInternalDataRetryCount(ie)
    79  			} else {
    80  				err = w.db.ReconnectInternalDataToBlockEthereumType(block)
    81  				if err != nil {
    82  					glog.Errorf("ReconnectInternalDataToBlockEthereumType %d %s, error %v", ie.Height, ie.Hash, err)
    83  				} else {
    84  					glog.Infof("Refetching internal data for %d %s, success", ie.Height, ie.Hash)
    85  				}
    86  			}
    87  		}
    88  	}
    89  	refetchInternalDataMux.Lock()
    90  	refetchingInternalData = false
    91  	refetchInternalDataMux.Unlock()
    92  }