Skip to content

Commit

Permalink
Fix and re-enable CliqueProposeRpcAcceptanceTest (hyperledger#8324)
Browse files Browse the repository at this point in the history
Signed-off-by: Fabio Di Fabio <[email protected]>
Co-authored-by: Sally MacFarlane <[email protected]>
  • Loading branch information
fab-10 and macfarla authored Feb 20, 2025
1 parent 0e54416 commit f54e455
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,12 @@ public BesuNode createExecutionEngineGenesisNode(final String name, final String

public BesuNode createCliqueNodeWithValidators(final String name, final String... validators)
throws IOException {
return createCliqueNodeWithValidators(name, CliqueOptions.DEFAULT, validators);
}

public BesuNode createCliqueNodeWithValidators(
final String name, final CliqueOptions cliqueOptions, final String... validators)
throws IOException {

return create(
new BesuNodeConfigurationBuilder()
Expand All @@ -553,7 +559,9 @@ public BesuNode createCliqueNodeWithValidators(final String name, final String..
node.createGenesisConfigForValidators(
asList(validators),
nodes,
GenesisConfigurationFactory::createCliqueGenesisConfig))
vs ->
GenesisConfigurationFactory.createCliqueGenesisConfig(
vs, cliqueOptions)))
.build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,114 +18,134 @@
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.condition.clique.ExpectNonceVote.CLIQUE_NONCE_VOTE;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory;

import java.io.IOException;
import java.util.Arrays;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

@Disabled("flaky see https://github.com/hyperledger/besu/issues/7973")
public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase {
private static final GenesisConfigurationFactory.CliqueOptions CLIQUE_OPTIONS =
new GenesisConfigurationFactory.CliqueOptions(5, 30000, true);

@Test
public void shouldAddValidators() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
public void shouldAddAndRemoveValidators() throws IOException {
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);

waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
}

@Test
public void shouldRemoveValidators() throws IOException {
final String[] initialValidators = {"miner1", "miner2", "miner3"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);

waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);

cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
final Condition cliqueValidatorsChanged = clique.awaitSignerSetChange(minerNode1);
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode3));
final Condition cliqueValidatorsChanged = clique.awaitSignerSetChange(minerNode2);
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode1));
minerNode3.execute(cliqueTransactions.createRemoveProposal(minerNode1));
cluster.verify(clique.validatorsEqual(minerNode2, minerNode3));
cluster.verify(cliqueValidatorsChanged);
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
}

@Disabled
@Test
public void shouldNotAddValidatorWhenInsufficientVotes() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);

waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
}

@Test
public void shouldNotRemoveValidatorWhenInsufficientVotes() throws IOException {
final BesuNode minerNode1 = besu.createCliqueNode("miner1");
final BesuNode minerNode2 = besu.createCliqueNode("miner2");
final BesuNode minerNode3 = besu.createCliqueNode("miner3");
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);

waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));

minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
}

@Disabled
@Test
public void shouldIncludeVoteInBlockHeader() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);

waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
minerNode1.verify(blockchain.beneficiaryEquals(minerNode2));
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.AUTH));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));

minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
minerNode2.verify(blockchain.reachesHeight(minerNode1, 1));
minerNode1.verify(blockchain.beneficiaryEquals(minerNode3));
minerNode2.verify(blockchain.beneficiaryEquals(minerNode3));
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.AUTH));
minerNode2.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.AUTH));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));

minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode2));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
minerNode1.verify(blockchain.beneficiaryEquals(minerNode2));
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.DROP));
}

private void waitForNodesConnectedAndInSync(
final BesuNode minerNode1, final BesuNode minerNode2, final BesuNode minerNode3) {
private void waitForNodesConnectedAndInSync(final BesuNode... nodes) {
// verify nodes are fully connected otherwise blocks could not be propagated
minerNode1.verify(net.awaitPeerCount(2));
minerNode2.verify(net.awaitPeerCount(2));
minerNode3.verify(net.awaitPeerCount(2));
Arrays.stream(nodes).forEach(node -> node.verify(net.awaitPeerCount(nodes.length - 1)));

// verify that the miner started producing blocks and all other nodes are syncing from it
waitForBlockHeight(minerNode1, 1);
final var minerChainHead = minerNode1.execute(ethTransactions.block());
minerNode2.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
minerNode3.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
waitForBlockHeight(nodes[0], 1);
final var firstNodeChainHead = nodes[0].execute(ethTransactions.block());
Arrays.stream(nodes)
.skip(1)
.forEach(node -> waitForBlockHeight(node, firstNodeChainHead.getNumber().longValue()));
}
}

0 comments on commit f54e455

Please sign in to comment.