mirror of
https://github.com/grassrootseconomics/eth-tracker.git
synced 2025-06-11 13:10:11 +02:00
feat: refactor historical syncer
This commit is contained in:
parent
f981007e71
commit
9782b3c9c5
@ -94,13 +94,14 @@ func main() {
|
|||||||
|
|
||||||
chainSyncer, err := syncer.New(syncer.SyncerOpts{
|
chainSyncer, err := syncer.New(syncer.SyncerOpts{
|
||||||
WebSocketEndpoint: ko.MustString("chain.ws_endpoint"),
|
WebSocketEndpoint: ko.MustString("chain.ws_endpoint"),
|
||||||
|
EnableHistorical: ko.Bool("chain.historical"),
|
||||||
|
StartBlock: uint64(ko.MustInt64("bootstrap.start_block")),
|
||||||
BatchQueue: &batchQueue,
|
BatchQueue: &batchQueue,
|
||||||
BlocksQueue: &blocksQueue,
|
BlocksQueue: &blocksQueue,
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
Logg: lo,
|
Logg: lo,
|
||||||
Stats: stats,
|
Stats: stats,
|
||||||
DB: db,
|
DB: db,
|
||||||
InitialLowerBound: uint64(ko.MustInt64("bootstrap.start_block")),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lo.Error("could not initialize chain syncer", "error", err)
|
lo.Error("could not initialize chain syncer", "error", err)
|
||||||
@ -114,7 +115,9 @@ func main() {
|
|||||||
cache, err := cache.New(cache.CacheOpts{
|
cache, err := cache.New(cache.CacheOpts{
|
||||||
Logg: lo,
|
Logg: lo,
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
Registries: ko.MustStrings("bootstrap.registries"),
|
Registries: ko.MustStrings("bootstrap.ge_registries"),
|
||||||
|
Blacklist: ko.MustStrings("bootstrap.blacklist"),
|
||||||
|
Watchlist: ko.MustStrings("bootstrap.watchlist"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lo.Error("could not initialize cache", "error", err)
|
lo.Error("could not initialize cache", "error", err)
|
||||||
|
@ -6,14 +6,17 @@ address = ":5001"
|
|||||||
|
|
||||||
[chain]
|
[chain]
|
||||||
ws_endpoint = "wss://ws.celo.grassecon.net"
|
ws_endpoint = "wss://ws.celo.grassecon.net"
|
||||||
rpc_endpoint = "https://rpc.ankr.com/celo/bae2b7745f52c50974d7ecb1a7c23dc05d9ab5b68caf498a7c73f09a3e8bc04a"
|
rpc_endpoint = "https://1rpc.io/celo"
|
||||||
testnet = false
|
testnet = false
|
||||||
|
realtime = true
|
||||||
|
historical = false
|
||||||
|
start_block = 24905000
|
||||||
|
|
||||||
[bootstrap]
|
[bootstrap]
|
||||||
start_block = 24905000
|
|
||||||
# https://software.grassecon.org/addresses
|
# https://software.grassecon.org/addresses
|
||||||
registries = [
|
ge_registries = [
|
||||||
"0xd1FB944748aca327a1ba036B082993D9dd9Bfa0C",
|
"0xd1FB944748aca327a1ba036B082993D9dd9Bfa0C",
|
||||||
"0x0cc9f4fff962def35bb34a53691180b13e653030",
|
"0x0cc9f4fff962def35bb34a53691180b13e653030",
|
||||||
]
|
]
|
||||||
|
watchlist = [""]
|
||||||
blacklist = [""]
|
blacklist = [""]
|
||||||
|
2
internal/cache/bootstrap.go
vendored
2
internal/cache/bootstrap.go
vendored
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/grassrootseconomics/w3-celo/module/eth"
|
"github.com/grassrootseconomics/w3-celo/module/eth"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bootstrapAllGESmartContracts(ctx context.Context, registries []string, chain *chain.Chain, cache Cache) (WatchableIndex, error) {
|
func bootstrapGESmartContracts(ctx context.Context, registries []string, chain *chain.Chain, cache Cache) (WatchableIndex, error) {
|
||||||
var (
|
var (
|
||||||
watchableIndex = make(WatchableIndex)
|
watchableIndex = make(WatchableIndex)
|
||||||
)
|
)
|
||||||
|
9
internal/cache/cache.go
vendored
9
internal/cache/cache.go
vendored
@ -25,6 +25,7 @@ type (
|
|||||||
CacheType string
|
CacheType string
|
||||||
Registries []string
|
Registries []string
|
||||||
Blacklist []string
|
Blacklist []string
|
||||||
|
Watchlist []string
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchableIndex map[string]bool
|
WatchableIndex map[string]bool
|
||||||
@ -47,7 +48,7 @@ func New(o CacheOpts) (Cache, error) {
|
|||||||
cache = NewMapCache()
|
cache = NewMapCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
watchableIndex, err := bootstrapAllGESmartContracts(
|
watchableIndex, err := bootstrapGESmartContracts(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
o.Registries,
|
o.Registries,
|
||||||
o.Chain,
|
o.Chain,
|
||||||
@ -56,12 +57,16 @@ func New(o CacheOpts) (Cache, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// We only watch the token and pool indexes
|
||||||
|
// If at some point we want to eatch the user index, this line should be removed
|
||||||
cache.SetWatchableIndex(watchableIndex)
|
cache.SetWatchableIndex(watchableIndex)
|
||||||
|
|
||||||
|
for _, address := range o.Watchlist {
|
||||||
|
cache.Add(address)
|
||||||
|
}
|
||||||
for _, address := range o.Blacklist {
|
for _, address := range o.Blacklist {
|
||||||
cache.Remove(address)
|
cache.Remove(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
o.Logg.Debug("cache bootstrap complete", "cached_addresses", cache.Size())
|
o.Logg.Debug("cache bootstrap complete", "cached_addresses", cache.Size())
|
||||||
|
|
||||||
return cache, nil
|
return cache, nil
|
||||||
|
@ -13,13 +13,11 @@ func (p *Processor) processBlock(ctx context.Context, block types.Block) error {
|
|||||||
blockNumber := block.NumberU64()
|
blockNumber := block.NumberU64()
|
||||||
|
|
||||||
txs, err := p.chain.GetTransactions(ctx, block)
|
txs, err := p.chain.GetTransactions(ctx, block)
|
||||||
p.logg.Debug("successfully fetched transactions", "txs", len(txs))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
receiptsResp, err := p.chain.GetReceipts(ctx, block)
|
receiptsResp, err := p.chain.GetReceipts(ctx, block)
|
||||||
p.logg.Debug("successfully fetched receipts", "receipts", len(txs))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -42,7 +40,7 @@ func (p *Processor) processBlock(ctx context.Context, block types.Block) error {
|
|||||||
if p.cache.Exists(txs[i].To().Hex()) {
|
if p.cache.Exists(txs[i].To().Hex()) {
|
||||||
from, err := types.Sender(types.LatestSignerForChainID(txs[i].ChainId()), &txs[i])
|
from, err := types.Sender(types.LatestSignerForChainID(txs[i].ChainId()), &txs[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logg.Error("hanlder error", "handler_type", "revert", "error", err)
|
p.logg.Error("handler error", "handler_type", "revert", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
revertReason, err := p.chain.GetRevertReason(ctx, receipt.TxHash, receipt.BlockNumber)
|
revertReason, err := p.chain.GetRevertReason(ctx, receipt.TxHash, receipt.BlockNumber)
|
||||||
|
@ -83,7 +83,7 @@ func (p *Processor) Start() {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
time.Sleep(emptyQueueIdleTime)
|
time.Sleep(emptyQueueIdleTime)
|
||||||
p.logg.Debug("queue empty slept for 1 second")
|
p.logg.Debug("processor queue empty slept for 1 second")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,41 +3,31 @@ package syncer
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
"github.com/dgraph-io/badger/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
blockBatchSize = 100
|
blockBatchSize = 100
|
||||||
|
emptyQueueIdelTime = 2 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Syncer) BootstrapHistoricalSyncer() error {
|
func (s *Syncer) BootstrapHistoricalSyncer() error {
|
||||||
v, err := s.db.GetLowerBound()
|
lower, err := s.db.GetLowerBound()
|
||||||
if err != nil {
|
|
||||||
if err == badger.ErrKeyNotFound {
|
|
||||||
if err := s.db.SetLowerBound(s.initialLowerBound); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
v = s.initialLowerBound
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
latestBlock, err := s.chain.GetLatestBlock(context.Background())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := s.db.SetUpperBound(latestBlock); err != nil {
|
|
||||||
|
upper, err := s.db.GetUpperBound()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
missingBlocks, err := s.db.GetMissingValuesBitSet(v, latestBlock)
|
missingBlocks, err := s.db.GetMissingValuesBitSet(lower, upper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
missingBlocksCount := missingBlocks.Count()
|
missingBlocksCount := missingBlocks.Count()
|
||||||
s.logg.Info("bootstrapping historical syncer", "missing_blocks", missingBlocksCount, "lower_bound", v, "upper_bound", latestBlock)
|
s.logg.Info("bootstrapping historical syncer", "missing_blocks", missingBlocksCount, "lower_bound", lower, "upper_bound", upper)
|
||||||
|
|
||||||
buffer := make([]uint, missingBlocksCount)
|
buffer := make([]uint, missingBlocksCount)
|
||||||
missingBlocks.NextSetMany(0, buffer)
|
missingBlocks.NextSetMany(0, buffer)
|
||||||
@ -48,12 +38,12 @@ func (s *Syncer) BootstrapHistoricalSyncer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Syncer) StartHistoricalSyncer(ctx context.Context) error {
|
func (s *Syncer) StartHistoricalSyncer() error {
|
||||||
s.logg.Info("starting historical syncer", "batch_size", blockBatchSize)
|
s.logg.Info("starting historical syncer", "batch_size", blockBatchSize)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-s.quit:
|
||||||
s.logg.Info("historical syncer shutting down")
|
s.logg.Info("historical syncer stopped")
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
if s.batchQueue.Len() > 0 {
|
if s.batchQueue.Len() > 0 {
|
||||||
@ -78,7 +68,15 @@ func (s *Syncer) StartHistoricalSyncer(ctx context.Context) error {
|
|||||||
for _, v := range blocks {
|
for _, v := range blocks {
|
||||||
s.blocksQueue.PushBack(v)
|
s.blocksQueue.PushBack(v)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
time.Sleep(emptyQueueIdelTime)
|
||||||
|
s.logg.Debug("historical batcher queue empty slept for 2 seconds")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Syncer) StopHistoricalSyncer() {
|
||||||
|
s.logg.Info("signaling historical syncer shutdown")
|
||||||
|
s.quit <- struct{}{}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
resubscribeInterval = 15 * time.Second
|
resubscribeInterval = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Syncer) StartRealtime() {
|
func (s *Syncer) StartRealtime() {
|
||||||
@ -55,7 +55,6 @@ func (s *Syncer) receiveRealtimeBlocks(ctx context.Context, fn BlockQueueFn) (ce
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case header := <-newHeadersReceiver:
|
case header := <-newHeadersReceiver:
|
||||||
s.logg.Debug("received block", "block", header.Number.Uint64())
|
|
||||||
if err := fn(eventsCtx, header.Number.Uint64()); err != nil {
|
if err := fn(eventsCtx, header.Number.Uint64()); err != nil {
|
||||||
if !errors.Is(err, context.Canceled) {
|
if !errors.Is(err, context.Canceled) {
|
||||||
s.logg.Error("realtime block queuer error", "error", err)
|
s.logg.Error("realtime block queuer error", "error", err)
|
||||||
@ -79,7 +78,6 @@ func (s *Syncer) queueRealtimeBlock(ctx context.Context, blockNumber uint64) err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.blocksQueue.PushFront(block)
|
s.blocksQueue.PushFront(block)
|
||||||
s.logg.Debug("queued block", "block", blockNumber)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package syncer
|
package syncer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"context"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/celo-org/celo-blockchain"
|
"github.com/celo-org/celo-blockchain"
|
||||||
@ -16,32 +16,48 @@ import (
|
|||||||
type (
|
type (
|
||||||
SyncerOpts struct {
|
SyncerOpts struct {
|
||||||
WebSocketEndpoint string
|
WebSocketEndpoint string
|
||||||
|
EnableHistorical bool
|
||||||
|
StartBlock uint64
|
||||||
BatchQueue *deque.Deque[uint64]
|
BatchQueue *deque.Deque[uint64]
|
||||||
BlocksQueue *deque.Deque[types.Block]
|
BlocksQueue *deque.Deque[types.Block]
|
||||||
Chain *chain.Chain
|
Chain *chain.Chain
|
||||||
Logg *slog.Logger
|
Logg *slog.Logger
|
||||||
Stats *stats.Stats
|
Stats *stats.Stats
|
||||||
DB *db.DB
|
DB *db.DB
|
||||||
InitialLowerBound uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Syncer struct {
|
Syncer struct {
|
||||||
batchQueue *deque.Deque[uint64]
|
batchQueue *deque.Deque[uint64]
|
||||||
blocksQueue *deque.Deque[types.Block]
|
blocksQueue *deque.Deque[types.Block]
|
||||||
chain *chain.Chain
|
chain *chain.Chain
|
||||||
logg *slog.Logger
|
logg *slog.Logger
|
||||||
stats *stats.Stats
|
stats *stats.Stats
|
||||||
ethClient *ethclient.Client
|
ethClient *ethclient.Client
|
||||||
db *db.DB
|
db *db.DB
|
||||||
initialLowerBound uint64
|
quit chan struct{}
|
||||||
//
|
startBlock uint64
|
||||||
realtimeSub celo.Subscription
|
realtimeSub celo.Subscription
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(o SyncerOpts) (*Syncer, error) {
|
func New(o SyncerOpts) (*Syncer, error) {
|
||||||
if o.InitialLowerBound == 0 {
|
if o.EnableHistorical {
|
||||||
return nil, errors.New("initial lower bound not set")
|
latestBlock, err := o.Chain.GetLatestBlock(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.StartBlock == 0 {
|
||||||
|
o.StartBlock = latestBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.DB.SetLowerBound(o.StartBlock); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := o.DB.SetUpperBound(latestBlock); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ethClient, err := ethclient.Dial(o.WebSocketEndpoint)
|
ethClient, err := ethclient.Dial(o.WebSocketEndpoint)
|
||||||
@ -50,13 +66,14 @@ func New(o SyncerOpts) (*Syncer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Syncer{
|
return &Syncer{
|
||||||
batchQueue: o.BatchQueue,
|
batchQueue: o.BatchQueue,
|
||||||
blocksQueue: o.BlocksQueue,
|
blocksQueue: o.BlocksQueue,
|
||||||
chain: o.Chain,
|
chain: o.Chain,
|
||||||
logg: o.Logg,
|
logg: o.Logg,
|
||||||
stats: o.Stats,
|
stats: o.Stats,
|
||||||
ethClient: ethClient,
|
ethClient: ethClient,
|
||||||
db: o.DB,
|
db: o.DB,
|
||||||
initialLowerBound: o.InitialLowerBound,
|
quit: make(chan struct{}),
|
||||||
|
startBlock: o.StartBlock,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user