-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathexplorer.go
196 lines (174 loc) · 8.12 KB
/
explorer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package node
import (
"context"
"fmt"
"net/http"
"time"
"github.com/synapsecns/sanguine/core/metrics"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/synapsecns/sanguine/services/explorer/backfill"
indexerConfig "github.com/synapsecns/sanguine/services/explorer/config/indexer"
gqlClient "github.com/synapsecns/sanguine/services/explorer/consumer/client"
fetcherpkg "github.com/synapsecns/sanguine/services/explorer/consumer/fetcher"
"github.com/synapsecns/sanguine/services/explorer/consumer/fetcher/tokenprice"
"github.com/synapsecns/sanguine/services/explorer/consumer/parser"
"github.com/synapsecns/sanguine/services/explorer/consumer/parser/tokendata"
"github.com/synapsecns/sanguine/services/explorer/contracts/bridgeconfig"
"github.com/synapsecns/sanguine/services/explorer/db"
"github.com/synapsecns/sanguine/services/explorer/static"
"golang.org/x/sync/errgroup"
)
// ExplorerBackfiller is a backfiller that aggregates all backfilling from ChainBackfillers.
type ExplorerBackfiller struct {
// consumerDB is the database to store consumer data in.
consumerDB db.ConsumerDB
// clients is a mapping of chain IDs -> clients.
clients map[uint32]bind.ContractBackend
// ChainBackfillers is a mapping of chain IDs -> chain backfillers.
ChainBackfillers map[uint32]*backfill.ChainBackfiller
// config is the config for the backfiller.
config indexerConfig.Config
}
// NewExplorerBackfiller creates a new backfiller for the explorer.
//
// nolint:gocognit
func NewExplorerBackfiller(consumerDB db.ConsumerDB, config indexerConfig.Config, clients map[uint32]bind.ContractBackend, handler metrics.Handler) (*ExplorerBackfiller, error) {
chainBackfillers := make(map[uint32]*backfill.ChainBackfiller)
httpClient := http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
ResponseHeaderTimeout: 10 * time.Second,
},
}
fetcher := fetcherpkg.NewFetcher(gqlClient.NewClient(&httpClient, config.ScribeURL), handler)
bridgeConfigRef, err := bridgeconfig.NewBridgeConfigRef(common.HexToAddress(config.BridgeConfigAddress), clients[config.BridgeConfigChainID])
if err != nil || bridgeConfigRef == nil {
return nil, fmt.Errorf("could not create bridge config ScribeFetcher: %w", err)
}
priceDataService, err := tokenprice.NewPriceDataService()
if err != nil {
return nil, fmt.Errorf("could not create price data service: %w", err)
}
newConfigFetcher, err := fetcherpkg.NewBridgeConfigFetcher(common.HexToAddress(config.BridgeConfigAddress), bridgeConfigRef)
if err != nil || newConfigFetcher == nil {
return nil, fmt.Errorf("could not get bridge abi: %w", err)
}
tokenSymbolToIDs, err := parser.ParseYaml(static.GetTokenSymbolToTokenIDConfig())
if err != nil {
return nil, fmt.Errorf("could not open yaml file: %w", err)
}
tokenDataService, err := tokendata.NewTokenDataService(newConfigFetcher, tokenSymbolToIDs)
if err != nil {
return nil, fmt.Errorf("could not create token data service: %w", err)
}
// Initialize each chain backfiller.
for _, chainConfig := range config.Chains {
chainBackfiller, err := getChainBackfiller(consumerDB, chainConfig, fetcher, clients[chainConfig.ChainID], tokenDataService, priceDataService)
if err != nil {
return nil, fmt.Errorf("could not get chain backfiller: %w", err)
}
chainBackfillers[chainConfig.ChainID] = chainBackfiller
}
return &ExplorerBackfiller{
consumerDB: consumerDB,
clients: clients,
ChainBackfillers: chainBackfillers,
config: config,
}, nil
}
// Backfill iterates over each chain backfiller and calls Backfill concurrently on each one.
//
// nolint:cyclop
func (e ExplorerBackfiller) Backfill(ctx context.Context, livefill bool) error {
refreshRate := e.config.DefaultRefreshRate
if refreshRate == 0 {
refreshRate = 1
}
g, groupCtx := errgroup.WithContext(ctx)
for i := range e.config.Chains {
chainConfig := e.config.Chains[i]
chainBackfiller := e.ChainBackfillers[chainConfig.ChainID]
g.Go(func() error {
err := chainBackfiller.Backfill(groupCtx, livefill, refreshRate)
if err != nil {
return fmt.Errorf("could not backfill chain %d: %w", chainConfig.ChainID, err)
}
return nil
})
}
if err := g.Wait(); err != nil {
logger.Errorf("backfill completed: %v", err)
return fmt.Errorf("could not livefill explorer: %w", err)
}
logger.Errorf("backfill completed with no errors")
return nil
}
// nolint gocognit,cyclop
func getChainBackfiller(consumerDB db.ConsumerDB, chainConfig indexerConfig.ChainConfig, fetcher fetcherpkg.ScribeFetcher, client bind.ContractBackend, tokenDataService tokendata.Service, priceDataService tokenprice.Service) (*backfill.ChainBackfiller, error) {
var err error
var bridgeParser *parser.BridgeParser
var messageBusParser *parser.MessageBusParser
var cctpParser *parser.CCTPParser
var swapService fetcherpkg.SwapService
var cctpService fetcherpkg.CCTPService
var rfqParser *parser.RFQParser
var rfqService fetcherpkg.RFQService
swapParsers := make(map[common.Address]*parser.SwapParser)
for i := range chainConfig.Contracts {
switch chainConfig.Contracts[i].ContractType {
case "bridge":
bridgeParser, err = parser.NewBridgeParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), tokenDataService, fetcher, priceDataService, false)
if err != nil || bridgeParser == nil {
return nil, fmt.Errorf("could not create bridge parser: %w", err)
}
case "swap":
swapService, err = fetcherpkg.NewSwapFetcher(common.HexToAddress(chainConfig.Contracts[i].Address), client, false)
if err != nil || swapService == nil {
return nil, fmt.Errorf("could not create swapService: %w", err)
}
swapParser, err := parser.NewSwapParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), false, fetcher, swapService, tokenDataService, priceDataService)
if err != nil || swapParser == nil {
return nil, fmt.Errorf("could not create swap parser: %w", err)
}
swapParsers[common.HexToAddress(chainConfig.Contracts[i].Address)] = swapParser
case "metaswap":
if swapService == nil {
swapService, err := fetcherpkg.NewSwapFetcher(common.HexToAddress(chainConfig.Contracts[i].Address), client, true)
if err != nil || swapService == nil {
return nil, fmt.Errorf("could not create swapService: %w", err)
}
}
swapParser, err := parser.NewSwapParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), true, fetcher, swapService, tokenDataService, priceDataService)
if err != nil || swapParser == nil {
return nil, fmt.Errorf("could not create swap parser: %w", err)
}
swapParsers[common.HexToAddress(chainConfig.Contracts[i].Address)] = swapParser
case "messagebus":
messageBusParser, err = parser.NewMessageBusParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), fetcher, priceDataService)
if err != nil || messageBusParser == nil {
return nil, fmt.Errorf("could not create message bus parser: %w", err)
}
case "cctp":
cctpService, err = fetcherpkg.NewCCTPFetcher(common.HexToAddress(chainConfig.Contracts[i].Address), client)
if err != nil || cctpService == nil {
return nil, fmt.Errorf("could not create cctpService: %w", err)
}
cctpParser, err = parser.NewCCTPParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), fetcher, cctpService, tokenDataService, priceDataService, false)
if err != nil || cctpParser == nil {
return nil, fmt.Errorf("could not create message bus parser: %w", err)
}
case "rfq":
rfqService, err = fetcherpkg.NewRFQFetcher(common.HexToAddress(chainConfig.Contracts[i].Address), client)
if err != nil || rfqService == nil {
return nil, fmt.Errorf("could not create rfqService: %w", err)
}
rfqParser, err = parser.NewRFQParser(consumerDB, common.HexToAddress(chainConfig.Contracts[i].Address), fetcher, rfqService, tokenDataService, priceDataService, false)
if err != nil || rfqParser == nil {
return nil, fmt.Errorf("could not create message bus parser: %w", err)
}
}
}
chainBackfiller := backfill.NewChainBackfiller(consumerDB, bridgeParser, swapParsers, messageBusParser, cctpParser, rfqParser, fetcher, chainConfig)
return chainBackfiller, nil
}