mirror of
https://github.com/luxfi/indexer.git
synced 2026-09-24 00:25:37 +00:00
Co-authored-by: dhrubabasu <[email protected]> Co-authored-by: Patrick O'Grady <[email protected]> Co-authored-by: Stephen <[email protected]>
728 lines
17 KiB
Go
728 lines
17 KiB
Go
package replay
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"sort"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/ava-labs/ortelius/servicesctrl"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/ava-labs/ortelius/db"
|
|
|
|
"github.com/ava-labs/avalanchego/ids"
|
|
avlancheGoUtils "github.com/ava-labs/avalanchego/utils"
|
|
"github.com/ava-labs/coreth/core/types"
|
|
"github.com/ava-labs/ortelius/cfg"
|
|
"github.com/ava-labs/ortelius/modelsc"
|
|
"github.com/ava-labs/ortelius/services"
|
|
"github.com/ava-labs/ortelius/services/indexes/avm"
|
|
"github.com/ava-labs/ortelius/services/indexes/cvm"
|
|
"github.com/ava-labs/ortelius/services/indexes/pvm"
|
|
"github.com/ava-labs/ortelius/stream"
|
|
"github.com/ava-labs/ortelius/stream/consumers"
|
|
"github.com/ava-labs/ortelius/utils"
|
|
)
|
|
|
|
type Replay interface {
|
|
Start() error
|
|
}
|
|
|
|
type ConsumeType uint32
|
|
|
|
var (
|
|
CONSUME ConsumeType = 1
|
|
CONSUMECONSENSUS ConsumeType = 2
|
|
CONSUMEC ConsumeType = 3
|
|
CONSUMECTRC ConsumeType = 4
|
|
CONSUMECLOG ConsumeType = 5
|
|
)
|
|
|
|
type WorkerPacket struct {
|
|
writer services.Consumer
|
|
cwriter *cvm.Writer
|
|
message services.Consumable
|
|
consumeType ConsumeType
|
|
block *modelsc.Block
|
|
}
|
|
|
|
type TxPoolID struct {
|
|
ID string
|
|
}
|
|
|
|
func NewDB(sc *servicesctrl.Control, config *cfg.Config, replayqueuesize int, replayqueuethreads int) Replay {
|
|
return &dbReplay{
|
|
sc: sc,
|
|
config: config,
|
|
counterAdded: utils.NewCounterID(),
|
|
counterWaits: utils.NewCounterID(),
|
|
queueSize: replayqueuesize,
|
|
queueTheads: replayqueuethreads,
|
|
}
|
|
}
|
|
|
|
type dbReplay struct {
|
|
errs *avlancheGoUtils.AtomicInterface
|
|
sc *servicesctrl.Control
|
|
config *cfg.Config
|
|
conns *utils.Connections
|
|
|
|
counterAdded *utils.CounterID
|
|
counterWaits *utils.CounterID
|
|
|
|
queueSize int
|
|
queueTheads int
|
|
|
|
persist db.Persist
|
|
}
|
|
|
|
func (replay *dbReplay) Start() error {
|
|
cfg.PerformUpdates = true
|
|
replay.persist = db.NewPersist()
|
|
|
|
replay.errs = &avlancheGoUtils.AtomicInterface{}
|
|
|
|
worker := utils.NewWorker(replay.queueSize, replay.queueTheads, replay.workerProcessor())
|
|
|
|
waitGroup := new(int64)
|
|
|
|
conns, err := replay.sc.Database()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
replay.conns = conns
|
|
|
|
for _, chainID := range replay.config.Chains {
|
|
err := replay.handleReader(chainID, waitGroup, worker, conns)
|
|
if err != nil {
|
|
log.Fatalln("reader failed", chainID, ":", err.Error())
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = replay.handleCReader(replay.config.CchainID, waitGroup, worker)
|
|
if err != nil {
|
|
log.Fatalln("reader failed", replay.config.CchainID, ":", err.Error())
|
|
return err
|
|
}
|
|
|
|
timeLog := time.Now()
|
|
|
|
logemit := func(waitGroupCnt int64) {
|
|
type CounterValues struct {
|
|
Added int64
|
|
Waits int64
|
|
}
|
|
|
|
ctot := make(map[string]*CounterValues)
|
|
countersValues := replay.counterAdded.Clone()
|
|
for cnter := range countersValues {
|
|
if _, ok := ctot[cnter]; !ok {
|
|
ctot[cnter] = &CounterValues{}
|
|
}
|
|
ctot[cnter].Added = countersValues[cnter]
|
|
}
|
|
countersValues = replay.counterWaits.Clone()
|
|
for cnter := range countersValues {
|
|
if _, ok := ctot[cnter]; !ok {
|
|
ctot[cnter] = &CounterValues{}
|
|
}
|
|
ctot[cnter].Waits = countersValues[cnter]
|
|
}
|
|
|
|
replay.sc.Log.Info("replaying db",
|
|
zap.Int64("wgc", waitGroupCnt),
|
|
zap.Int64("jobs", worker.JobCnt()),
|
|
)
|
|
|
|
var sortedcnters []string
|
|
for cnter := range ctot {
|
|
sortedcnters = append(sortedcnters, cnter)
|
|
}
|
|
sort.Strings(sortedcnters)
|
|
for _, cnter := range sortedcnters {
|
|
if ctot[cnter].Waits != 0 {
|
|
newlogline := fmt.Sprintf("key:%s add:%d wait:%d", cnter, ctot[cnter].Added, ctot[cnter].Waits)
|
|
replay.sc.Log.Info(newlogline)
|
|
}
|
|
}
|
|
}
|
|
|
|
var waitGroupCnt int64
|
|
for {
|
|
waitGroupCnt = atomic.LoadInt64(waitGroup)
|
|
if waitGroupCnt == 0 && worker.JobCnt() == 0 {
|
|
break
|
|
}
|
|
|
|
if time.Since(timeLog).Seconds() > 30 {
|
|
timeLog = time.Now()
|
|
logemit(waitGroupCnt)
|
|
}
|
|
|
|
time.Sleep(time.Second)
|
|
}
|
|
|
|
logemit(waitGroupCnt)
|
|
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Error("replaying db failed",
|
|
zap.Error(err),
|
|
)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) handleCReader(chain string, waitGroup *int64, worker utils.Worker) error {
|
|
writer, err := cvm.NewWriter(replay.config.NetworkID, chain)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = replay.startCchain(chain, waitGroup, worker, writer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = replay.startCchainTrc(chain, waitGroup, worker, writer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = replay.startCchainLog(chain, waitGroup, worker, writer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) handleReader(chain cfg.Chain, waitGroup *int64, worker utils.Worker, conns *utils.Connections) error {
|
|
var err error
|
|
var writer services.Consumer
|
|
switch chain.VMType {
|
|
case consumers.IndexerAVMName:
|
|
writer, err = avm.NewWriter(replay.config.NetworkID, chain.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case consumers.IndexerPVMName:
|
|
writer, err = pvm.NewWriter(replay.config.NetworkID, chain.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return fmt.Errorf("unknown vmtype")
|
|
}
|
|
|
|
{
|
|
tn := fmt.Sprintf("%d-%s", replay.config.NetworkID, chain.ID)
|
|
replay.sc.Log.Info("starting bootstrap replay",
|
|
zap.String("topic", tn),
|
|
)
|
|
ctx := context.Background()
|
|
err := writer.Bootstrap(ctx, conns, replay.persist)
|
|
replay.sc.Log.Info("finished bootstrap replay",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = replay.startDecision(chain, waitGroup, worker, writer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = replay.startConsensus(chain, waitGroup, worker, writer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) workerProcessor() func(int, interface{}) {
|
|
return func(_ int, valuei interface{}) {
|
|
ctx := context.Background()
|
|
|
|
switch value := valuei.(type) {
|
|
case *WorkerPacket:
|
|
var consumererr error
|
|
switch value.consumeType {
|
|
case CONSUME:
|
|
rsleep := utils.NewRetrySleeper(1, 100*time.Millisecond, time.Second)
|
|
for {
|
|
consumererr = value.writer.Consume(ctx, replay.conns, value.message, replay.persist)
|
|
if !utils.ErrIsLockError(consumererr) {
|
|
break
|
|
}
|
|
rsleep.Inc()
|
|
}
|
|
if consumererr != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
case CONSUMECONSENSUS:
|
|
rsleep := utils.NewRetrySleeper(1, 100*time.Millisecond, time.Second)
|
|
for {
|
|
consumererr = value.writer.ConsumeConsensus(ctx, replay.conns, value.message, replay.persist)
|
|
if !utils.ErrIsLockError(consumererr) {
|
|
break
|
|
}
|
|
rsleep.Inc()
|
|
}
|
|
if consumererr != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
case CONSUMEC:
|
|
rsleep := utils.NewRetrySleeper(1, 100*time.Millisecond, time.Second)
|
|
for {
|
|
consumererr = value.cwriter.Consume(ctx, replay.conns, value.message, value.block, replay.persist)
|
|
if !utils.ErrIsLockError(consumererr) {
|
|
break
|
|
}
|
|
rsleep.Inc()
|
|
}
|
|
if consumererr != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
case CONSUMECTRC:
|
|
transactionTrace := &modelsc.TransactionTrace{}
|
|
err := json.Unmarshal(value.message.Body(), transactionTrace)
|
|
if err != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
rsleep := utils.NewRetrySleeper(1, 100*time.Millisecond, time.Second)
|
|
for {
|
|
consumererr = value.cwriter.ConsumeTrace(ctx, replay.conns, value.message, transactionTrace, replay.persist)
|
|
if !utils.ErrIsLockError(consumererr) {
|
|
break
|
|
}
|
|
rsleep.Inc()
|
|
}
|
|
if consumererr != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
case CONSUMECLOG:
|
|
txLogs := &types.Log{}
|
|
err := json.Unmarshal(value.message.Body(), txLogs)
|
|
if err != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
rsleep := utils.NewRetrySleeper(1, 100*time.Millisecond, time.Second)
|
|
for {
|
|
consumererr = value.cwriter.ConsumeLogs(ctx, replay.conns, value.message, txLogs, replay.persist)
|
|
if !utils.ErrIsLockError(consumererr) {
|
|
break
|
|
}
|
|
rsleep.Inc()
|
|
}
|
|
if consumererr != nil {
|
|
replay.errs.SetValue(consumererr)
|
|
return
|
|
}
|
|
}
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
func (replay *dbReplay) startCchain(chain string, waitGroup *int64, worker utils.Worker, writer *cvm.Writer) error {
|
|
tn := fmt.Sprintf("%d-%s-cchain", replay.config.NetworkID, chain)
|
|
|
|
replay.counterWaits.Inc(tn)
|
|
replay.counterAdded.Add(tn, 0)
|
|
|
|
atomic.AddInt64(waitGroup, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(waitGroup, -1)
|
|
defer replay.counterWaits.Add(tn, -1)
|
|
|
|
job := replay.conns.Stream().NewJob("query-replay-txpoll")
|
|
sess := replay.conns.DB().NewSessionForEventReceiver(job)
|
|
|
|
ctx := context.Background()
|
|
var txPools []TxPoolID
|
|
_, err := sess.Select("id").
|
|
From(db.TableTxPool).
|
|
Where("topic=?", tn).
|
|
OrderAsc("created_at").
|
|
LoadContext(ctx, &txPools)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
for _, txPoolID := range txPools {
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Info("topic replay stopped due to error",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
return
|
|
}
|
|
|
|
txPoolQ := db.TxPool{
|
|
ID: txPoolID.ID,
|
|
}
|
|
var txPool *db.TxPool
|
|
for {
|
|
txPool, err = replay.persist.QueryTxPool(ctx, sess, &txPoolQ)
|
|
if err == nil {
|
|
break
|
|
}
|
|
replay.sc.Log.Warn("topic replay erred",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
id, err := ids.FromString(txPool.MsgKey)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
replay.counterAdded.Inc(tn)
|
|
|
|
block, err := modelsc.Unmarshal(txPool.Serialization)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
if block.BlockExtraData == nil {
|
|
block.BlockExtraData = []byte("")
|
|
}
|
|
|
|
msgc := stream.NewMessage(
|
|
id.String(),
|
|
chain,
|
|
block.BlockExtraData,
|
|
txPool.CreatedAt.UTC().Unix(),
|
|
int64(txPool.CreatedAt.UTC().Nanosecond()),
|
|
)
|
|
|
|
worker.Enque(&WorkerPacket{cwriter: writer, message: msgc, block: block, consumeType: CONSUMEC})
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) startCchainTrc(chain string, waitGroup *int64, worker utils.Worker, writer *cvm.Writer) error {
|
|
tn := fmt.Sprintf("%d-%s-cchain-trc", replay.config.NetworkID, chain)
|
|
|
|
replay.counterWaits.Inc(tn)
|
|
replay.counterAdded.Add(tn, 0)
|
|
|
|
atomic.AddInt64(waitGroup, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(waitGroup, -1)
|
|
defer replay.counterWaits.Add(tn, -1)
|
|
|
|
job := replay.conns.Stream().NewJob("query-replay-txpoll")
|
|
sess := replay.conns.DB().NewSessionForEventReceiver(job)
|
|
|
|
ctx := context.Background()
|
|
var txPools []TxPoolID
|
|
_, err := sess.Select("id").
|
|
From(db.TableTxPool).
|
|
Where("topic=?", tn).
|
|
OrderAsc("created_at").
|
|
LoadContext(ctx, &txPools)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
for _, txPoolID := range txPools {
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Info("topic replay stopped due to error",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
return
|
|
}
|
|
|
|
txPoolQ := db.TxPool{
|
|
ID: txPoolID.ID,
|
|
}
|
|
var txPool *db.TxPool
|
|
for {
|
|
txPool, err = replay.persist.QueryTxPool(ctx, sess, &txPoolQ)
|
|
if err == nil {
|
|
break
|
|
}
|
|
replay.sc.Log.Warn("topic replay erred",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
id, err := ids.FromString(txPool.MsgKey)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
replay.counterAdded.Inc(tn)
|
|
|
|
msgc := stream.NewMessage(
|
|
id.String(),
|
|
chain,
|
|
txPool.Serialization,
|
|
txPool.CreatedAt.UTC().Unix(),
|
|
int64(txPool.CreatedAt.UTC().Nanosecond()),
|
|
)
|
|
|
|
worker.Enque(&WorkerPacket{cwriter: writer, message: msgc, consumeType: CONSUMECTRC})
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) startCchainLog(chain string, waitGroup *int64, worker utils.Worker, writer *cvm.Writer) error {
|
|
tn := fmt.Sprintf("%d-%s-cchain-logs", replay.config.NetworkID, chain)
|
|
|
|
replay.counterWaits.Inc(tn)
|
|
replay.counterAdded.Add(tn, 0)
|
|
|
|
atomic.AddInt64(waitGroup, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(waitGroup, -1)
|
|
defer replay.counterWaits.Add(tn, -1)
|
|
|
|
job := replay.conns.Stream().NewJob("query-replay-txpoll")
|
|
sess := replay.conns.DB().NewSessionForEventReceiver(job)
|
|
|
|
ctx := context.Background()
|
|
var txPools []TxPoolID
|
|
_, err := sess.Select("id").
|
|
From(db.TableTxPool).
|
|
Where("topic=?", tn).
|
|
OrderAsc("created_at").
|
|
LoadContext(ctx, &txPools)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
for _, txPoolID := range txPools {
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Info("topic replay stopped due to error",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
return
|
|
}
|
|
|
|
txPoolQ := db.TxPool{
|
|
ID: txPoolID.ID,
|
|
}
|
|
var txPool *db.TxPool
|
|
for {
|
|
txPool, err = replay.persist.QueryTxPool(ctx, sess, &txPoolQ)
|
|
if err == nil {
|
|
break
|
|
}
|
|
replay.sc.Log.Warn("topic replay erred",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
id, err := ids.FromString(txPool.MsgKey)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
replay.counterAdded.Inc(tn)
|
|
|
|
msgc := stream.NewMessage(
|
|
id.String(),
|
|
chain,
|
|
txPool.Serialization,
|
|
txPool.CreatedAt.UTC().Unix(),
|
|
int64(txPool.CreatedAt.UTC().Nanosecond()),
|
|
)
|
|
|
|
worker.Enque(&WorkerPacket{cwriter: writer, message: msgc, consumeType: CONSUMECLOG})
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) startConsensus(chain cfg.Chain, waitGroup *int64, worker utils.Worker, writer services.Consumer) error {
|
|
tn := stream.GetTopicName(replay.config.NetworkID, chain.ID, stream.EventTypeConsensus)
|
|
|
|
replay.counterWaits.Inc(tn)
|
|
replay.counterAdded.Add(tn, 0)
|
|
|
|
atomic.AddInt64(waitGroup, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(waitGroup, -1)
|
|
defer replay.counterWaits.Add(tn, -1)
|
|
|
|
job := replay.conns.Stream().NewJob("query-replay-txpoll")
|
|
sess := replay.conns.DB().NewSessionForEventReceiver(job)
|
|
|
|
ctx := context.Background()
|
|
var txPools []TxPoolID
|
|
_, err := sess.Select("id").
|
|
From(db.TableTxPool).
|
|
Where("topic=?", tn).
|
|
OrderAsc("created_at").
|
|
LoadContext(ctx, &txPools)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
for _, txPoolID := range txPools {
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Info("topic replay stopped due to error",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
return
|
|
}
|
|
|
|
txPoolQ := db.TxPool{
|
|
ID: txPoolID.ID,
|
|
}
|
|
var txPool *db.TxPool
|
|
for {
|
|
txPool, err = replay.persist.QueryTxPool(ctx, sess, &txPoolQ)
|
|
if err == nil {
|
|
break
|
|
}
|
|
replay.sc.Log.Warn("topic replay erred",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
id, err := ids.FromString(txPool.MsgKey)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
replay.counterAdded.Inc(tn)
|
|
|
|
msgc := stream.NewMessage(
|
|
id.String(),
|
|
chain.ID,
|
|
txPool.Serialization,
|
|
txPool.CreatedAt.UTC().Unix(),
|
|
int64(txPool.CreatedAt.UTC().Nanosecond()),
|
|
)
|
|
|
|
worker.Enque(&WorkerPacket{writer: writer, message: msgc, consumeType: CONSUMECONSENSUS})
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (replay *dbReplay) startDecision(chain cfg.Chain, waitGroup *int64, worker utils.Worker, writer services.Consumer) error {
|
|
tn := stream.GetTopicName(replay.config.NetworkID, chain.ID, stream.EventTypeDecisions)
|
|
|
|
replay.counterWaits.Inc(tn)
|
|
replay.counterAdded.Add(tn, 0)
|
|
|
|
atomic.AddInt64(waitGroup, 1)
|
|
go func() {
|
|
defer atomic.AddInt64(waitGroup, -1)
|
|
defer replay.counterWaits.Add(tn, -1)
|
|
|
|
job := replay.conns.Stream().NewJob("query-replay-txpoll")
|
|
sess := replay.conns.DB().NewSessionForEventReceiver(job)
|
|
|
|
ctx := context.Background()
|
|
var txPools []TxPoolID
|
|
_, err := sess.Select("id").
|
|
From(db.TableTxPool).
|
|
Where("topic=?", tn).
|
|
OrderAsc("created_at").
|
|
LoadContext(ctx, &txPools)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
for _, txPoolID := range txPools {
|
|
if errIntf := replay.errs.GetValue(); errIntf != nil {
|
|
err := errIntf.(error)
|
|
replay.sc.Log.Info("topic replay stopped due to error",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
return
|
|
}
|
|
|
|
txPoolQ := db.TxPool{
|
|
ID: txPoolID.ID,
|
|
}
|
|
var txPool *db.TxPool
|
|
for {
|
|
txPool, err = replay.persist.QueryTxPool(ctx, sess, &txPoolQ)
|
|
if err == nil {
|
|
break
|
|
}
|
|
replay.sc.Log.Warn("topic replay erred",
|
|
zap.String("topic", tn),
|
|
zap.Error(err),
|
|
)
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
id, err := ids.FromString(txPool.MsgKey)
|
|
if err != nil {
|
|
replay.errs.SetValue(err)
|
|
return
|
|
}
|
|
|
|
replay.counterAdded.Inc(tn)
|
|
|
|
msgc := stream.NewMessage(
|
|
id.String(),
|
|
chain.ID,
|
|
txPool.Serialization,
|
|
txPool.CreatedAt.UTC().Unix(),
|
|
int64(txPool.CreatedAt.UTC().Nanosecond()),
|
|
)
|
|
|
|
worker.Enque(&WorkerPacket{writer: writer, message: msgc, consumeType: CONSUME})
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|