-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Headers fetching via NeoFS BlockFetcher service #3789
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Ekaterina Pavlova <[email protected]>
ee083c5
to
6b9d29e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HeadersFetcher is started in the wrong place. Ensure that nothing prevents StateSync module to request blocks/headers during the node start.
queue: make([]*block.Block, cacheSize), | ||
checkBlocks: make(chan struct{}, 1), | ||
headersQueue: make([]*block.Header, cacheSize), | ||
checkHeaders: make(chan struct{}, 1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need this headers/blocks split inside the queue. What we need is a type-specific queue, it may be implemented via generics, because overall logic is the same for blocks/headers.
On server side we may use two instances of the queue: one for blocks, and another one for headers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's have the current implementation for now and finalize the overall process firstly; afterwards we'll refactor blockqueue.
pkg/network/server.go
Outdated
var err error | ||
s.blockFetcher, err = blockfetcher.New(chain, s.NeoFSBlockFetcherCfg, log, s.bFetcherQueue.PutBlock, | ||
sync.OnceFunc(func() { close(s.blockFetcherFin) })) | ||
s.headerFetcher, err = blockfetcher.New(chain, s.NeoFSBlockFetcherCfg, log, s.bFetcherQueue.PutBlock, s.bFetcherQueue.PutHeader, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provide s.stateSync
instead of chain
as the first argument to blockfetcher.New
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The height is different for s.stateSync. It starts from 3 mln, so the block/header can persist, and the queue becomes locked. That's why I rolled it back to the chain. Why can't it be the chain? Blockfetcher uses it only for config and BlockHeight(). will recheck why its s.stateSync starts from the middle of the sequence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need BlockHeight and HeaderHeight to be aligned with statesync module vision, that's the main idea.
pkg/core/statesync/module.go
Outdated
|
||
billet *mpt.Billet | ||
|
||
jumpCallback func(p uint32) error | ||
} | ||
|
||
// NewModule returns new instance of statesync module. | ||
func NewModule(bc Ledger, stateMod *stateroot.Module, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module { | ||
func NewModule(bc Ledger, log *zap.Logger, s *dao.Simple, jumpCallback func(p uint32) error) *Module { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert this change.
e867abb
to
26c546e
Compare
26c546e
to
3b2b9a6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the service start work as expected?
@@ -285,9 +285,6 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger) (*Bl | |||
zap.Uint32("MaxValidUntilBlockIncrement", cfg.MaxValidUntilBlockIncrement)) | |||
} | |||
if cfg.P2PStateExchangeExtensions { | |||
if !cfg.StateRootInHeader { | |||
return nil, errors.New("P2PStatesExchangeExtensions are enabled, but StateRootInHeader is off") | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need more sophisticated check. If BlockFetcher is on, then it's OK, but if Blockfetcher is off and StateRootInHeader is also off, then it's an error.
pkg/network/server.go
Outdated
if s.chain.HeaderHeight() < p.LastBlockIndex() { | ||
return s.requestHeaders(p) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if
check must be adjusted. Right now it's related to peers only, but if blockfetcher is used, then we don't care about peer height because another source of data is used (NeoFS storage).
pkg/network/server.go
Outdated
if s.stateSync.NeedHeaders() { | ||
if s.chain.HeaderHeight() < p.LastBlockIndex() { | ||
return s.requestHeaders(p) | ||
} | ||
return nil | ||
} | ||
s.headerFetcher.Shutdown() | ||
if s.ServerConfig.NeoFSBlockFetcherCfg.Enabled { | ||
err := s.blockFetcher.Start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blockfetcher should fetch exactly the range of blocks that is required by statesymc module if statesync module is enabled. If statesync module is disabled, then blockfetcher should fetch all blocks starting from 0. Check that this logic is present in the blockfetcher.
pkg/network/server.go
Outdated
if s.ServerConfig.NeoFSBlockFetcherCfg.Enabled { | ||
err := s.headerFetcher.Start() | ||
if err != nil { | ||
s.log.Error("skipping NeoFS BlockFetcher", zap.Error(err)) | ||
} | ||
} | ||
if s.headerFetcher.IsActive() { | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition may lead to deadlock, consider the situation: NeoFS storage is missing the latest headers. Once started, headerfetcher will fetch all available headers and shutdown. However, if some latest headers are still required by statesync, then we need to switch to P2P. Right now this code will restart headersfetcher anyway. Setting s.headerFetcher
to nil after the first headerfetcher shutdown (and checking for nil in dependent places) may do the trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with nil we cant use isActive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without nil we can't distinguish finished service from not started. So additional nil checks is a trade-off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added isShutdown to the blockfetcher. if you don't like it, will look more precisely to the nil.
err = bfs.enqueueBlock(b) | ||
if !bfs.cfg.BlocksOnly { | ||
err = bfs.enqueueHeader(&b.Header) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the code that will read header from stream without transactions reading.
pkg/network/server.go
Outdated
s.bFetcherQueue = bqueue.New(chain, log, nil, s.NeoFSBlockFetcherCfg.BQueueSize, updateBlockQueueLenMetric, bqueue.Blocking) | ||
s.bFetcherQueue = bqueue.New(s.stateSync, log, nil, s.NeoFSBlockFetcherCfg.BQueueSize, updateBlockQueueLenMetric, bqueue.Blocking) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need a switch here. The main idea is that blockfetcher should work both with statesync module enabled/disabled. If statesync module is disabled then we need a usual blockfetcher operation flow that will fetch blocks, put them directly into chain-backed queue and shutdown. If statesync module is enabled then blockfetcher should use statesync-backed queue and headersfetcher should also be started.
3b2b9a6
to
f4d006f
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3789 +/- ##
==========================================
- Coverage 83.13% 82.82% -0.32%
==========================================
Files 335 335
Lines 46855 47186 +331
==========================================
+ Hits 38954 39082 +128
- Misses 6311 6505 +194
- Partials 1590 1599 +9 ☔ View full report in Codecov by Sentry. |
f4d006f
to
b2c9187
Compare
sometimes:
|
pkg/network/server.go
Outdated
return nil, fmt.Errorf("failed to create NeoFS BlockFetcher: %w", err) | ||
} | ||
s.NeoFSBlockFetcherCfg.BlocksOnly = true | ||
s.blockFetcher, err = blockfetcher.New(bq, s.NeoFSBlockFetcherCfg, log, s.bFetcherQueue.PutBlock, s.bFetcherQueue.PutHeader, sync.OnceFunc(func() { close(s.blockFetcherFin) })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I don't see in the current implementation is: when statesync part is over, the node should start its usual sync process:
- Start the third blockfetcher instance backed by a simple queue (not by statesync module) and check if there are blocks from NeoFS that can be fetched.
- Once all blocks are fetched from NeoFS, move to P2P sync.
35f31b2
to
2112fe0
Compare
Close #3574 Signed-off-by: Ekaterina Pavlova <[email protected]>
Signed-off-by: Ekaterina Pavlova <[email protected]>
2112fe0
to
f3629c4
Compare
Close #3574