@@ -65,6 +65,11 @@ func (p poolWrapper) Close() error {
65
65
return nil
66
66
}
67
67
68
+ type indexedOID struct {
69
+ Index int
70
+ OID oid.ID
71
+ }
72
+
68
73
// Service is a service that fetches blocks from NeoFS.
69
74
type Service struct {
70
75
// isActive denotes whether the service is working or in the process of shutdown.
@@ -75,15 +80,15 @@ type Service struct {
75
80
operationMode OperationMode
76
81
77
82
stateRootInHeader bool
78
- // headerSize is the size of the header in bytes .
79
- headerSize int
83
+ // headerSizeMap is a map of height to expected header size .
84
+ headerSizeMap map [ int ] int
80
85
81
86
chain Ledger
82
87
pool poolWrapper
83
88
enqueue func (block bqueue.Queueable ) error
84
89
account * wallet.Account
85
90
86
- oidsCh chan oid. ID
91
+ oidsCh chan indexedOID
87
92
// wg is a wait group for block downloaders.
88
93
wg sync.WaitGroup
89
94
@@ -101,7 +106,7 @@ type Service struct {
101
106
shutdownCallback func ()
102
107
103
108
// Depends on the OperationMode, the following functions are set to the appropriate functions.
104
- getFunc func (ctx context.Context , oid string ) (io.ReadCloser , error )
109
+ getFunc func (ctx context.Context , oid string , index int ) (io.ReadCloser , error )
105
110
readFunc func (rc io.ReadCloser ) (any , error )
106
111
heightFunc func () uint32
107
112
}
@@ -168,7 +173,7 @@ func New(chain Ledger, cfg config.NeoFSBlockFetcher, logger *zap.Logger, put fun
168
173
log : logger ,
169
174
cfg : cfg ,
170
175
operationMode : opt ,
171
- headerSize : getHeaderSize (chain .GetConfig ()),
176
+ headerSizeMap : getHeaderSizeMap (chain .GetConfig ()),
172
177
173
178
enqueue : put ,
174
179
account : account ,
@@ -184,13 +189,14 @@ func New(chain Ledger, cfg config.NeoFSBlockFetcher, logger *zap.Logger, put fun
184
189
// * first full block of OIDs is processing by Downloader
185
190
// * second full block of OIDs is available to be fetched by Downloader immediately
186
191
// * third half-filled block of OIDs is being collected by OIDsFetcher.
187
- oidsCh : make (chan oid. ID , 2 * cfg .OIDBatchSize ),
192
+ oidsCh : make (chan indexedOID , 2 * cfg .OIDBatchSize ),
188
193
}, nil
189
194
}
190
195
191
- func getHeaderSize (chain config.Blockchain ) int {
192
- m := smartcontract . GetDefaultHonestNodeCount ( int ( chain . ValidatorsCount ) )
196
+ func getHeaderSizeMap (chain config.Blockchain ) map [ int ] int {
197
+ headerSizeMap := make ( map [ int ] int )
193
198
vs , _ := keys .NewPublicKeysFromStrings (chain .StandbyCommittee )
199
+ m := smartcontract .GetDefaultHonestNodeCount (int (chain .ValidatorsCount ))
194
200
verification , _ := smartcontract .CreateDefaultMultiSigRedeemScript (vs [:chain .GetNumOfCNs (0 )])
195
201
b := block.Header {
196
202
StateRootEnabled : chain .StateRootInHeader ,
@@ -200,7 +206,22 @@ func getHeaderSize(chain config.Blockchain) int {
200
206
InvocationScript : make ([]byte , 66 * m ),
201
207
},
202
208
}
203
- return b .GetExpectedHeaderSize ()
209
+ headerSizeMap [0 ] = b .GetExpectedHeaderSize ()
210
+
211
+ for height := range chain .CommitteeHistory {
212
+ m = smartcontract .GetDefaultHonestNodeCount (chain .GetNumOfCNs (height ))
213
+ verification , _ = smartcontract .CreateDefaultMultiSigRedeemScript (vs [:chain .GetNumOfCNs (height )])
214
+ b = block.Header {
215
+ StateRootEnabled : chain .StateRootInHeader ,
216
+ Timestamp : 42 ,
217
+ Script : transaction.Witness {
218
+ VerificationScript : verification ,
219
+ InvocationScript : make ([]byte , 66 * m ),
220
+ },
221
+ }
222
+ headerSizeMap [int (height )] = b .GetExpectedHeaderSize ()
223
+ }
224
+ return headerSizeMap
204
225
}
205
226
206
227
// Start runs the NeoFS BlockFetcher service.
@@ -288,11 +309,13 @@ func (bfs *Service) oidDownloader() {
288
309
func (bfs * Service ) blockDownloader () {
289
310
defer bfs .wg .Done ()
290
311
291
- for blkOid := range bfs .oidsCh {
312
+ for indexedOid := range bfs .oidsCh {
313
+ index := indexedOid .Index
314
+ blkOid := indexedOid .OID
292
315
ctx , cancel := context .WithTimeout (bfs .ctx , bfs .cfg .Timeout )
293
316
defer cancel ()
294
317
295
- rc , err := bfs .getFunc (ctx , blkOid .String ())
318
+ rc , err := bfs .getFunc (ctx , blkOid .String (), index )
296
319
if err != nil {
297
320
if isContextCanceledErr (err ) {
298
321
return
@@ -358,15 +381,15 @@ func (bfs *Service) fetchOIDsFromIndexFiles() error {
358
381
359
382
blockCtx , blockCancel := context .WithTimeout (bfs .ctx , bfs .cfg .Timeout )
360
383
defer blockCancel ()
361
- oidsRC , err := bfs .objectGet (blockCtx , blockOidsObject [0 ].String ())
384
+ oidsRC , err := bfs .objectGet (blockCtx , blockOidsObject [0 ].String (), - 1 )
362
385
if err != nil {
363
386
if isContextCanceledErr (err ) {
364
387
return nil
365
388
}
366
389
return fmt .Errorf ("failed to fetch '%s' object with index %d: %w" , bfs .cfg .IndexFileAttribute , startIndex , err )
367
390
}
368
391
369
- err = bfs .streamBlockOIDs (oidsRC , int (skip ))
392
+ err = bfs .streamBlockOIDs (oidsRC , int (startIndex ), int ( skip ))
370
393
if err != nil {
371
394
if isContextCanceledErr (err ) {
372
395
return nil
@@ -381,7 +404,7 @@ func (bfs *Service) fetchOIDsFromIndexFiles() error {
381
404
}
382
405
383
406
// streamBlockOIDs reads block OIDs from the read closer and sends them to the OIDs channel.
384
- func (bfs * Service ) streamBlockOIDs (rc io.ReadCloser , skip int ) error {
407
+ func (bfs * Service ) streamBlockOIDs (rc io.ReadCloser , startIndex , skip int ) error {
385
408
defer rc .Close ()
386
409
oidBytes := make ([]byte , oid .Size )
387
410
oidsProcessed := 0
@@ -408,7 +431,7 @@ func (bfs *Service) streamBlockOIDs(rc io.ReadCloser, skip int) error {
408
431
select {
409
432
case <- bfs .exiterToOIDDownloader :
410
433
return nil
411
- case bfs .oidsCh <- oidBlock :
434
+ case bfs .oidsCh <- indexedOID { Index : startIndex * int ( bfs . cfg . IndexFileSize ) + oidsProcessed , OID : oidBlock } :
412
435
}
413
436
414
437
oidsProcessed ++
@@ -453,12 +476,14 @@ func (bfs *Service) fetchOIDsBySearch() error {
453
476
bfs .log .Info (fmt .Sprintf ("NeoFS BlockFetcher service: no block found with index %d, stopping" , startIndex ))
454
477
return nil
455
478
}
479
+ index := int (startIndex )
456
480
for _ , oid := range blockOids {
457
481
select {
458
482
case <- bfs .exiterToOIDDownloader :
459
483
return nil
460
- case bfs .oidsCh <- oid :
484
+ case bfs .oidsCh <- indexedOID { Index : index , OID : oid } :
461
485
}
486
+ index ++ //Won't work properly if neofs.ObjectSearch results are not ordered.
462
487
}
463
488
startIndex += batchSize
464
489
}
@@ -592,7 +617,7 @@ func (bfs *Service) retry(action func() error) error {
592
617
return err
593
618
}
594
619
595
- func (bfs * Service ) objectGet (ctx context.Context , oid string ) (io.ReadCloser , error ) {
620
+ func (bfs * Service ) objectGet (ctx context.Context , oid string , index int ) (io.ReadCloser , error ) {
596
621
u , err := url .Parse (fmt .Sprintf ("%s:%s/%s" , neofs .URIScheme , bfs .cfg .ContainerID , oid ))
597
622
if err != nil {
598
623
return nil , err
@@ -605,8 +630,19 @@ func (bfs *Service) objectGet(ctx context.Context, oid string) (io.ReadCloser, e
605
630
return rc , err
606
631
}
607
632
608
- func (bfs * Service ) objectGetRange (ctx context.Context , oid string ) (io.ReadCloser , error ) {
609
- u , err := url .Parse (fmt .Sprintf ("%s:%s/%s/%s/%d|%d" , neofs .URIScheme , bfs .cfg .ContainerID , oid , "range" , 0 , bfs .headerSize ))
633
+ func (bfs * Service ) objectGetRange (ctx context.Context , oid string , height int ) (io.ReadCloser , error ) {
634
+ nearestHeight := 0
635
+ for h := range bfs .headerSizeMap {
636
+ if h <= height && h > nearestHeight {
637
+ nearestHeight = h
638
+ }
639
+ if nearestHeight >= height {
640
+ break
641
+ }
642
+ }
643
+
644
+ size := bfs .headerSizeMap [nearestHeight ]
645
+ u , err := url .Parse (fmt .Sprintf ("%s:%s/%s/%s/%d|%d" , neofs .URIScheme , bfs .cfg .ContainerID , oid , "range" , 0 , size ))
610
646
if err != nil {
611
647
return nil , err
612
648
}
0 commit comments