mirror of https://github.com/hyperledger/besu
Clique acceptance tests (#290)
parent
24b8d730e4
commit
ab744a916c
@ -0,0 +1,49 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.clique; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class CliqueDiscardRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldDiscardVotes() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode2)); |
||||
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode2)); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode1.execute(cliqueTransactions.createDiscardProposal(minerNode2)); |
||||
minerNode1.execute(cliqueTransactions.createDiscardProposal(minerNode3)); |
||||
|
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 2)); |
||||
|
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); |
||||
minerNode1.verify(clique.noProposals()); |
||||
minerNode2.verify( |
||||
clique.proposalsEqual().removeProposal(minerNode2).addProposal(minerNode3).build()); |
||||
} |
||||
} |
@ -0,0 +1,68 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.clique; |
||||
|
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class CliqueGetSignersRpcTest extends AcceptanceTestBase { |
||||
private PantheonNode minerNode1; |
||||
private PantheonNode minerNode2; |
||||
private PantheonNode minerNode3; |
||||
private PantheonNode[] allNodes; |
||||
private PantheonNode[] initialNodes; |
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
final String[] validators = {"miner1", "miner2"}; |
||||
minerNode1 = pantheon.createCliqueNodeWithValidators("miner1", validators); |
||||
minerNode2 = pantheon.createCliqueNodeWithValidators("miner2", validators); |
||||
minerNode3 = pantheon.createCliqueNodeWithValidators("miner3", validators); |
||||
initialNodes = new PantheonNode[] {minerNode1, minerNode2}; |
||||
allNodes = new PantheonNode[] {minerNode1, minerNode2, minerNode3}; |
||||
cluster.start(allNodes); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldBeAbleToGetValidatorsForBlockNumber() { |
||||
cluster.verify(clique.validatorsAtBlockEqual("0x0", initialNodes)); |
||||
cluster.waitUntil(wait.chainHeadIsAt(1)); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
|
||||
cluster.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsAtBlockEqual("0x2", initialNodes)); |
||||
|
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsAtBlockEqual("0x3", allNodes)); |
||||
cluster.verify(clique.validatorsAtBlockEqual(LATEST, allNodes)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldBeAbleToGetValidatorsForBlockHash() { |
||||
cluster.verify(clique.validatorsAtBlockHashFromBlockNumberEqual(minerNode1, 0, initialNodes)); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
|
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsAtBlockHashFromBlockNumberEqual(minerNode1, 1, initialNodes)); |
||||
|
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsAtBlockHashFromBlockNumberEqual(minerNode1, 3, allNodes)); |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.clique; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.account.Account; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class CliqueMiningAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldMineTransactionsOnSingleNode() throws IOException { |
||||
final PantheonNode minerNode = pantheon.createCliqueNode("miner1"); |
||||
cluster.start(minerNode); |
||||
|
||||
final Account sender = accounts.createAccount("account1"); |
||||
final Account receiver = accounts.createAccount("account2"); |
||||
|
||||
minerNode.execute(transactions.createTransfer(sender, 50)); |
||||
cluster.verify(sender.balanceEquals(50)); |
||||
|
||||
minerNode.execute(transactions.createIncrementalTransfers(sender, receiver, 1)); |
||||
cluster.verify(receiver.balanceEquals(1)); |
||||
|
||||
minerNode.execute(transactions.createIncrementalTransfers(sender, receiver, 2)); |
||||
cluster.verify(receiver.balanceEquals(3)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldMineTransactionsOnMultipleNodes() throws IOException { |
||||
final PantheonNode minerNode1 = pantheon.createCliqueNode("miner1"); |
||||
final PantheonNode minerNode2 = pantheon.createCliqueNode("miner2"); |
||||
final PantheonNode minerNode3 = pantheon.createCliqueNode("miner3"); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
final Account sender = accounts.createAccount("account1"); |
||||
final Account receiver = accounts.createAccount("account2"); |
||||
|
||||
minerNode1.execute(transactions.createTransfer(sender, 50)); |
||||
cluster.verify(sender.balanceEquals(50)); |
||||
|
||||
minerNode2.execute(transactions.createIncrementalTransfers(sender, receiver, 1)); |
||||
cluster.verify(receiver.balanceEquals(1)); |
||||
|
||||
minerNode3.execute(transactions.createIncrementalTransfers(sender, receiver, 2)); |
||||
cluster.verify(receiver.balanceEquals(3)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldStallMiningWhenInsufficientValidators() throws IOException { |
||||
final PantheonNode minerNode1 = pantheon.createCliqueNode("miner1"); |
||||
final PantheonNode minerNode2 = pantheon.createCliqueNode("miner2"); |
||||
final PantheonNode minerNode3 = pantheon.createCliqueNode("miner3"); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.stopNode(minerNode2); |
||||
cluster.stopNode(minerNode3); |
||||
minerNode1.verify(net.awaitPeerCount(0)); |
||||
minerNode1.verify(clique.noNewBlockCreated(minerNode1)); |
||||
} |
||||
} |
@ -0,0 +1,45 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.clique; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class CliqueProposalRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldReturnProposals() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.verify(clique.noProposals()); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode2)); |
||||
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode3)); |
||||
|
||||
minerNode1.verify( |
||||
clique.proposalsEqual().addProposal(minerNode3).removeProposal(minerNode2).build()); |
||||
minerNode2.verify(clique.proposalsEqual().removeProposal(minerNode3).build()); |
||||
minerNode3.verify(clique.noProposals()); |
||||
} |
||||
} |
@ -0,0 +1,115 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.clique; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique.ExpectNonceVote.CLIQUE_NONCE_VOTE; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition.WaitCondition; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldAddValidators() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); |
||||
final WaitCondition cliqueValidatorsChanged = wait.cliqueValidatorsChanged(minerNode1); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
cluster.waitUntil(cliqueValidatorsChanged); |
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldRemoveValidators() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2", "miner3"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3)); |
||||
final WaitCondition cliqueValidatorsChanged = wait.cliqueValidatorsChanged(minerNode1); |
||||
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3)); |
||||
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode3)); |
||||
cluster.waitUntil(cliqueValidatorsChanged); |
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldNotAddValidatorWhenInsufficientVotes() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); |
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldNotRemoveValidatorWhenInsufficientVotes() throws IOException { |
||||
final PantheonNode minerNode1 = pantheon.createCliqueNode("miner1"); |
||||
final PantheonNode minerNode2 = pantheon.createCliqueNode("miner2"); |
||||
final PantheonNode minerNode3 = pantheon.createCliqueNode("miner3"); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3)); |
||||
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3)); |
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3)); |
||||
} |
||||
|
||||
@Test |
||||
public void shouldIncludeVoteInBlockHeader() throws IOException { |
||||
final String[] initialValidators = {"miner1", "miner2"}; |
||||
final PantheonNode minerNode1 = |
||||
pantheon.createCliqueNodeWithValidators("miner1", initialValidators); |
||||
final PantheonNode minerNode2 = |
||||
pantheon.createCliqueNodeWithValidators("miner2", initialValidators); |
||||
final PantheonNode minerNode3 = |
||||
pantheon.createCliqueNodeWithValidators("miner3", initialValidators); |
||||
cluster.start(minerNode1, minerNode2, minerNode3); |
||||
|
||||
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3)); |
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
minerNode1.verify(blockchain.beneficiaryEquals(minerNode3)); |
||||
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.AUTH)); |
||||
|
||||
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode2)); |
||||
minerNode1.waitUntil(wait.chainHeadHasProgressed(minerNode1, 1)); |
||||
minerNode1.verify(blockchain.beneficiaryEquals(minerNode2)); |
||||
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.DROP)); |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.blockchain; |
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
public class ExpectBeneficiary implements Condition { |
||||
private final EthTransactions eth; |
||||
private final String beneficiary; |
||||
|
||||
public ExpectBeneficiary(final EthTransactions eth, final PantheonNode node) { |
||||
this.eth = eth; |
||||
this.beneficiary = node.getAddress().toString(); |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor(() -> assertThat(node.execute(eth.block()).getMiner()).isEqualTo(beneficiary)); |
||||
} |
||||
} |
@ -0,0 +1,76 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.blockchain; |
||||
|
||||
import static junit.framework.TestCase.fail; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
||||
import org.awaitility.Awaitility; |
||||
|
||||
public class ExpectBlockNotCreated implements Condition { |
||||
private final EthTransactions eth; |
||||
private final int initialWait; |
||||
private final int blockPeriodWait; |
||||
|
||||
public ExpectBlockNotCreated( |
||||
final EthTransactions eth, final int initialWait, final int blockPeriodWait) { |
||||
this.eth = eth; |
||||
this.initialWait = initialWait; |
||||
this.blockPeriodWait = blockPeriodWait; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
final AtomicInteger tries = new AtomicInteger(); |
||||
final int triesRequired = blockPeriodWait / 1000; |
||||
final BigInteger initialBlock = initialBlock(node); |
||||
Awaitility.await() |
||||
.pollInterval(1, TimeUnit.SECONDS) |
||||
.atMost(30, TimeUnit.SECONDS) |
||||
.until(() -> isNewBlock(node, tries, triesRequired, initialBlock)); |
||||
} |
||||
|
||||
private Boolean isNewBlock( |
||||
final Node node, |
||||
final AtomicInteger tries, |
||||
final int triesRequired, |
||||
final BigInteger lastBlock) { |
||||
final BigInteger currentBlock = node.execute(eth.blockNumber()); |
||||
final int currentTries = tries.getAndIncrement(); |
||||
if (!currentBlock.equals(lastBlock)) { |
||||
final String failMsg = |
||||
String.format( |
||||
"New block created. Expected block=%s got block=%s", lastBlock, currentBlock); |
||||
fail(failMsg); |
||||
} |
||||
// Only consider that the block is really the same after a period of time or number tries as a
|
||||
// block could be currently be in the process of being mined
|
||||
return currentTries > triesRequired; |
||||
} |
||||
|
||||
private BigInteger initialBlock(final Node node) { |
||||
try { |
||||
Thread.sleep(initialWait); |
||||
return node.execute(eth.blockNumber()); |
||||
} catch (InterruptedException e) { |
||||
throw new IllegalStateException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.blockchain; |
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
public class ExpectBlockNumber implements Condition { |
||||
private final EthTransactions eth; |
||||
private final BigInteger blockNumber; |
||||
|
||||
public ExpectBlockNumber(final EthTransactions eth, final BigInteger blockNumber) { |
||||
this.eth = eth; |
||||
this.blockNumber = blockNumber; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor(() -> assertThat(node.execute(eth.blockNumber())).isEqualTo(blockNumber)); |
||||
} |
||||
} |
@ -0,0 +1,123 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static tech.pegasys.pantheon.ethereum.core.Hash.fromHexString; |
||||
|
||||
import tech.pegasys.pantheon.config.CliqueConfigOptions; |
||||
import tech.pegasys.pantheon.config.GenesisConfigFile; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.blockchain.ExpectBlockNotCreated; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique.ExpectNonceVote.CLIQUE_NONCE_VOTE; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.Arrays; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import com.google.common.collect.ImmutableMap; |
||||
import org.web3j.protocol.core.DefaultBlockParameter; |
||||
|
||||
public class CliqueConditions { |
||||
private final EthTransactions eth; |
||||
private final CliqueTransactions clique; |
||||
|
||||
public CliqueConditions(final EthTransactions eth, final CliqueTransactions clique) { |
||||
this.eth = eth; |
||||
this.clique = clique; |
||||
} |
||||
|
||||
public ExpectValidators validatorsEqual(final PantheonNode... validators) { |
||||
return new ExpectValidators(clique, validatorAddresses(validators)); |
||||
} |
||||
|
||||
public Condition validatorsAtBlockEqual( |
||||
final String blockNumber, final PantheonNode... validators) { |
||||
return new ExpectValidatorsAtBlock(clique, blockNumber, validatorAddresses(validators)); |
||||
} |
||||
|
||||
public Condition validatorsAtBlockHashFromBlockNumberEqual( |
||||
final Node node, final long blockNumber, final PantheonNode... validators) { |
||||
final DefaultBlockParameter blockParameter = |
||||
DefaultBlockParameter.valueOf(BigInteger.valueOf(blockNumber)); |
||||
final String blockHash = node.execute(eth.block(blockParameter)).getHash(); |
||||
return new ExpectValidatorsAtBlockHash( |
||||
clique, fromHexString(blockHash), validatorAddresses(validators)); |
||||
} |
||||
|
||||
public ProposalsConfig proposalsEqual() { |
||||
return new ProposalsConfig(clique); |
||||
} |
||||
|
||||
public Condition noProposals() { |
||||
return new ExpectProposals(clique, ImmutableMap.of()); |
||||
} |
||||
|
||||
public Condition nonceVoteEquals(final CLIQUE_NONCE_VOTE clique_nonce_vote) { |
||||
return new ExpectNonceVote(eth, clique_nonce_vote); |
||||
} |
||||
|
||||
public Condition noNewBlockCreated(final PantheonNode node) { |
||||
final int blockPeriodSeconds = cliqueBlockPeriod(node); |
||||
final int blockPeriodWait = blockPeriodSeconds * 1000; |
||||
return new ExpectBlockNotCreated(eth, blockPeriodWait, blockPeriodWait); |
||||
} |
||||
|
||||
private int cliqueBlockPeriod(final PantheonNode node) { |
||||
final String config = node.genesisConfigProvider().createGenesisConfig(emptyList()).get(); |
||||
final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(config); |
||||
final CliqueConfigOptions cliqueConfigOptions = |
||||
genesisConfigFile.getConfigOptions().getCliqueConfigOptions(); |
||||
return cliqueConfigOptions.getBlockPeriodSeconds(); |
||||
} |
||||
|
||||
private Address[] validatorAddresses(final PantheonNode[] validators) { |
||||
return Arrays.stream(validators).map(PantheonNode::getAddress).sorted().toArray(Address[]::new); |
||||
} |
||||
|
||||
public static class ProposalsConfig { |
||||
private final Map<PantheonNode, Boolean> proposals = new HashMap<>(); |
||||
private final CliqueTransactions clique; |
||||
|
||||
public ProposalsConfig(final CliqueTransactions clique) { |
||||
this.clique = clique; |
||||
} |
||||
|
||||
public ProposalsConfig addProposal(final PantheonNode node) { |
||||
proposals.put(node, true); |
||||
return this; |
||||
} |
||||
|
||||
public ProposalsConfig removeProposal(final PantheonNode node) { |
||||
proposals.put(node, false); |
||||
return this; |
||||
} |
||||
|
||||
public Condition build() { |
||||
final Map<Address, Boolean> proposalsAsAddress = |
||||
this.proposals |
||||
.entrySet() |
||||
.stream() |
||||
.collect(Collectors.toMap(p -> p.getKey().getAddress(), Entry::getValue)); |
||||
return new ExpectProposals(clique, proposalsAsAddress); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique.ExpectNonceVote.CLIQUE_NONCE_VOTE.AUTH; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
public class ExpectNonceVote implements Condition { |
||||
private static final String NONCE_AUTH = "0xffffffffffffffff"; |
||||
private static final String NONCE_DROP = "0x0000000000000000"; |
||||
private final EthTransactions eth; |
||||
private final String expectedNonce; |
||||
|
||||
public enum CLIQUE_NONCE_VOTE { |
||||
AUTH, |
||||
DROP |
||||
} |
||||
|
||||
public ExpectNonceVote(final EthTransactions eth, final CLIQUE_NONCE_VOTE vote) { |
||||
this.eth = eth; |
||||
this.expectedNonce = vote == AUTH ? NONCE_AUTH : NONCE_DROP; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor(() -> assertThat(node.execute(eth.block()).getNonceRaw()).isEqualTo(expectedNonce)); |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
|
||||
import java.util.Map; |
||||
|
||||
public class ExpectProposals implements Condition { |
||||
private final CliqueTransactions clique; |
||||
private final Map<Address, Boolean> proposers; |
||||
|
||||
public ExpectProposals(final CliqueTransactions clique, final Map<Address, Boolean> proposers) { |
||||
this.clique = clique; |
||||
this.proposers = proposers; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor(() -> assertThat(node.execute(clique.createProposals())).isEqualTo(proposers)); |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
|
||||
public class ExpectValidators implements Condition { |
||||
private final CliqueTransactions clique; |
||||
private final Address[] validators; |
||||
|
||||
public ExpectValidators(final CliqueTransactions clique, final Address... validators) { |
||||
this.clique = clique; |
||||
this.validators = validators; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor( |
||||
() -> |
||||
assertThat(node.execute(clique.createGetSigners(LATEST))).containsExactly(validators)); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
|
||||
public class ExpectValidatorsAtBlock implements Condition { |
||||
private final CliqueTransactions clique; |
||||
private final String blockParameter; |
||||
private final Address[] validators; |
||||
|
||||
public ExpectValidatorsAtBlock( |
||||
final CliqueTransactions clique, final String blockNumber, final Address... validators) { |
||||
this.clique = clique; |
||||
this.blockParameter = blockNumber; |
||||
this.validators = validators; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor( |
||||
() -> |
||||
assertThat(node.execute(clique.createGetSigners(blockParameter))) |
||||
.containsExactly(validators)); |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
|
||||
public class ExpectValidatorsAtBlockHash implements Condition { |
||||
private final CliqueTransactions clique; |
||||
private final Hash blockHash; |
||||
private final Address[] validators; |
||||
|
||||
public ExpectValidatorsAtBlockHash( |
||||
final CliqueTransactions clique, final Hash blockHash, final Address... validators) { |
||||
this.clique = clique; |
||||
this.blockHash = blockHash; |
||||
this.validators = validators; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor( |
||||
() -> |
||||
assertThat(node.execute(clique.createGetSignersAtHash(blockHash))) |
||||
.containsExactly(validators)); |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.node; |
||||
|
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
@FunctionalInterface |
||||
public interface GenesisConfigProvider { |
||||
Optional<String> createGenesisConfig(final List<RunnableNode> validators); |
||||
} |
@ -0,0 +1,81 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static java.util.Collections.singletonList; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
|
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.JsonRpc2_0Web3j; |
||||
import org.web3j.protocol.core.Request; |
||||
import org.web3j.protocol.core.Response; |
||||
|
||||
public class PantheonWeb3j extends JsonRpc2_0Web3j { |
||||
|
||||
public PantheonWeb3j(final Web3jService web3jService) { |
||||
super(web3jService); |
||||
} |
||||
|
||||
public PantheonWeb3j( |
||||
final Web3jService web3jService, |
||||
final long pollingInterval, |
||||
final ScheduledExecutorService scheduledExecutorService) { |
||||
super(web3jService, pollingInterval, scheduledExecutorService); |
||||
} |
||||
|
||||
public Request<?, ProposeResponse> cliquePropose(final String address, final Boolean auth) { |
||||
return new Request<>( |
||||
"clique_propose", |
||||
Arrays.asList(address, auth.toString()), |
||||
web3jService, |
||||
ProposeResponse.class); |
||||
} |
||||
|
||||
public Request<?, DiscardResponse> cliqueDiscard(final String address) { |
||||
return new Request<>( |
||||
"clique_discard", singletonList(address), web3jService, DiscardResponse.class); |
||||
} |
||||
|
||||
public Request<?, ProposalsResponse> cliqueProposals() { |
||||
return new Request<>("clique_proposals", emptyList(), web3jService, ProposalsResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSigners(final String blockNumber) { |
||||
return new Request<>( |
||||
"clique_getSigners", singletonList(blockNumber), web3jService, SignersBlockResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSignersAtHash(final Hash hash) { |
||||
return new Request<>( |
||||
"clique_getSignersAtHash", |
||||
singletonList(hash.toString()), |
||||
web3jService, |
||||
SignersBlockResponse.class); |
||||
} |
||||
|
||||
public static class ProposeResponse extends Response<Boolean> {} |
||||
|
||||
public static class DiscardResponse extends Response<Boolean> {} |
||||
|
||||
public static class SignersBlockResponse extends Response<List<Address>> {} |
||||
|
||||
public static class ProposalsResponse extends Response<Map<Address, Boolean>> {} |
||||
} |
@ -0,0 +1,41 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j.DiscardResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class CliqueDiscard implements Transaction<Boolean> { |
||||
private final String address; |
||||
|
||||
public CliqueDiscard(final String address) { |
||||
this.address = address; |
||||
} |
||||
|
||||
@Override |
||||
public Boolean execute(final PantheonWeb3j node) { |
||||
try { |
||||
final DiscardResponse result = node.cliqueDiscard(address).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j.SignersBlockResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
public class CliqueGetSigners implements Transaction<List<Address>> { |
||||
private final String blockNumber; |
||||
|
||||
public CliqueGetSigners(final String blockNumber) { |
||||
this.blockNumber = blockNumber; |
||||
} |
||||
|
||||
@Override |
||||
public List<Address> execute(final PantheonWeb3j node) { |
||||
try { |
||||
final SignersBlockResponse result = node.cliqueGetSigners(blockNumber).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j.SignersBlockResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
public class CliqueGetSignersAtHash implements Transaction<List<Address>> { |
||||
private final Hash hash; |
||||
|
||||
public CliqueGetSignersAtHash(final Hash hash) { |
||||
this.hash = hash; |
||||
} |
||||
|
||||
@Override |
||||
public List<Address> execute(final PantheonWeb3j node) { |
||||
try { |
||||
final SignersBlockResponse result = node.cliqueGetSignersAtHash(hash).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j.ProposalsResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
public class CliqueProposals implements Transaction<Map<Address, Boolean>> { |
||||
|
||||
@Override |
||||
public Map<Address, Boolean> execute(final PantheonWeb3j node) { |
||||
try { |
||||
final ProposalsResponse result = node.cliqueProposals().send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j.ProposeResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class CliquePropose implements Transaction<Boolean> { |
||||
private final String address; |
||||
private final boolean auth; |
||||
|
||||
public CliquePropose(final String address, final boolean auth) { |
||||
this.address = address; |
||||
this.auth = auth; |
||||
} |
||||
|
||||
@Override |
||||
public Boolean execute(final PantheonWeb3j node) { |
||||
try { |
||||
final ProposeResponse result = node.cliquePropose(address, auth).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
public class CliqueTransactions { |
||||
public static final String LATEST = "latest"; |
||||
|
||||
public CliquePropose createRemoveProposal(final PantheonNode node) { |
||||
return propose(node.getAddress().toString(), false); |
||||
} |
||||
|
||||
public CliquePropose createAddProposal(final PantheonNode node) { |
||||
return propose(node.getAddress().toString(), true); |
||||
} |
||||
|
||||
private CliquePropose propose(final String address, final boolean auth) { |
||||
return new CliquePropose(address, auth); |
||||
} |
||||
|
||||
public CliqueProposals createProposals() { |
||||
return new CliqueProposals(); |
||||
} |
||||
|
||||
public CliqueGetSigners createGetSigners(final String blockNumber) { |
||||
return new CliqueGetSigners(blockNumber); |
||||
} |
||||
|
||||
public CliqueGetSignersAtHash createGetSignersAtHash(final Hash blockHash) { |
||||
return new CliqueGetSignersAtHash(blockHash); |
||||
} |
||||
|
||||
public CliqueDiscard createDiscardProposal(final PantheonNode node) { |
||||
return new CliqueDiscard(node.getAddress().toString()); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.web3j.protocol.core.DefaultBlockParameter; |
||||
import org.web3j.protocol.core.methods.response.EthBlock; |
||||
import org.web3j.protocol.core.methods.response.EthBlock.Block; |
||||
|
||||
public class EthGetBlockTransaction implements Transaction<Block> { |
||||
private final DefaultBlockParameter blockParameter; |
||||
private final boolean fullTransactionObjects; |
||||
|
||||
EthGetBlockTransaction( |
||||
final DefaultBlockParameter blockParameter, final boolean fullTransactionObjects) { |
||||
this.blockParameter = blockParameter; |
||||
this.fullTransactionObjects = fullTransactionObjects; |
||||
} |
||||
|
||||
@Override |
||||
public Block execute(final PantheonWeb3j node) { |
||||
try { |
||||
final EthBlock result = |
||||
node.ethGetBlockByNumber(blockParameter, fullTransactionObjects).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getBlock(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
|
||||
@FunctionalInterface |
||||
public interface WaitCondition { |
||||
void waitUntil(Node node); |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition; |
||||
|
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.blockchain.ExpectBlockNumber; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; |
||||
|
||||
import java.math.BigInteger; |
||||
|
||||
public class WaitConditions { |
||||
private final EthTransactions eth; |
||||
private final CliqueTransactions clique; |
||||
|
||||
public WaitConditions(final EthTransactions eth, final CliqueTransactions clique) { |
||||
this.eth = eth; |
||||
this.clique = clique; |
||||
} |
||||
|
||||
public WaitCondition chainHeadHasProgressed( |
||||
final PantheonNode node, final int blocksAheadOfLatest) { |
||||
final BigInteger futureBlock = |
||||
node.execute(eth.blockNumber()).add(BigInteger.valueOf(blocksAheadOfLatest)); |
||||
return new ExpectBlockNumber(eth, futureBlock)::verify; |
||||
} |
||||
|
||||
public WaitCondition cliqueValidatorsChanged(final Node node) { |
||||
return new WaitUntilSignersChanged(node.execute(clique.createGetSigners(LATEST)), clique); |
||||
} |
||||
|
||||
public WaitCondition chainHeadIsAt(final long blockNumber) { |
||||
return new ExpectBlockNumber(eth, BigInteger.valueOf(blockNumber))::verify; |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
/* |
||||
* Copyright 2018 ConsenSys AG. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on |
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the |
||||
* specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class WaitUntilSignersChanged implements WaitCondition { |
||||
private final CliqueTransactions clique; |
||||
private final List<Address> initialSigners; |
||||
|
||||
public WaitUntilSignersChanged( |
||||
final List<Address> initialSigners, final CliqueTransactions clique) { |
||||
this.initialSigners = initialSigners; |
||||
this.clique = clique; |
||||
} |
||||
|
||||
@Override |
||||
public void waitUntil(final Node node) { |
||||
waitFor( |
||||
60, |
||||
() -> |
||||
assertThat(node.execute(clique.createGetSigners(LATEST))).isNotEqualTo(initialSigners)); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
{ |
||||
"config": { |
||||
"chainId": 4, |
||||
"homesteadBlock": 1, |
||||
"eip150Block": 2, |
||||
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||
"eip155Block": 0, |
||||
"eip158Block": 0, |
||||
"byzantiumBlock": 0, |
||||
"clique": { |
||||
"period": 5, |
||||
"epoch": 30000 |
||||
} |
||||
}, |
||||
"nonce": "0x0", |
||||
"timestamp": "0x58ee40ba", |
||||
"extraData": "%cliqueExtraData%", |
||||
"gasLimit": "0x47b760", |
||||
"difficulty": "0x1", |
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||
"coinbase": "0x0000000000000000000000000000000000000000", |
||||
"alloc": { |
||||
"fe3b557e8fb62b89f4916b721be55ceb828dbd73": { |
||||
"privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "0xad78ebc5ac6200000" |
||||
}, |
||||
"627306090abaB3A6e1400e9345bC60c78a8BEf57": { |
||||
"privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "90000000000000000000000" |
||||
}, |
||||
"f17f52151EbEF6C7334FAD080c5704D77216b732": { |
||||
"privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f", |
||||
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored", |
||||
"balance": "90000000000000000000000" |
||||
} |
||||
}, |
||||
"number": "0x0", |
||||
"gasUsed": "0x0", |
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" |
||||
} |
Loading…
Reference in new issue