Skip to content

Commit 470bfba

Browse files
authored
store finalization in replication path (#338)
1 parent 6ea24f4 commit 470bfba

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

epoch.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,7 @@ func (e *Epoch) processFinalizedBlock(block Block, finalization *Finalization) e
18611861
zap.Stringer("expected digest", blockDependency),
18621862
zap.Uint64s("missing rounds", missingRounds),
18631863
)
1864+
return errors.New("Received a finalization for nextSeqToCommit that breaks our chain")
18641865
}
18651866

18661867
// Create a task that will verify the block in the future, after its predecessors have also been verified.
@@ -2050,6 +2051,15 @@ func (e *Epoch) createFinalizedBlockVerificationTask(block Block, finalization *
20502051
return md.Digest
20512052
}
20522053

2054+
// Store the verified block in rounds map so subsequent blocks can find it as a dependency
2055+
roundEntry := NewRound(verifiedBlock)
2056+
roundEntry.finalization = finalization
2057+
e.rounds[md.Round] = roundEntry
2058+
e.Logger.Debug("Stored finalized replicated block in rounds map",
2059+
zap.Uint64("round", md.Round),
2060+
zap.Uint64("seq", md.Seq),
2061+
zap.Stringer("digest", md.Digest))
2062+
20532063
if err := e.indexFinalization(verifiedBlock, *finalization); err != nil {
20542064
e.haltedError = err
20552065
e.Logger.Error("Failed to index finalization", zap.Error(err))

replication_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,78 @@ func allowFinalizeVotes(msg *simplex.Message, from, to simplex.NodeID) bool {
13281328
return true
13291329
}
13301330

1331+
// TestReplicationStoresFinalization checks finalizations are stored in the rounds
1332+
// map when processing.
1333+
func TestReplicationStoresFinalization(t *testing.T) {
1334+
bb := testutil.NewTestBlockBuilder()
1335+
nodes := []simplex.NodeID{{1}, {2}, {3}, {4}}
1336+
sentMessages := make(chan *simplex.Message, 100)
1337+
1338+
conf, _, storage := DefaultTestNodeEpochConfig(t, nodes[3], &recordingComm{
1339+
Communication: NoopComm(nodes),
1340+
SentMessages: sentMessages,
1341+
}, bb)
1342+
conf.ReplicationEnabled = true
1343+
1344+
e, err := simplex.NewEpoch(conf)
1345+
require.NoError(t, err)
1346+
require.NoError(t, e.Start())
1347+
1348+
// createBlocks 2 blocks with finalizations
1349+
blocks := createBlocks(t, nodes, 2)
1350+
vote, err := NewTestVote(blocks[0].VerifiedBlock.(simplex.Block), nodes[0])
1351+
require.NoError(t, err)
1352+
// send block 1
1353+
e.HandleMessage(&simplex.Message{
1354+
BlockMessage: &simplex.BlockMessage{
1355+
Block: blocks[0].VerifiedBlock.(simplex.Block),
1356+
Vote: *vote,
1357+
},
1358+
}, nodes[0])
1359+
1360+
// Send a finalization for block 2 to trigger replication
1361+
finalization := blocks[1].Finalization
1362+
e.HandleMessage(&simplex.Message{
1363+
Finalization: &finalization,
1364+
}, nodes[1])
1365+
1366+
// Wait for the replication request to be sent
1367+
for {
1368+
msg := <-sentMessages
1369+
if msg.ReplicationRequest != nil {
1370+
break
1371+
}
1372+
}
1373+
1374+
// pass in replication response to epoch with both blocks and their finalizations
1375+
quorumRounds := []simplex.QuorumRound{
1376+
{
1377+
Block: blocks[0].VerifiedBlock.(simplex.Block),
1378+
Finalization: &blocks[0].Finalization,
1379+
},
1380+
{
1381+
Block: blocks[1].VerifiedBlock.(simplex.Block),
1382+
Finalization: &blocks[1].Finalization,
1383+
},
1384+
}
1385+
1386+
replicationResponse := &simplex.ReplicationResponse{
1387+
Data: quorumRounds,
1388+
}
1389+
1390+
e.HandleMessage(&simplex.Message{
1391+
ReplicationResponse: replicationResponse,
1392+
}, nodes[1])
1393+
1394+
// Verify both blocks are committed
1395+
for i := range 2 {
1396+
committed := storage.WaitForBlockCommit(uint64(i))
1397+
require.Equal(t, blocks[i].VerifiedBlock, committed)
1398+
}
1399+
1400+
require.Equal(t, uint64(2), storage.NumBlocks())
1401+
}
1402+
13311403
// TestReplicationChain tests that a node can both empty notarizations and notarizations for the same round.
13321404
func TestReplicationChain(t *testing.T) {
13331405
// Digest message requests are needed for this test

0 commit comments

Comments
 (0)