-
Notifications
You must be signed in to change notification settings - Fork 146
feat(lib/grandpa): ensure catch-up logic works #2152
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 9 commits
b7d814c
13b943e
faa8f82
0099a98
ec356aa
8320fc9
9a73bb2
b554d66
22e43c3
87c3ccf
75c4c4f
c1cd3f4
8fbd095
cc01bb2
0b6aeaa
b5e81f3
b2dc802
fa2dbdd
1a9c766
0019d85
3ac4e19
e75c810
aa78386
884a59e
6810d92
835ac6b
b57565f
8054782
144022e
db73c8c
592e201
d2fcc21
c04125b
576eabd
a45fbd5
a4aa5f7
728e91a
735f98c
a3bc897
71c3774
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 |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import ( | |
| "math/big" | ||
| "reflect" | ||
|
|
||
| "github.com/ChainSafe/chaindb" | ||
| "github.com/ChainSafe/gossamer/dot/network" | ||
| "github.com/ChainSafe/gossamer/dot/telemetry" | ||
| "github.com/ChainSafe/gossamer/dot/types" | ||
|
|
@@ -21,6 +22,8 @@ import ( | |
| "github.com/libp2p/go-libp2p-core/peer" | ||
| ) | ||
|
|
||
| const catchupThreshold = 2 | ||
|
|
||
| // MessageHandler handles GRANDPA consensus messages | ||
| type MessageHandler struct { | ||
| grandpa *Service | ||
|
|
@@ -37,6 +40,8 @@ func NewMessageHandler(grandpa *Service, blockState BlockState, telemetryMailer | |
| } | ||
| } | ||
|
|
||
| //nolint | ||
| // TODO: NotificationMessage is used at places. But NotificationMessage we return is always nil. | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
|
||
| // HandleMessage handles a GRANDPA consensus message | ||
| // if it is a CommitMessage, it updates the BlockState | ||
| // if it is a VoteMessage, it sends it to the GRANDPA service | ||
|
|
@@ -56,25 +61,29 @@ func (h *MessageHandler) handleMessage(from peer.ID, m GrandpaMessage) (network. | |
| return nil, h.handleCommitMessage(msg) | ||
| case *NeighbourMessage: | ||
| // we can afford to not retry handling neighbour message, if it errors. | ||
| return nil, h.handleNeighbourMessage(msg) | ||
| return nil, h.handleNeighbourMessage(msg, from) | ||
| case *CatchUpRequest: | ||
| return h.handleCatchUpRequest(msg) | ||
| return nil, h.handleCatchUpRequest(msg, from) | ||
| case *CatchUpResponse: | ||
| err := h.handleCatchUpResponse(msg) | ||
| if errors.Is(err, blocktree.ErrNodeNotFound) { | ||
| // TODO: we are adding these messages to reprocess them again, but we | ||
| // haven't added code to reprocess them. Do that. | ||
| // Also, revisit if we need to add these message in synchronous manner | ||
| if errors.Is(err, blocktree.ErrNodeNotFound) || errors.Is(err, chaindb.ErrKeyNotFound) { | ||
| // TODO: revisit if we need to add these message in synchronous manner | ||
| // or not. If not, change catchUpResponseMessages to a normal map. #1531 | ||
| h.grandpa.tracker.addCatchUpResponse(msg) | ||
| h.grandpa.tracker.addCatchUpResponse(&networkCatchUpResponseMessage{ | ||
| from: from, | ||
| msg: msg, | ||
| }) | ||
| } else if err != nil { | ||
| logger.Debugf("could not catchup: %s", err) | ||
|
Contributor
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. Why not return the error here? |
||
| } | ||
|
|
||
| return nil, err | ||
| default: | ||
| return nil, ErrInvalidMessageType | ||
| } | ||
| } | ||
|
|
||
| func (h *MessageHandler) handleNeighbourMessage(msg *NeighbourMessage) error { | ||
| func (h *MessageHandler) handleNeighbourMessage(msg *NeighbourMessage, from peer.ID) error { | ||
| currFinalized, err := h.blockState.GetFinalisedHeader(0, 0) | ||
| if err != nil { | ||
| return err | ||
|
|
@@ -87,18 +96,58 @@ func (h *MessageHandler) handleNeighbourMessage(msg *NeighbourMessage) error { | |
|
|
||
| // TODO; determine if there is some reason we don't receive justifications in responses near the head (usually), | ||
| // and remove the following code if it's fixed. (#1815) | ||
| head, err := h.blockState.BestBlockNumber() | ||
| // head, err := h.blockState.BestBlockNumber() | ||
| // if err != nil { | ||
| // return err | ||
| // } | ||
|
|
||
| // TODO: Why are we ignoring these? Isn't | ||
| // msg.Number likely to be higher if we are lagging behind? | ||
| // ignore neighbour messages that are above our head | ||
| // if int64(msg.Number) > head.Int64() { | ||
| // return nil | ||
| // } | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
kishansagathiya marked this conversation as resolved.
Outdated
|
||
|
|
||
| logger.Debugf("got neighbour message with number %d, set id %d and round %d, from: %s ", | ||
| msg.Number, msg.SetID, msg.Round, from) | ||
| // TODO: should we send a justification request here? potentially re-connect this to sync package? (#1815) | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
|
||
|
|
||
| highestRound, setID, err := h.blockState.GetHighestRoundAndSetID() | ||
| if err != nil { | ||
| return err | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // ignore neighbour messages that are above our head | ||
| if int64(msg.Number) > head.Int64() { | ||
| return nil | ||
| // catch up only if we are behind by more than catchup threshold | ||
| if (int(msg.Round) - int(highestRound)) > catchupThreshold { | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
Contributor
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. Define
kishansagathiya marked this conversation as resolved.
Outdated
|
||
| logger.Debugf("lagging behind by %d rounds", int(msg.Round)-int(highestRound)) | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
|
||
|
|
||
| if err := h.sendCatchUpRequest( | ||
| from, newCatchUpRequest(msg.Round, setID), | ||
| ); err != nil { | ||
| logger.Debugf("failed to send catch up request: %s", err.Error()) | ||
| return err | ||
| } | ||
|
|
||
| logger.Debugf("successfully sent a catch up request to node %s, for round number %d and set ID %d", | ||
| from, msg.Round, setID) | ||
| } | ||
|
|
||
| logger.Debugf("got neighbour message with number %d, set id %d and round %d", msg.Number, msg.SetID, msg.Round) | ||
| // TODO: should we send a justification request here? potentially re-connect this to sync package? (#1815) | ||
| return nil | ||
| } | ||
|
|
||
| func (h *MessageHandler) sendCatchUpRequest(to peer.ID, req *CatchUpRequest) error { | ||
| cm, err := req.ToConsensusMessage() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = h.grandpa.network.SendMessage(to, cm) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| h.grandpa.paused.Store(true) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
|
|
@@ -149,31 +198,46 @@ func (h *MessageHandler) handleCommitMessage(msg *CommitMessage) error { | |
| return nil | ||
| } | ||
|
|
||
| func (h *MessageHandler) handleCatchUpRequest(msg *CatchUpRequest) (*ConsensusMessage, error) { | ||
| func (h *MessageHandler) handleCatchUpRequest(msg *CatchUpRequest, from peer.ID) error { | ||
| if !h.grandpa.authority { | ||
| return nil, nil //nolint:nilnil | ||
| return nil | ||
| } | ||
|
|
||
| logger.Debugf("received catch up request for round %d and set id %d", | ||
| msg.Round, msg.SetID) | ||
| logger.Debugf("received catch up request for round %d and set id %d, from %s", | ||
| msg.Round, msg.SetID, from) | ||
|
|
||
| logger.Debugf("Our latest round is %d", h.grandpa.state.round) | ||
|
|
||
| if msg.SetID != h.grandpa.state.setID { | ||
| return nil, ErrSetIDMismatch | ||
| return ErrSetIDMismatch | ||
| } | ||
|
|
||
| if msg.Round >= h.grandpa.state.round { | ||
| return nil, ErrInvalidCatchUpRound | ||
| if msg.Round > h.grandpa.state.round { | ||
| return ErrInvalidCatchUpRound | ||
|
kishansagathiya marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| resp, err := h.grandpa.newCatchUpResponse(msg.Round, msg.SetID) | ||
| // We don't necessarily have to reply with the round asked in the request, we can reply | ||
| // with our latest round. | ||
| resp, err := h.grandpa.newCatchUpResponse(h.grandpa.state.round, h.grandpa.state.setID) | ||
| if err != nil { | ||
| return nil, err | ||
| return err | ||
| } | ||
|
|
||
| cm, err := resp.ToConsensusMessage() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| err = h.grandpa.network.SendMessage(from, cm) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
kishansagathiya marked this conversation as resolved.
|
||
|
|
||
| logger.Debugf( | ||
| "sending catch up response with hash %s for round %d and set id %d", | ||
| resp.Hash, msg.Round, msg.SetID) | ||
| return resp.ToConsensusMessage() | ||
| "successfully sent catch up response with hash %s for round %d and set id %d, to %s", | ||
| resp.Hash, h.grandpa.state.round, h.grandpa.state.setID, from) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (h *MessageHandler) handleCatchUpResponse(msg *CatchUpResponse) error { | ||
|
|
@@ -182,14 +246,9 @@ func (h *MessageHandler) handleCatchUpResponse(msg *CatchUpResponse) error { | |
| } | ||
|
|
||
| logger.Debugf( | ||
| "received catch up response with hash %s for round %d and set id %d", | ||
| "processing catch up response with hash %s for round %d and set id %d", | ||
| msg.Hash, msg.Round, msg.SetID) | ||
|
|
||
| // TODO: re-add catch-up logic (#1531) | ||
| if true { | ||
| return nil | ||
| } | ||
|
|
||
| // if we aren't currently expecting a catch up response, return | ||
| if !h.grandpa.paused.Load().(bool) { | ||
| logger.Debug("not currently paused, ignoring catch up response") | ||
|
|
@@ -200,7 +259,7 @@ func (h *MessageHandler) handleCatchUpResponse(msg *CatchUpResponse) error { | |
| return ErrSetIDMismatch | ||
| } | ||
|
|
||
| if msg.Round != h.grandpa.state.round-1 { | ||
| if msg.Round <= h.grandpa.state.round { | ||
| return ErrInvalidCatchUpResponseRound | ||
| } | ||
|
|
||
|
|
@@ -233,6 +292,7 @@ func (h *MessageHandler) handleCatchUpResponse(msg *CatchUpResponse) error { | |
| // update state and signal to grandpa we are ready to initiate | ||
| head, err := h.grandpa.blockState.GetHeader(msg.Hash) | ||
| if err != nil { | ||
| logger.Debugf("failed to process catch up response for round %d, storing the catch up response to retry", msg.Round) | ||
| return err | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,6 +153,7 @@ func NewInstance(code []byte, cfg *Config) (*Instance, error) { | |
| codeHash: cfg.CodeHash, | ||
| } | ||
|
|
||
| // TODO: log this error in debug, trace or warn mode. Do not ignore it. | ||
|
Contributor
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. Why not just return it? |
||
| inst.version, _ = inst.Version() | ||
| return inst, nil | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.