7
7
"sync"
8
8
"time"
9
9
10
- "github.com/NilFoundation/nil/nil/common"
11
10
"github.com/NilFoundation/nil/nil/common/assert"
12
11
"github.com/NilFoundation/nil/nil/common/check"
12
+ "github.com/NilFoundation/nil/nil/common/concurrent"
13
13
"github.com/NilFoundation/nil/nil/common/logging"
14
14
cerrors "github.com/NilFoundation/nil/nil/internal/collate/errors"
15
15
"github.com/NilFoundation/nil/nil/internal/db"
@@ -102,54 +102,6 @@ func (s *Syncer) WaitComplete(ctx context.Context) error {
102
102
}
103
103
}
104
104
105
- func (s * Syncer ) getLocalVersion (ctx context.Context ) (* NodeVersion , error ) {
106
- protocolVersion := s .networkManager .ProtocolVersion ()
107
-
108
- rotx , err := s .db .CreateRoTx (ctx )
109
- if err != nil {
110
- return nil , err
111
- }
112
- defer rotx .Rollback ()
113
-
114
- res , err := db .ReadBlockHashByNumber (rotx , types .MainShardId , 0 )
115
- if err != nil {
116
- if errors .Is (err , db .ErrKeyNotFound ) {
117
- return & NodeVersion {protocolVersion , common .EmptyHash }, nil
118
- }
119
- return nil , err
120
- }
121
- return & NodeVersion {protocolVersion , res }, err
122
- }
123
-
124
- type NodeVersion struct {
125
- ProtocolVersion string
126
- GenesisBlockHash common.Hash
127
- }
128
-
129
- func (s * Syncer ) fetchRemoteVersion (ctx context.Context ) (NodeVersion , error ) {
130
- var err error
131
- for _ , peer := range s .config .BootstrapPeers {
132
- var peerId network.PeerID
133
- peerId , err = s .networkManager .Connect (ctx , network .AddrInfo (peer ))
134
- if err != nil {
135
- continue
136
- }
137
-
138
- var protocolVersion string
139
- protocolVersion , err = s .networkManager .GetPeerProtocolVersion (peerId )
140
- if err != nil {
141
- continue
142
- }
143
-
144
- var res common.Hash
145
- res , err = fetchGenesisBlockHash (ctx , s .networkManager , peerId )
146
- if err == nil {
147
- return NodeVersion {protocolVersion , res }, nil
148
- }
149
- }
150
- return NodeVersion {}, fmt .Errorf ("failed to fetch version from all peers; last error: %w" , err )
151
- }
152
-
153
105
func (s * Syncer ) fetchSnapshot (ctx context.Context ) error {
154
106
var err error
155
107
for _ , peer := range s .config .BootstrapPeers {
@@ -171,12 +123,12 @@ func (s *Syncer) Init(ctx context.Context, allowDbDrop bool) error {
171
123
return nil
172
124
}
173
125
174
- version , err := s . getLocalVersion (ctx )
126
+ version , err := GetLocalVersion (ctx , s . networkManager , s . db )
175
127
if err != nil {
176
128
return err
177
129
}
178
130
179
- remoteVersion , err := s . fetchRemoteVersion (ctx )
131
+ remoteVersion , err := FetchRemoteVersion (ctx , s . networkManager , s . config . BootstrapPeers )
180
132
if err != nil {
181
133
// Nodes with allowDbDrop are supposed to be secondary, so they must sync with some reliable peer.
182
134
// We need some nodes to start without fetching a remote version
@@ -220,7 +172,7 @@ func (s *Syncer) Init(ctx context.Context, allowDbDrop bool) error {
220
172
// SetHandlers sets the handlers for generic (shard-independent) protocols.
221
173
// It must be called after the initial sync of ALL shards is completed.
222
174
// It should be called once, e.g., by the main shard syncer.
223
- // (Subsequent calls do not have any side effects, but might return an error.)
175
+ // (Subsequent calls do not have any side effects but might return an error.)
224
176
func (s * Syncer ) SetHandlers (ctx context.Context ) error {
225
177
if s .networkManager == nil {
226
178
return nil
@@ -236,6 +188,9 @@ func (s *Syncer) Run(ctx context.Context) error {
236
188
return nil
237
189
}
238
190
191
+ ctx , cancel := context .WithCancel (ctx )
192
+ defer cancel ()
193
+
239
194
if s .config .ShardId .IsMainShard () {
240
195
if err := SetVersionHandler (ctx , s .networkManager , s .db ); err != nil {
241
196
return fmt .Errorf ("failed to set version handler: %w" , err )
@@ -249,24 +204,62 @@ func (s *Syncer) Run(ctx context.Context) error {
249
204
s .fetchBlocks (ctx )
250
205
s .waitForSync .Done ()
251
206
252
- s .logger .Info ().Msg ("Syncer initialization complete" )
253
-
254
207
if ctx .Err () != nil {
255
208
return nil
256
209
}
257
210
211
+ s .logger .Info ().Msg ("Running syncer..." )
212
+
258
213
sub , err := s .networkManager .PubSub ().Subscribe (s .topic )
259
214
if err != nil {
260
215
return fmt .Errorf ("failed to subscribe to %s: %w" , s .topic , err )
261
216
}
262
217
defer sub .Close ()
263
218
219
+ go s .doFetch (ctx , sub )
220
+
221
+ if len (s .config .BootstrapPeers ) == 0 {
222
+ s .logger .Info ().Msg ("No bootstrap peers. Skipping version check" )
223
+
224
+ <- ctx .Done ()
225
+ return nil
226
+ }
227
+
228
+ return s .runVersionCheckLoop (ctx )
229
+ }
230
+
231
+ func (s * Syncer ) runVersionCheckLoop (ctx context.Context ) error {
232
+ version , err := GetLocalVersion (ctx , s .networkManager , s .db )
233
+ if err != nil {
234
+ return err
235
+ }
236
+
237
+ return concurrent .RunTickerLoopWithErr (ctx , 10 * time .Second , func (ctx context.Context ) error {
238
+ remoteVersion , err := FetchRemoteVersion (ctx , s .networkManager , s .config .BootstrapPeers )
239
+ if err != nil {
240
+ s .logger .Warn ().Err (err ).Msg ("Failed to fetch remote version" )
241
+ return nil
242
+ }
243
+
244
+ if version .ProtocolVersion != remoteVersion .ProtocolVersion {
245
+ return & ProtocolVersionMismatchError {
246
+ version .ProtocolVersion ,
247
+ remoteVersion .ProtocolVersion ,
248
+ }
249
+ }
250
+
251
+ if version .GenesisBlockHash != remoteVersion .GenesisBlockHash {
252
+ return fmt .Errorf ("local version is outdated; local: %s, remote: %s" , version , remoteVersion )
253
+ }
254
+
255
+ return nil
256
+ })
257
+ }
258
+
259
+ func (s * Syncer ) doFetch (ctx context.Context , sub * network.Subscription ) {
264
260
ch := sub .Start (ctx , true )
265
261
for {
266
262
select {
267
- case <- ctx .Done ():
268
- s .logger .Debug ().Msg ("Syncer is terminated" )
269
- return nil
270
263
case msg := <- ch :
271
264
saved , err := s .processTopicTransaction (ctx , msg .Data )
272
265
if err != nil {
@@ -287,6 +280,9 @@ func (s *Syncer) Run(ctx context.Context) error {
287
280
s .logger .Warn ().Msgf ("No new block in the topic for %s, pulling blocks actively" , s .config .Timeout )
288
281
289
282
s .fetchBlocks (ctx )
283
+ case <- ctx .Done ():
284
+ s .logger .Info ().Msg ("Syncer is terminated" )
285
+ return
290
286
}
291
287
}
292
288
}
0 commit comments