Skip to content

Commit

Permalink
728 Implement PreCommit Stage (#749)
Browse files Browse the repository at this point in the history
# Description

- If ```round.isCompletable() = true``` or timer ```Time >= t + 4 * T```
is expires -> end pre-commit stage
- end() method waits ```round.getGrandpaGhost()``` to have a value
before proceeding to the next stage
- Once GrandpaGhost is available, a vote message is broadcast
- ```isCompleted``` field is added to ```GrandpaRound``` that is
updated, when ```findGrandpaGhost``` is executed and the previous method
for checking if the round is completable is renamed to
```checkIfCompletable```

Fixes #728

---------

Co-authored-by: Hristiyan Mitov <[email protected]>
Co-authored-by: Hristiyan Mitov <[email protected]>
  • Loading branch information
3 people authored Feb 11, 2025
1 parent 3f67133 commit 0e92cf1
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class CompletedStage implements StageState {
@Override
public void start(GrandpaRound round) {
round.setOnFinalizeHandler(null);
round.getOnStageTimerHandler().shutdown();
round.clearOnStageTimerHandler();
end(round);
}

Expand Down
24 changes: 19 additions & 5 deletions src/main/java/com/limechain/grandpa/round/GrandpaRound.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ public class GrandpaRound {
@Nullable
private Vote preCommitChoice;

/**
* Updated when the Grandpa Ghost is calculated.<BR>
* Default value is false.
*/
private boolean isCompletable;

private Map<Hash256, SignedVote> preVotes = new ConcurrentHashMap<>();
private Map<Hash256, SignedVote> preCommits = new ConcurrentHashMap<>();
private Vote primaryVote;
Expand Down Expand Up @@ -248,7 +254,7 @@ private boolean isFinalizable() {
*
* @return if the current round is completable
*/
private boolean isCompletable() {
public boolean checkIfCompletable() {

Map<Vote, Long> votes = getDirectVotes(SubRound.PRE_COMMIT);
long votesCount = votes.values().stream()
Expand Down Expand Up @@ -350,7 +356,7 @@ private BlockHeader findBestFinalCandidate() {
*
* @return GRANDPA GHOST block as a vote
*/
private BlockHeader findGrandpaGhost() {
public BlockHeader findGrandpaGhost() {

if (roundNumber.equals(BigInteger.ZERO)) {
return lastFinalizedBlock;
Expand All @@ -362,10 +368,11 @@ private BlockHeader findGrandpaGhost() {
throw new GhostExecutionException("GHOST not found");
}

BlockHeader grandpaGhost = selectBlockWithMostVotes(blocks, getPrevBestFinalCandidate());
this.grandpaGhost = grandpaGhost;
BlockHeader result = selectBlockWithMostVotes(blocks, getPrevBestFinalCandidate());
this.grandpaGhost = result;
this.isCompletable = checkIfCompletable();

return grandpaGhost;
return result;
}

/**
Expand Down Expand Up @@ -650,4 +657,11 @@ public void broadcastCommitMessage() {

peerMessageCoordinator.sendCommitMessageToPeers(commitMessage);
}

public void clearOnStageTimerHandler() {
if (onStageTimerHandler != null && onStageTimerHandler.isShutdown()) {
onStageTimerHandler.shutdown();
onStageTimerHandler = null;
}
}
}
42 changes: 40 additions & 2 deletions src/main/java/com/limechain/grandpa/round/PreCommitStage.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,51 @@
package com.limechain.grandpa.round;

import com.limechain.exception.grandpa.GrandpaGenericException;
import com.limechain.grandpa.vote.SubRound;
import com.limechain.grandpa.vote.Vote;
import lombok.extern.java.Log;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Log
public class PreCommitStage implements StageState {

@Override
public void start(GrandpaRound round) {
log.fine(String.format("Round %d started pre-commit stage.", round.getRoundNumber()));

if (round.isCompletable()) {
end(round);
return;
}

long timeElapsed = System.currentTimeMillis() - round.getStartTime().toEpochMilli();
long timeRemaining = (4 * GrandpaRound.DURATION) - timeElapsed;

round.setOnStageTimerHandler(Executors.newScheduledThreadPool(1));
round.getOnStageTimerHandler().schedule(() -> {
log.fine(String.format("Round %d timer triggered.", round.getRoundNumber()));
end(round);
}, timeRemaining, TimeUnit.MILLISECONDS);
}

@Override
public void end(GrandpaRound round) {
}
}

round.clearOnStageTimerHandler();

try {

Vote grandpaGhost = Vote.fromBlockHeader(round.getGrandpaGhost());
log.fine(String.format("Round %d ended pre-commit stage.", round.getRoundNumber()));

round.broadcastVoteMessage(grandpaGhost, SubRound.PRE_COMMIT);
round.setState(new FinalizeStage());
round.getState().start(round);

} catch (GrandpaGenericException e) {
log.fine(String.format("Round %d cannot end now: %s", round.getRoundNumber(), e.getMessage()));
}
}
}

0 comments on commit 0e92cf1

Please sign in to comment.