From 23fdbf3895b2a2abecbbe508ae256defc7b70003 Mon Sep 17 00:00:00 2001 From: osrib Date: Thu, 6 Mar 2025 13:57:42 +0200 Subject: [PATCH] Adding target vote number calculation (#812) --- .../com/limechain/beefy/state/BeefyState.java | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/limechain/beefy/state/BeefyState.java b/src/main/java/com/limechain/beefy/state/BeefyState.java index 335e689a..41bd4ee1 100644 --- a/src/main/java/com/limechain/beefy/state/BeefyState.java +++ b/src/main/java/com/limechain/beefy/state/BeefyState.java @@ -20,6 +20,7 @@ import java.math.BigInteger; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -37,6 +38,7 @@ public class BeefyState extends AbstractState implements ServiceConsensusState { private static final BigInteger THRESHOLD_DENOMINATOR = BigInteger.valueOf(3); + private static final int MIN_BLOCK_DELTA = 1; private ValidatorSet validatorSet; @@ -54,6 +56,9 @@ public class BeefyState extends AbstractState implements ServiceConsensusState { @Nullable private BigInteger beefyFinalized; + @Nullable + private BigInteger grandpaFinalized; + /** * Tracks the next block number (digest) for which BEEFY should process votes or finalization. * Initialized as the maximum of beefyGenesis and beefyFinalized, or zero if genesis is unknown. @@ -67,7 +72,7 @@ public class BeefyState extends AbstractState implements ServiceConsensusState { private VoteMessage lastVote; //mapper key is mandatory block number where authority set change appeared - private Map sessions = new ConcurrentHashMap<>(); + private LinkedHashMap sessions = new LinkedHashMap<>(); //mapper key is authority public key private Map signedVotes = new ConcurrentHashMap<>(); @@ -143,6 +148,52 @@ public BigInteger getThreshold() { return numOfValidators.subtract(faulty); } + public void vote() { + + // Get the first session (round) + Map.Entry sessionStart = sessions.firstEntry(); + + // If no session is found, exit the method + if (sessionStart == null) { + log.info("Vote BEEFY: No voting round started"); + return; + } + + BigInteger sessionStartBlock = sessionStart.getKey(); + + // Calculate the target vote block number + BigInteger targetVoteBlockNumber; + + // If the mandatory block (sessionStart) does not have a beefy justification yet, vote on it + if (beefyFinalized.compareTo(sessionStartBlock) < 0) { + log.info(String.format("Vote BEEFY: vote target - mandatory block: #%s%n", sessionStartBlock)); + targetVoteBlockNumber = sessionStartBlock; + } else { + BigInteger diff = grandpaFinalized.subtract(beefyFinalized).max(BigInteger.ZERO).add(BigInteger.ONE); + int diffInt = diff.min(BigInteger.valueOf(Integer.MAX_VALUE)).intValue(); + int nextPowerOfTwo = (Integer.bitCount(diffInt) == 1) ? diffInt : Integer.highestOneBit(diffInt) << 1; + int adjustedDiff = Math.max(MIN_BLOCK_DELTA, nextPowerOfTwo); + + targetVoteBlockNumber = beefyFinalized.add(BigInteger.valueOf(adjustedDiff)); + + log.info(String.format("Vote BEEFY: vote target - diff: %d, next_power_of_two: %d, target block: #%s%n", + diffInt, nextPowerOfTwo, targetVoteBlockNumber)); + } + + // Don't vote for targets until they've been finalized (`target` can be > `bestGrandpa` when `minDelta` is big enough). + // Also, ensure it's not voting on a block that has already been voted on. + if (targetVoteBlockNumber.compareTo(grandpaFinalized) > 0 || targetVoteBlockNumber.compareTo(lastVoted) <= 0) { + return; // No voting if target is beyond grandpa finalized or it's not a new block + } + + // If it's a valid vote target, update the last voted block + lastVoted = targetVoteBlockNumber; + + // TODO: Get Beefy Keys + // TODO: Create Commitment and signature + // TODO: Broadcast Vote Message + } + private void reportDoubleVoting(VoteMessage voteMessage) { //Todo: Generate key ownership proof //Todo: Submit report double voting to Beefy api path