Skip to content

Commit

Permalink
feat: add vote power verification
Browse files Browse the repository at this point in the history
  • Loading branch information
limebell committed Apr 12, 2024
1 parent 99ad048 commit ae03e6f
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 5 deletions.
15 changes: 15 additions & 0 deletions Libplanet.Net.Tests/Consensus/HeightVoteSetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ public void CannotAddUnknownValidator()
Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));
}

[Fact]
public void CannotAddValidatorWithInvalidPower()
{
var preVote = new VoteMetadata(
2,
0,
default,
DateTimeOffset.UtcNow,
TestUtils.ValidatorSet[0].PublicKey,
TestUtils.ValidatorSet[0].Power + 1,
VoteFlag.PreVote).Sign(TestUtils.PrivateKeys[0]);

Assert.Throws<InvalidVoteException>(() => _heightVoteSet.AddVote(preVote));
}

[Fact]
public void CannotAddMultipleVotesPerRoundPerValidator()
{
Expand Down
7 changes: 7 additions & 0 deletions Libplanet.Net/Consensus/HeightVoteSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ public void AddVote(Vote vote)
vote);
}

if (_validatorSet.GetValidator(validatorKey).Power != vote.ValidatorPower)
{
const string msg = "ValidatorPower of the vote is not the same " +
"with the one in the validator set";
throw new InvalidVoteException(msg, vote);
}

if (!vote.Flag.Equals(VoteFlag.PreVote) &&
!vote.Flag.Equals(VoteFlag.PreCommit))
{
Expand Down
15 changes: 15 additions & 0 deletions Libplanet.Tests/Consensus/ValidatorSetTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,30 @@ public void ValidateBlockCommitValidators()
BigInteger.One,
VoteFlag.PreCommit).Sign(key))
.ToImmutableArray();
var invalidPowerVotes = orderedPrivateKeys
.Select(
key => new VoteMetadata(
height,
round,
hash,
DateTimeOffset.UtcNow,
key.PublicKey,
2,
VoteFlag.PreCommit).Sign(key))
.ToImmutableArray();

var blockCommitWithUnorderedVotes =
new BlockCommit(height, round, hash, unorderedVotes);
var blockCommitWithInvalidPowerVotes =
new BlockCommit(height, round, hash, unorderedVotes);
var blockCommitWithInsufficientVotes =
new BlockCommit(height, round, hash, orderedVotes.Take(5).ToImmutableArray());
var validBlockCommit = new BlockCommit(height, round, hash, orderedVotes);

Assert.False(
validatorSet.ValidateBlockCommitValidators(blockCommitWithUnorderedVotes));
Assert.False(
validatorSet.ValidateBlockCommitValidators(blockCommitWithInvalidPowerVotes));
Assert.False(
validatorSet.ValidateBlockCommitValidators(blockCommitWithInsufficientVotes));
Assert.True(validatorSet.ValidateBlockCommitValidators(validBlockCommit));
Expand Down
5 changes: 3 additions & 2 deletions Libplanet.Types/Blocks/BlockCommit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ public BlockCommit(
vote.Height != height ||
vote.Round != round ||
!blockHash.Equals(vote.BlockHash) ||
(vote.Flag != VoteFlag.Null && vote.Flag != VoteFlag.PreCommit)))
(vote.Flag != VoteFlag.Null && vote.Flag != VoteFlag.PreCommit) ||
!vote.Verify()))
{
throw new ArgumentException(
$"Every vote must have the same height as {height}, the same round " +
$"as {round}, the same hash as {blockHash}, and must have flag value of " +
$"either {VoteFlag.Null} or {VoteFlag.PreCommit}.",
$"either {VoteFlag.Null} or {VoteFlag.PreCommit}, and must be signed.",
nameof(votes));
}

Expand Down
10 changes: 7 additions & 3 deletions Libplanet.Types/Consensus/ValidatorSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,15 +249,19 @@ public Validator GetProposer(long height, int round)

/// <summary>
/// Checks whether <see cref="BlockCommit.Votes"/> is ordered
/// by <see cref="Address"/> of each <see cref="Vote.ValidatorPublicKey"/>.
/// by <see cref="Address"/> of each <see cref="Vote.ValidatorPublicKey"/>,
/// and <see cref="Vote.ValidatorPower"/> equals to the one recorded in the chain states.
/// </summary>
/// <param name="blockCommit">The <see cref="BlockCommit"/> to check.</param>
/// <returns><see langword="true"/> if the <see cref="BlockCommit.Votes"/> is
/// ordered, <see langword="false"/> otherwise.</returns>
public bool ValidateBlockCommitValidators(BlockCommit blockCommit)
{
return Validators.Select(validator => validator.PublicKey).SequenceEqual(
blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList());
return Validators.Select(validator => validator.PublicKey)
.SequenceEqual(
blockCommit.Votes.Select(vote => vote.ValidatorPublicKey).ToList()) &&
blockCommit.Votes.All(
v => v.ValidatorPower == GetValidator(v.ValidatorPublicKey).Power);
}
}
}

0 comments on commit ae03e6f

Please sign in to comment.