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 }