*: qbft improvements#4560
Conversation
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## pinebit/qbft-fixes #4560 +/- ##
======================================================
+ Coverage 57.08% 57.11% +0.03%
======================================================
Files 245 245
Lines 33229 33246 +17
======================================================
+ Hits 18969 18989 +20
+ Misses 11869 11868 -1
+ Partials 2391 2389 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR tightens and refactors QBFT-related p2p handling to better bound resource usage under oversized or adversarial messages, while cleaning up resend/rate-limit logic in the QBFT core algorithm.
Changes:
- Add a configurable p2p read-size cap (
WithReadLimit) and cover it with a unit test. - Refactor the post-decision
MsgDecidedrebroadcast gating into a helper (allowDecidedResend). - Add a QBFT consensus wire-message size cap (32MB) and refactor/extend message limit verification and early cancellation checks during justification verification.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| p2p/sender.go | Adds WithReadLimit option to cap delimited reader message sizes. |
| p2p/sender_test.go | Adds test ensuring oversized messages are rejected before reaching the handler. |
| core/qbft/qbft.go | Refactors decided rebroadcast limiting into allowDecidedResend. |
| core/consensus/qbft/qbft.go | Applies read-limit to QBFT handler, adds max message size constant, and refactors message limit verification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return func(opts *sendRecvOpts) { | ||
| for _, pID := range opts.protocols { | ||
| opts.readersByProtocol[pID] = func(s network.Stream) pbio.Reader { | ||
| return pbio.NewDelimitedReader(s, limit) | ||
| } | ||
| } | ||
| } |
| allowDecidedResend := func(source, round int64) bool { | ||
| resend, ok := decidedResends[source] | ||
| if !ok && len(decidedResends) >= d.Nodes { | ||
| return false | ||
| } | ||
|
|
||
| if round <= resend.Round || resend.Count >= maxDecidedResends { | ||
| return false | ||
| } | ||
|
|
||
| decidedResends[source] = decidedResend{Round: round, Count: resend.Count + 1} | ||
|
|
||
| return true | ||
| } |
| // small justification sub-messages (bounded in handle) plus its values, the largest of | ||
| // which is a single block proposal (a few MB on mainnet); 32MB leaves ample margin while | ||
| // bounding the receive/decode/allocation cost a malicious peer can inflict per message. | ||
| const maxConsensusMsgSize = 32 * 1024 * 1024 // 32 MB. |
There was a problem hiding this comment.
I hope you know this is sufficient.. I saw full blocks ~20Mb in our metrics, it is close to 32...



Refactors and extra checks
category: refactor
ticket: none