-
Notifications
You must be signed in to change notification settings - Fork 140
fix(dot/sync): fix "block with unknown header is ready" error #2191
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
Changes from 7 commits
da45b81
a65e71e
ce03937
8e00818
62c711c
30ebc87
8ce6bf9
4fe4520
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,10 +13,11 @@ import ( | |||||
"sync" | ||||||
"time" | ||||||
|
||||||
"github.com/ChainSafe/gossamer/dot/peerset" | ||||||
"github.com/ChainSafe/chaindb" | ||||||
"github.com/libp2p/go-libp2p-core/peer" | ||||||
|
||||||
"github.com/ChainSafe/gossamer/dot/network" | ||||||
"github.com/ChainSafe/gossamer/dot/peerset" | ||||||
"github.com/ChainSafe/gossamer/dot/types" | ||||||
"github.com/ChainSafe/gossamer/lib/common" | ||||||
"github.com/ChainSafe/gossamer/lib/common/variadic" | ||||||
|
@@ -522,7 +523,7 @@ func (cs *chainSync) setMode(mode chainSyncState) { | |||||
case bootstrap: | ||||||
cs.handler = newBootstrapSyncer(cs.blockState) | ||||||
case tip: | ||||||
cs.handler = newTipSyncer(cs.blockState, cs.pendingBlocks, cs.readyBlocks) | ||||||
cs.handler = newTipSyncer(cs.blockState, cs.pendingBlocks, cs.readyBlocks, cs.handleReadyBlock) | ||||||
} | ||||||
|
||||||
cs.state = mode | ||||||
|
@@ -692,41 +693,61 @@ func (cs *chainSync) doSync(req *network.BlockRequestMessage, peersTried map[pee | |||||
// response was validated! place into ready block queue | ||||||
for _, bd := range resp.BlockData { | ||||||
// block is ready to be processed! | ||||||
handleReadyBlock(bd, cs.pendingBlocks, cs.readyBlocks) | ||||||
cs.handleReadyBlock(bd) | ||||||
} | ||||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
func handleReadyBlock(bd *types.BlockData, pendingBlocks DisjointBlockSet, readyBlocks *blockQueue) { | ||||||
// see if there are any descendents in the pending queue that are now ready to be processed, | ||||||
// as we have just become aware of their parent block | ||||||
func (cs *chainSync) handleReadyBlock(bd *types.BlockData) { | ||||||
// first check that the block isn't already in the ready queue | ||||||
if cs.readyBlocks.has(bd.Hash) { | ||||||
logger.Tracef("ignoring block %s in response, already in ready queue", bd.Hash) | ||||||
return | ||||||
} | ||||||
|
||||||
// if header was not requested, get it from the pending set | ||||||
// if we're expecting headers, validate should ensure we have a header | ||||||
if bd.Header == nil { | ||||||
block := pendingBlocks.getBlock(bd.Hash) | ||||||
block := cs.pendingBlocks.getBlock(bd.Hash) | ||||||
if block == nil { | ||||||
logger.Criticalf("block with unknown header is ready: hash=%s", bd.Hash) | ||||||
// block wasn't in the pending set! | ||||||
// let's check the db as maybe we already processed it | ||||||
has, err := cs.blockState.HasHeader(bd.Hash) | ||||||
if err != nil && !errors.Is(err, chaindb.ErrKeyNotFound) { | ||||||
logger.Debugf("failed to check if header is known for hash %s: err=%s", bd.Hash, err) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done! |
||||||
return | ||||||
} | ||||||
|
||||||
if has { | ||||||
// seems we already processed the block, so let's just return | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit unneded the log message says it already
Suggested change
|
||||||
logger.Tracef("ignoring block we've already processed, hash=%s", bd.Hash) | ||||||
return | ||||||
} | ||||||
|
||||||
// this is bad and shouldn't happen | ||||||
logger.Errorf("block with unknown header is ready: hash=%s", bd.Hash) | ||||||
Comment on lines
+726
to
+727
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this happen if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @qdm12 yeah this case would be hit if the error is |
||||||
return | ||||||
} | ||||||
|
||||||
bd.Header = block.header | ||||||
} | ||||||
|
||||||
if bd.Header == nil { | ||||||
logger.Criticalf("new ready block number (unknown) with hash %s", bd.Hash) | ||||||
logger.Errorf("new ready block number (unknown) with hash %s", bd.Hash) | ||||||
return | ||||||
} | ||||||
|
||||||
logger.Tracef("new ready block number %s with hash %s", bd.Header.Number, bd.Hash) | ||||||
|
||||||
// see if there are any descendents in the pending queue that are now ready to be processed, | ||||||
// as we have just become aware of their parent block | ||||||
ready := []*types.BlockData{bd} | ||||||
ready = pendingBlocks.getReadyDescendants(bd.Hash, ready) | ||||||
ready = cs.pendingBlocks.getReadyDescendants(bd.Hash, ready) | ||||||
|
||||||
for _, rb := range ready { | ||||||
pendingBlocks.removeBlock(rb.Hash) | ||||||
readyBlocks.push(rb) | ||||||
cs.pendingBlocks.removeBlock(rb.Hash) | ||||||
cs.readyBlocks.push(rb) | ||||||
} | ||||||
} | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -8,23 +8,29 @@ import ( | |||||
"math/big" | ||||||
|
||||||
"github.com/ChainSafe/gossamer/dot/network" | ||||||
"github.com/ChainSafe/gossamer/dot/types" | ||||||
"github.com/ChainSafe/gossamer/lib/common" | ||||||
) | ||||||
|
||||||
var _ workHandler = &tipSyncer{} | ||||||
|
||||||
type handleReadyBlockFunc = func(*types.BlockData) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit does the following work?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes it does, is there a preference for one? |
||||||
|
||||||
// tipSyncer handles workers when syncing at the tip of the chain | ||||||
type tipSyncer struct { | ||||||
blockState BlockState | ||||||
pendingBlocks DisjointBlockSet | ||||||
readyBlocks *blockQueue | ||||||
blockState BlockState | ||||||
pendingBlocks DisjointBlockSet | ||||||
readyBlocks *blockQueue | ||||||
handleReadyBlock handleReadyBlockFunc | ||||||
} | ||||||
|
||||||
func newTipSyncer(blockState BlockState, pendingBlocks DisjointBlockSet, readyBlocks *blockQueue) *tipSyncer { | ||||||
func newTipSyncer(blockState BlockState, pendingBlocks DisjointBlockSet, readyBlocks *blockQueue, | ||||||
handleReadyBlock handleReadyBlockFunc) *tipSyncer { | ||||||
return &tipSyncer{ | ||||||
blockState: blockState, | ||||||
pendingBlocks: pendingBlocks, | ||||||
readyBlocks: readyBlocks, | ||||||
blockState: blockState, | ||||||
pendingBlocks: pendingBlocks, | ||||||
readyBlocks: readyBlocks, | ||||||
handleReadyBlock: handleReadyBlock, | ||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -210,7 +216,7 @@ func (s *tipSyncer) handleTick() ([]*worker, error) { | |||||
if has || s.readyBlocks.has(block.header.ParentHash) { | ||||||
// block is ready, as parent is known! | ||||||
// also, move any pendingBlocks that are descendants of this block to the ready blocks queue | ||||||
handleReadyBlock(block.toBlockData(), s.pendingBlocks, s.readyBlocks) | ||||||
s.handleReadyBlock(block.toBlockData()) | ||||||
continue | ||||||
} | ||||||
|
||||||
|
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.
nit unneeded