blockbook/api/ethereumtype.go
2023-04-13 11:28:52 +02:00

93 lines
3.1 KiB
Go

package api
import (
"sync"
"github.com/golang/glog"
"github.com/linxGnu/grocksdb"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/db"
)
// refetch internal data
var refetchingInternalData = false
var refetchInternalDataMux sync.Mutex
func (w *Worker) IsRefetchingInternalData() bool {
refetchInternalDataMux.Lock()
defer refetchInternalDataMux.Unlock()
return refetchingInternalData
}
func (w *Worker) RefetchInternalData() error {
refetchInternalDataMux.Lock()
defer refetchInternalDataMux.Unlock()
if !refetchingInternalData {
refetchingInternalData = true
go w.RefetchInternalDataRoutine()
}
return nil
}
const maxNumberOfRetires = 25
func (w *Worker) incrementRefetchInternalDataRetryCount(ie *db.BlockInternalDataError) {
wb := grocksdb.NewWriteBatch()
defer wb.Destroy()
err := w.db.StoreBlockInternalDataErrorEthereumType(wb, &bchain.Block{
BlockHeader: bchain.BlockHeader{
Hash: ie.Hash,
Height: ie.Height,
},
}, ie.ErrorMessage, ie.Retries+1)
if err != nil {
glog.Errorf("StoreBlockInternalDataErrorEthereumType %d %s, error %v", ie.Height, ie.Hash, err)
} else {
w.db.WriteBatch(wb)
}
}
func (w *Worker) RefetchInternalDataRoutine() {
internalErrors, err := w.db.GetBlockInternalDataErrorsEthereumType()
if err == nil {
for i := range internalErrors {
ie := &internalErrors[i]
if ie.Retries >= maxNumberOfRetires {
glog.Infof("Refetching internal data for %d %s, retries exceeded", ie.Height, ie.Hash)
continue
}
glog.Infof("Refetching internal data for %d %s, retries %d", ie.Height, ie.Hash, ie.Retries)
block, err := w.chain.GetBlock(ie.Hash, ie.Height)
var blockSpecificData *bchain.EthereumBlockSpecificData
if block != nil {
blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
}
if err != nil || block == nil || blockSpecificData == nil || blockSpecificData.InternalDataError != "" {
glog.Errorf("Refetching internal data for %d %s, error %v, retrying", ie.Height, ie.Hash, err)
// try for second time to fetch the data - the 2nd attempt after the first unsuccessful has many times higher probability of success
// probably something to do with data preloaded to cache on the backend
block, err = w.chain.GetBlock(ie.Hash, ie.Height)
if err != nil || block == nil {
glog.Errorf("Refetching internal data for %d %s, error %v", ie.Height, ie.Hash, err)
continue
}
}
blockSpecificData, _ = block.CoinSpecificData.(*bchain.EthereumBlockSpecificData)
if blockSpecificData != nil && blockSpecificData.InternalDataError != "" {
glog.Errorf("Refetching internal data for %d %s, internal data error %v", ie.Height, ie.Hash, blockSpecificData.InternalDataError)
w.incrementRefetchInternalDataRetryCount(ie)
} else {
err = w.db.ReconnectInternalDataToBlockEthereumType(block)
if err != nil {
glog.Errorf("ReconnectInternalDataToBlockEthereumType %d %s, error %v", ie.Height, ie.Hash, err)
} else {
glog.Infof("Refetching internal data for %d %s, success", ie.Height, ie.Hash)
}
}
}
}
refetchInternalDataMux.Lock()
refetchingInternalData = false
refetchInternalDataMux.Unlock()
}