Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c58597d

Browse files
authoredApr 26, 2023
Fix TestStateOversizedBlock (celestiaorg#755)
* Fix TestStateOversizedBlock * Moved `findBlockSizeLimit` together with other aux functions
1 parent 2373e27 commit c58597d

File tree

1 file changed

+101
-55
lines changed

1 file changed

+101
-55
lines changed
 

‎consensus/state_test.go

+101-55
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"strings"
78
"testing"
89
"time"
910

@@ -256,73 +257,88 @@ func TestStateBadProposal(t *testing.T) {
256257
}
257258

258259
func TestStateOversizedBlock(t *testing.T) {
259-
ctx, cancel := context.WithCancel(context.Background())
260-
defer cancel()
260+
const maxBytes = 2000
261261

262-
cs1, vss := randState(2)
263-
cs1.state.ConsensusParams.Block.MaxBytes = 2000
264-
height, round := cs1.Height, cs1.Round
265-
vs2 := vss[1]
266-
267-
partSize := types.BlockPartSizeBytes
268-
269-
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
270-
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
271-
272-
propBlock, err := cs1.createProposalBlock(ctx)
273-
require.NoError(t, err)
274-
propBlock.Data.Txs = []types.Tx{cmtrand.Bytes(2001)}
275-
propBlock.Header.DataHash = propBlock.Data.Hash()
262+
for _, testCase := range []struct {
263+
name string
264+
oversized bool
265+
}{
266+
{
267+
name: "max size, correct block",
268+
oversized: false,
269+
},
270+
{
271+
name: "off-by-1 max size, incorrect block",
272+
oversized: true,
273+
},
274+
} {
275+
t.Run(testCase.name, func(t *testing.T) {
276+
cs1, vss := randState(2)
277+
cs1.state.ConsensusParams.Block.MaxBytes = maxBytes
278+
height, round := cs1.Height, cs1.Round
279+
vs2 := vss[1]
276280

277-
// make the second validator the proposer by incrementing round
278-
round++
279-
incrementRound(vss[1:]...)
281+
partSize := types.BlockPartSizeBytes
280282

281-
propBlockParts, err := propBlock.MakePartSet(partSize)
282-
require.NoError(t, err)
283-
blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
284-
proposal := types.NewProposal(height, round, -1, blockID)
285-
p := proposal.ToProto()
286-
if err := vs2.SignProposal(cs1.state.ChainID, p); err != nil {
287-
t.Fatal("failed to sign bad proposal", err)
288-
}
289-
proposal.Signature = p.Signature
283+
propBlock, propBlockParts := findBlockSizeLimit(t, height, maxBytes, cs1, partSize, testCase.oversized)
290284

291-
totalBytes := 0
292-
for i := 0; i < int(propBlockParts.Total()); i++ {
293-
part := propBlockParts.GetPart(i)
294-
totalBytes += len(part.Bytes)
295-
}
285+
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
286+
voteCh := subscribe(cs1.eventBus, types.EventQueryVote)
296287

297-
if err := cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
298-
t.Fatal(err)
299-
}
288+
// make the second validator the proposer by incrementing round
289+
round++
290+
incrementRound(vss[1:]...)
300291

301-
// start the machine
302-
startTestRound(cs1, height, round)
292+
blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
293+
proposal := types.NewProposal(height, round, -1, blockID)
294+
p := proposal.ToProto()
295+
if err := vs2.SignProposal(cs1.state.ChainID, p); err != nil {
296+
t.Fatal("failed to sign bad proposal", err)
297+
}
298+
proposal.Signature = p.Signature
303299

304-
t.Log("Block Sizes", "Limit", cs1.state.ConsensusParams.Block.MaxBytes, "Current", totalBytes)
300+
totalBytes := 0
301+
for i := 0; i < int(propBlockParts.Total()); i++ {
302+
part := propBlockParts.GetPart(i)
303+
totalBytes += len(part.Bytes)
304+
}
305305

306-
// c1 should log an error with the block part message as it exceeds the consensus params. The
307-
// block is not added to cs.ProposalBlock so the node timeouts.
308-
ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
306+
if err := cs1.SetProposalAndBlock(proposal, propBlock, propBlockParts, "some peer"); err != nil {
307+
t.Fatal(err)
308+
}
309309

310-
// and then should send nil prevote and precommit regardless of whether other validators prevote and
311-
// precommit on it
312-
ensurePrevote(voteCh, height, round)
313-
validatePrevote(t, cs1, round, vss[0], nil)
310+
// start the machine
311+
startTestRound(cs1, height, round)
312+
313+
t.Log("Block Sizes;", "Limit", cs1.state.ConsensusParams.Block.MaxBytes, "Current", totalBytes)
314+
315+
validateHash := propBlock.Hash()
316+
lockedRound := int32(1)
317+
if testCase.oversized {
318+
validateHash = nil
319+
lockedRound = -1
320+
// if the block is oversized cs1 should log an error with the block part message as it exceeds
321+
// the consensus params. The block is not added to cs.ProposalBlock so the node timeouts.
322+
ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.Propose(round).Nanoseconds())
323+
// and then should send nil prevote and precommit regardless of whether other validators prevote and
324+
// precommit on it
325+
}
326+
ensurePrevote(voteCh, height, round)
327+
validatePrevote(t, cs1, round, vss[0], validateHash)
314328

315-
bps, err := propBlock.MakePartSet(partSize)
316-
require.NoError(t, err)
329+
bps, err := propBlock.MakePartSet(partSize)
330+
require.NoError(t, err)
317331

318-
signAddVotes(cs1, cmtproto.PrevoteType, propBlock.Hash(), bps.Header(), false, vs2)
319-
ensurePrevote(voteCh, height, round)
320-
ensurePrecommit(voteCh, height, round)
321-
validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
332+
signAddVotes(cs1, cmtproto.PrevoteType, propBlock.Hash(), bps.Header(), false, vs2)
333+
ensurePrevote(voteCh, height, round)
334+
ensurePrecommit(voteCh, height, round)
335+
validatePrecommit(t, cs1, round, lockedRound, vss[0], validateHash, validateHash)
322336

323-
bps2, err := propBlock.MakePartSet(partSize)
324-
require.NoError(t, err)
325-
signAddVotes(cs1, cmtproto.PrecommitType, propBlock.Hash(), bps2.Header(), true, vs2)
337+
bps2, err := propBlock.MakePartSet(partSize)
338+
require.NoError(t, err)
339+
signAddVotes(cs1, cmtproto.PrecommitType, propBlock.Hash(), bps2.Header(), true, vs2)
340+
})
341+
}
326342
}
327343

328344
//----------------------------------------------------------------------------------------------------
@@ -2516,3 +2532,33 @@ func signAddPrecommitWithExtension(
25162532
require.NoError(t, err, "failed to sign vote")
25172533
addVotes(cs, v)
25182534
}
2535+
2536+
func findBlockSizeLimit(t *testing.T, height, maxBytes int64, cs *State, partSize uint32, oversized bool) (*types.Block, *types.PartSet) {
2537+
var offset int64
2538+
if !oversized {
2539+
offset = -2
2540+
}
2541+
softMaxDataBytes := int(types.MaxDataBytes(maxBytes, 0, 0))
2542+
for i := softMaxDataBytes; i < softMaxDataBytes*2; i++ {
2543+
propBlock := cs.state.MakeBlock(
2544+
height,
2545+
[]types.Tx{[]byte("a=" + strings.Repeat("o", i-2))},
2546+
&types.Commit{},
2547+
nil,
2548+
cs.privValidatorPubKey.Address(),
2549+
)
2550+
2551+
propBlockParts, err := propBlock.MakePartSet(partSize)
2552+
require.NoError(t, err)
2553+
if propBlockParts.ByteSize() > maxBytes+offset {
2554+
s := "real max"
2555+
if oversized {
2556+
s = "off-by-1"
2557+
}
2558+
t.Log("Detected "+s+" data size for block;", "size", i, "softMaxDataBytes", softMaxDataBytes)
2559+
return propBlock, propBlockParts
2560+
}
2561+
}
2562+
require.Fail(t, "We shouldn't hit the end of the loop")
2563+
return nil, nil
2564+
}

0 commit comments

Comments
 (0)
Please sign in to comment.