diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index 1279fd44573..edf1f77de69 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -17,7 +17,6 @@ import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.ADMIN; -import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.CLIQUE; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.IBFT; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.PLUGINS; import static org.hyperledger.besu.tests.acceptance.dsl.transaction.bft.ConsensusType.QBFT; @@ -36,7 +35,6 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.Node; import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory; -import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory.CliqueOptions; import java.io.File; import java.io.IOException; @@ -46,7 +44,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.function.UnaryOperator; import org.apache.tuweni.bytes.Bytes; @@ -122,16 +119,6 @@ public BesuNode createNode( return create(configBuilder.build()); } - public Node createArchiveNodeThatMustNotBeTheBootnode(final String name) throws IOException { - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .jsonRpcEnabled() - .webSocketEnabled() - .bootnodeEligible(false) - .build()); - } - public Node createQbftNodeThatMustNotBeTheBootnode(final String name) throws IOException { return createQbftNode(name, nodeConfigBuilder -> nodeConfigBuilder.bootnodeEligible(false)); } @@ -233,15 +220,6 @@ public BesuNode createNodeWithAuthenticationUsingEcdsaJwtPublicKey(final String .build()); } - public BesuNode createNodeWithP2pDisabled(final String name) throws IOException { - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .p2pEnabled(false) - .jsonRpcConfiguration(node.createJsonRpcEnabledConfig()) - .build()); - } - public BesuNode createArchiveNodeWithRpcDisabled(final String name) throws IOException { return create(new BesuNodeConfigurationBuilder().name(name).build()); } @@ -310,40 +288,14 @@ public BesuNode createQbftNode(final String name) throws IOException { return createQbftNode(name, UnaryOperator.identity()); } - public BesuNode createCliqueNode(final String name) throws IOException { - return createCliqueNode(name, UnaryOperator.identity()); - } - - public BesuNode createCliqueNode( - final String name, final UnaryOperator configModifier) - throws IOException { - final List enableRpcApis = new ArrayList<>(Arrays.asList()); - enableRpcApis.addAll(List.of(IBFT.name(), ADMIN.name(), CLIQUE.name())); - BesuNodeConfigurationBuilder builder = - new BesuNodeConfigurationBuilder() - .name(name) - .jsonRpcConfiguration( - node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis.toArray(String[]::new))) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .devMode(false) - .jsonRpcTxPool() - .genesisConfigProvider(GenesisConfigurationFactory::createCliqueGenesisConfig); - - builder = configModifier.apply(builder); - - return create(builder.build()); - } - public BesuNode createQbftNode( final String name, final UnaryOperator configModifier) throws IOException { - final List enableRpcApis = new ArrayList<>(Arrays.asList()); - enableRpcApis.addAll(List.of(QBFT.name(), ADMIN.name())); + final String[] enableRpcApis = new String[] {QBFT.name(), ADMIN.name()}; BesuNodeConfigurationBuilder builder = new BesuNodeConfigurationBuilder() .name(name) - .jsonRpcConfiguration( - node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis.toArray(String[]::new))) + .jsonRpcConfiguration(node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis)) .webSocketConfiguration(node.createWebSocketEnabledConfig()) .devMode(false) .jsonRpcTxPool() @@ -358,68 +310,6 @@ public BesuNode createQbftNodeWithRevertReasonEnabled(final String name) throws return createQbftNode(name, BesuNodeConfigurationBuilder::revertReasonEnabled); } - public BesuNode createCliquePluginsNode( - final String name, - final List plugins, - final List extraCLIOptions, - final String... extraRpcApis) - throws IOException { - - final List enableRpcApis = new ArrayList<>(Arrays.asList(extraRpcApis)); - enableRpcApis.addAll(List.of(IBFT.name(), ADMIN.name(), PLUGINS.name(), CLIQUE.name())); - - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .jsonRpcConfiguration( - node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis.toArray(String[]::new))) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .plugins(plugins) - .extraCLIOptions(extraCLIOptions) - .devMode(false) - .jsonRpcTxPool() - .genesisConfigProvider( - validators -> - GenesisConfigurationFactory.createCliqueGenesisConfig( - validators, CliqueOptions.DEFAULT)) - .build()); - } - - public BesuNode createCliqueNode(final String name, final CliqueOptions cliqueOptions) - throws IOException { - return createCliqueNodeWithExtraCliOptionsAndRpcApis(name, cliqueOptions, List.of()); - } - - public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis( - final String name, final CliqueOptions cliqueOptions, final List extraCliOptions) - throws IOException { - return createCliqueNodeWithExtraCliOptionsAndRpcApis( - name, cliqueOptions, extraCliOptions, Set.of()); - } - - public BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis( - final String name, - final CliqueOptions cliqueOptions, - final List extraCliOptions, - final Set extraRpcApis) - throws IOException { - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .miningEnabled() - .jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(extraRpcApis)) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .inProcessRpcConfiguration(node.createInProcessRpcConfiguration(extraRpcApis)) - .devMode(false) - .jsonRpcTxPool() - .genesisConfigProvider( - validators -> - GenesisConfigurationFactory.createCliqueGenesisConfig( - validators, cliqueOptions)) - .extraCLIOptions(extraCliOptions) - .build()); - } - public BesuNode createIbft2NonValidatorBootnode(final String name, final String genesisFile) throws IOException { return create( @@ -463,22 +353,6 @@ public BesuNode createIbft2NodeWithLocalAccountPermissioning( .build()); } - public BesuNode createIbft2Node(final String name, final String genesisFile) throws IOException { - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .miningEnabled() - .jsonRpcConfiguration(node.createJsonRpcWithIbft2AdminEnabledConfig()) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .devMode(false) - .genesisConfigProvider( - validators -> - GenesisConfigurationFactory.createIbft2GenesisConfigFilterBootnode( - validators, genesisFile)) - .bootnodeEligible(false) - .build()); - } - public BesuNode createIbft2Node( final String name, final boolean fixedPort, final DataStorageFormat storageFormat) throws IOException { @@ -659,34 +533,6 @@ public BesuNode createExecutionEngineGenesisNode(final String name, final String .build()); } - 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() - .name(name) - .miningEnabled() - .jsonRpcConfiguration(node.createJsonRpcWithCliqueEnabledConfig(Set.of())) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .jsonRpcTxPool() - .devMode(false) - .genesisConfigProvider( - nodes -> - node.createGenesisConfigForValidators( - asList(validators), - nodes, - vs -> - GenesisConfigurationFactory.createCliqueGenesisConfig( - vs, cliqueOptions))) - .build()); - } - public BesuNode createIbft2NodeWithValidators(final String name, final String... validators) throws IOException { @@ -706,25 +552,6 @@ public BesuNode createIbft2NodeWithValidators(final String name, final String... .build()); } - public BesuNode createQbftTLSNodeWithValidators( - final String name, final String type, final String... validators) throws IOException { - - return create( - new BesuNodeConfigurationBuilder() - .name(name) - .miningEnabled() - .jsonRpcConfiguration(node.createJsonRpcWithIbft2EnabledConfig(false)) - .webSocketConfiguration(node.createWebSocketEnabledConfig()) - .devMode(false) - .genesisConfigProvider( - nodes -> - node.createGenesisConfigForValidators( - asList(validators), - nodes, - GenesisConfigurationFactory::createIbft2GenesisConfig)) - .build()); - } - public BesuNode createQbftNodeWithValidators(final String name, final String... validators) throws IOException { @@ -789,33 +616,22 @@ private BesuNodeConfigurationBuilder createConfigurationBuilderWithStaticNodes( } public BesuNode createNodeWithNonDefaultSignatureAlgorithm( - final String name, - final String genesisPath, - final KeyPair keyPair, - final List staticNodes) - throws IOException { + final String name, final KeyPair keyPair, final List staticNodes) throws IOException { BesuNodeConfigurationBuilder builder = - createNodeConfigurationWithNonDefaultSignatureAlgorithm( - name, genesisPath, keyPair, staticNodes); + createNodeConfigurationWithNonDefaultSignatureAlgorithm(name, keyPair, staticNodes); return create(builder.build()); } public BesuNodeConfigurationBuilder createNodeConfigurationWithNonDefaultSignatureAlgorithm( - final String name, - final String genesisPath, - final KeyPair keyPair, - final List staticNodes) { - - final List enableRpcApis = new ArrayList<>(Arrays.asList()); - enableRpcApis.addAll(List.of(QBFT.name(), ADMIN.name())); + final String name, final KeyPair keyPair, final List staticNodes) { + final String[] enableRpcApis = new String[] {QBFT.name(), ADMIN.name()}; BesuNodeConfigurationBuilder builder = createConfigurationBuilderWithStaticNodes(name, staticNodes); builder = builder - .jsonRpcConfiguration( - node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis.toArray(String[]::new))) + .jsonRpcConfiguration(node.createJsonRpcWithRpcApiEnabledConfig(enableRpcApis)) .webSocketConfiguration(node.createWebSocketEnabledConfig()) .devMode(false) .jsonRpcTxPool() diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueDiscardRpcAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueDiscardRpcAcceptanceTest.java deleted file mode 100644 index 3ac42cb056c..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueDiscardRpcAcceptanceTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -public class CliqueDiscardRpcAcceptanceTest extends AcceptanceTestBase { - - @Test - public void shouldDiscardVotes() throws IOException { - final String[] validators = {"validator1", "validator3"}; - final BesuNode validator1 = besu.createCliqueNodeWithValidators("validator1", validators); - final BesuNode validator2 = besu.createCliqueNodeWithValidators("validator2", validators); - final BesuNode validator3 = besu.createCliqueNodeWithValidators("validator3", validators); - cluster.start(validator1, validator2, validator3); - - validator1.execute(cliqueTransactions.createAddProposal(validator2)); - validator1.execute(cliqueTransactions.createRemoveProposal(validator3)); - validator1.verify( - clique.proposalsEqual().addProposal(validator2).removeProposal(validator3).build()); - - validator1.execute(cliqueTransactions.createDiscardProposal(validator2)); - validator1.verify(clique.proposalsEqual().removeProposal(validator3).build()); - - validator1.execute(cliqueTransactions.createDiscardProposal(validator3)); - cluster.verify(clique.noProposals()); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueGetSignersRpcAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueGetSignersRpcAcceptanceTest.java deleted file mode 100644 index 25a1d335105..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueGetSignersRpcAcceptanceTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import static org.hyperledger.besu.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -@Disabled("flaky test due to hardcoded block numbers") -public class CliqueGetSignersRpcAcceptanceTest extends AcceptanceTestBase { - private BesuNode minerNode1; - private BesuNode minerNode2; - - @BeforeEach - public void setUp() throws Exception { - final String[] validators = {"miner1"}; - minerNode1 = besu.createCliqueNodeWithValidators("miner1", validators); - minerNode2 = besu.createCliqueNodeWithValidators("miner2", validators); - cluster.start(minerNode1, minerNode2); - } - - @Test - public void shouldBeAbleToGetValidatorsForBlockNumber() { - cluster.verify(clique.validatorsAtBlockEqual("0x0", minerNode1)); - minerNode1.verify(blockchain.minimumHeight(1)); - - minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2)); - cluster.verify(blockchain.reachesHeight(minerNode1, 1)); - cluster.verify(clique.validatorsAtBlockEqual("0x2", minerNode1, minerNode2)); - cluster.verify(clique.validatorsAtBlockEqual(LATEST, minerNode1, minerNode2)); - } - - @Test - public void shouldBeAbleToGetValidatorsForBlockHash() { - cluster.verify(clique.validatorsAtBlockHashFromBlockNumberEqual(minerNode1, 0, minerNode1)); - minerNode1.verify(blockchain.minimumHeight(1)); - - minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2)); - cluster.verify(blockchain.reachesHeight(minerNode1, 1)); - cluster.verify( - clique.validatorsAtBlockHashFromBlockNumberEqual(minerNode1, 2, minerNode1, minerNode2)); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueMiningAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueMiningAcceptanceTest.java deleted file mode 100644 index 60333579f6f..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueMiningAcceptanceTest.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import static java.util.stream.Collectors.joining; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.assertj.core.data.Percentage.withPercentage; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -import org.hyperledger.besu.tests.acceptance.dsl.account.Account; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; -import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.genesis.GenesisConfigurationFactory.CliqueOptions; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.web3j.protocol.core.DefaultBlockParameter; - -public class CliqueMiningAcceptanceTest extends AcceptanceTestBase { - - @Test - public void shouldMineTransactionsOnSingleNode() throws IOException { - final BesuNode minerNode = besu.createCliqueNode("miner1"); - cluster.start(minerNode); - - final Account sender = accounts.createAccount("account1"); - final Account receiver = accounts.createAccount("account2"); - - minerNode.execute(accountTransactions.createTransfer(sender, 50)); - cluster.verify(sender.balanceEquals(50)); - - minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1)); - cluster.verify(receiver.balanceEquals(1)); - - minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2)); - cluster.verify(receiver.balanceEquals(3)); - } - - @Test - public void shouldNotMineBlocksIfNoTransactionsWhenCreateEmptyBlockIsFalse() throws IOException { - final var cliqueOptionsNoEmptyBlocks = - new CliqueOptions( - CliqueOptions.DEFAULT.blockPeriodSeconds(), CliqueOptions.DEFAULT.epochLength(), false); - final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptionsNoEmptyBlocks); - cluster.start(minerNode); - - cluster.verify(clique.noNewBlockCreated(minerNode)); - } - - @Test - public void shouldMineBlocksOnlyWhenTransactionsArePresentWhenCreateEmptyBlocksIsFalse() - throws IOException { - final var cliqueOptionsNoEmptyBlocks = - new CliqueOptions( - CliqueOptions.DEFAULT.blockPeriodSeconds(), CliqueOptions.DEFAULT.epochLength(), false); - final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptionsNoEmptyBlocks); - cluster.start(minerNode); - - final Account sender = accounts.createAccount("account1"); - - cluster.verify(clique.noNewBlockCreated(minerNode)); - - minerNode.execute(accountTransactions.createTransfer(sender, 50)); - - minerNode.verify(clique.blockIsCreatedByProposer(minerNode)); - } - - @Test - @Disabled("flaky see https://github.com/hyperledger/besu/issues/8862") - public void shouldMineTransactionsOnMultipleNodes() throws IOException { - final BesuNode minerNode1 = besu.createCliqueNode("miner1"); - final BesuNode minerNode2 = besu.createCliqueNode("miner2"); - final BesuNode minerNode3 = besu.createCliqueNode("miner3"); - startClusterAndVerifyProducingBlocks(minerNode1, minerNode2, minerNode3); - - final Account sender = accounts.createAccount("account1"); - final Account receiver = accounts.createAccount("account2"); - - minerNode1.execute(accountTransactions.createTransfer(sender, 50)); - cluster.verify(sender.balanceEquals(50)); - - minerNode2.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1)); - cluster.verify(receiver.balanceEquals(1)); - - minerNode3.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2)); - cluster.verify(receiver.balanceEquals(3)); - } - - @Test - public void shouldStallMiningWhenInsufficientValidators() throws IOException { - final BesuNode minerNode1 = besu.createCliqueNode("miner1"); - final BesuNode minerNode2 = besu.createCliqueNode("miner2"); - final BesuNode minerNode3 = besu.createCliqueNode("miner3"); - startClusterAndVerifyProducingBlocks(minerNode1, minerNode2, minerNode3); - - cluster.stopNode(minerNode2); - cluster.stopNode(minerNode3); - minerNode1.verify(net.awaitPeerCount(0)); - minerNode1.verify(clique.blockIsCreatedByProposer(minerNode1)); - - minerNode1.verify(clique.noNewBlockCreated(minerNode1)); - } - - private void startClusterAndVerifyProducingBlocks( - final BesuNode minerNode1, final BesuNode minerNode2, final BesuNode minerNode3) { - cluster.start(minerNode1, minerNode2, minerNode3); - - // 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)); - - // verify that we have started producing blocks - waitForBlockHeight(minerNode1, 1); - final var minerChainHead = minerNode1.execute(ethTransactions.block()); - minerNode2.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue())); - minerNode3.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue())); - } - - @Test - @Disabled("flaky see https://github.com/hyperledger/besu/issues/8862") - public void shouldStillMineWhenANodeFailsAndHasSufficientValidators() throws IOException { - final BesuNode minerNode1 = besu.createCliqueNode("miner1"); - final BesuNode minerNode2 = besu.createCliqueNode("miner2"); - final BesuNode minerNode3 = besu.createCliqueNode("miner3"); - startClusterAndVerifyProducingBlocks(minerNode1, minerNode2, minerNode3); - - cluster.verifyOnActiveNodes(blockchain.reachesHeight(minerNode1, 1, 85)); - - cluster.stopNode(minerNode3); - cluster.verifyOnActiveNodes(net.awaitPeerCount(1)); - - cluster.verifyOnActiveNodes(blockchain.reachesHeight(minerNode1, 2)); - cluster.verifyOnActiveNodes(clique.blockIsCreatedByProposer(minerNode1)); - cluster.verifyOnActiveNodes(clique.blockIsCreatedByProposer(minerNode2)); - } - - @Test - public void shouldMineBlocksAccordingToBlockPeriodTransitions() throws IOException { - - final var cliqueOptions = new CliqueOptions(3, CliqueOptions.DEFAULT.epochLength(), true); - final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptions); - - // setup transitions - final Map decreasePeriodTo2_Transition = - Map.of("block", 3, "blockperiodseconds", 2); - final Map decreasePeriodTo1_Transition = - Map.of("block", 4, "blockperiodseconds", 1); - // ensure previous blockperiodseconds transition is carried over - final Map dummy_Transition = Map.of("block", 5, "createemptyblocks", true); - final Map increasePeriodTo2_Transition = - Map.of("block", 6, "blockperiodseconds", 2); - - final Optional initialGenesis = - minerNode.getGenesisConfigProvider().create(List.of(minerNode)); - final String genesisWithTransitions = - prependTransitionsToCliqueOptions( - initialGenesis.orElseThrow(), - List.of( - decreasePeriodTo2_Transition, - decreasePeriodTo1_Transition, - dummy_Transition, - increasePeriodTo2_Transition)); - minerNode.setGenesisConfig(genesisWithTransitions); - - // Mine 6 blocks - cluster.start(minerNode); - minerNode.verify(blockchain.reachesHeight(minerNode, 5)); - - // Assert the block period decreased/increased after each transition - final long block1Timestamp = getTimestampForBlock(minerNode, 1); - final long block2Timestamp = getTimestampForBlock(minerNode, 2); - final long block3Timestamp = getTimestampForBlock(minerNode, 3); - final long block4Timestamp = getTimestampForBlock(minerNode, 4); - final long block5Timestamp = getTimestampForBlock(minerNode, 5); - final long block6Timestamp = getTimestampForBlock(minerNode, 6); - assertThat(block2Timestamp - block1Timestamp).isCloseTo(3, withPercentage(20)); - assertThat(block3Timestamp - block2Timestamp).isCloseTo(2, withPercentage(20)); - assertThat(block4Timestamp - block3Timestamp).isCloseTo(1, withPercentage(20)); - assertThat(block5Timestamp - block4Timestamp).isCloseTo(1, withPercentage(20)); - assertThat(block6Timestamp - block5Timestamp).isCloseTo(2, withPercentage(20)); - } - - @Test - public void shouldMineBlocksAccordingToCreateEmptyBlocksTransitions() throws IOException { - - final var cliqueOptionsEmptyBlocks = - new CliqueOptions(2, CliqueOptions.DEFAULT.epochLength(), true); - final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptionsEmptyBlocks); - - // setup transitions - final Map noEmptyBlocks_Transition = - Map.of("block", 3, "createemptyblocks", false); - final Map emptyBlocks_Transition = - Map.of("block", 4, "createemptyblocks", true); - final Map secondNoEmptyBlocks_Transition = - Map.of("block", 6, "createemptyblocks", false); - // ensure previous createemptyblocks transition is carried over - final Map dummy_Transition = Map.of("block", 7, "blockperiodseconds", 1); - - final Optional initialGenesis = - minerNode.getGenesisConfigProvider().create(List.of(minerNode)); - final String genesisWithTransitions = - prependTransitionsToCliqueOptions( - initialGenesis.orElseThrow(), - List.of( - noEmptyBlocks_Transition, - emptyBlocks_Transition, - secondNoEmptyBlocks_Transition, - dummy_Transition)); - minerNode.setGenesisConfig(genesisWithTransitions); - - final Account sender = accounts.createAccount("account1"); - - // Mine 2 blocks - cluster.start(minerNode); - minerNode.verify(blockchain.reachesHeight(minerNode, 1)); - - // tx required to mine block - cluster.verify(clique.noNewBlockCreated(minerNode)); - minerNode.execute(accountTransactions.createTransfer(sender, 50)); - minerNode.verify(clique.blockIsCreatedByProposer(minerNode)); - - // Mine 2 more blocks so chain head is 5 - minerNode.verify(blockchain.reachesHeight(minerNode, 2)); - - // tx required to mine block 6 - cluster.verify(clique.noNewBlockCreated(minerNode)); - minerNode.execute(accountTransactions.createTransfer(sender, 50)); - minerNode.verify(clique.blockIsCreatedByProposer(minerNode)); - - // check createemptyblocks transition carried over when other transition activated... - // tx required to mine block 7 - cluster.verify(clique.noNewBlockCreated(minerNode)); - } - - private long getTimestampForBlock(final BesuNode minerNode, final int blockNumber) { - return minerNode - .execute( - ethTransactions.block(DefaultBlockParameter.valueOf(BigInteger.valueOf(blockNumber)))) - .getTimestamp() - .longValue(); - } - - private String prependTransitionsToCliqueOptions( - final String originalOptions, final List> transitions) { - final StringBuilder stringBuilder = - new StringBuilder() - .append(formatCliqueTransitionsOptions(transitions)) - .append(",\n") - .append(quote("clique")) - .append(": {"); - - return originalOptions.replace(quote("clique") + ": {", stringBuilder.toString()); - } - - private String formatCliqueTransitionsOptions(final List> transitions) { - final StringBuilder stringBuilder = new StringBuilder(); - - stringBuilder.append(quote("transitions")); - stringBuilder.append(": {\n"); - stringBuilder.append(quote("clique")); - stringBuilder.append(": ["); - final String formattedTransitions = - transitions.stream().map(this::formatTransition).collect(joining(",\n")); - stringBuilder.append(formattedTransitions); - stringBuilder.append("\n]"); - stringBuilder.append("}\n"); - - return stringBuilder.toString(); - } - - private String quote(final Object value) { - return '"' + value.toString() + '"'; - } - - private String formatTransition(final Map transition) { - final StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("{"); - String formattedTransition = - transition.keySet().stream() - .map(key -> formatKeyValues(key, transition.get(key))) - .collect(joining(",")); - stringBuilder.append(formattedTransition); - stringBuilder.append("}"); - return stringBuilder.toString(); - } - - private String formatKeyValues(final Object... keyOrValue) { - if (keyOrValue.length % 2 == 1) { - // An odd number of strings cannot form a set of key-value pairs - throw new IllegalArgumentException("Must supply key-value pairs"); - } - final StringBuilder stringBuilder = new StringBuilder(); - for (int i = 0; i < keyOrValue.length; i += 2) { - if (i > 0) { - stringBuilder.append(", "); - } - final String key = keyOrValue[i].toString(); - final Object value = keyOrValue[i + 1]; - final String valueStr = value instanceof String ? quote(value) : value.toString(); - stringBuilder.append(String.format("\n%s: %s", quote(key), valueStr)); - } - return stringBuilder.toString(); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposalRpcAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposalRpcAcceptanceTest.java deleted file mode 100644 index 6cbfbbda0f0..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposalRpcAcceptanceTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -public class CliqueProposalRpcAcceptanceTest extends AcceptanceTestBase { - - @Test - public void shouldReturnProposals() 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); - 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()); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposeRpcAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposeRpcAcceptanceTest.java deleted file mode 100644 index fc179925a5f..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueProposeRpcAcceptanceTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -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.Test; - -public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase { - private static final GenesisConfigurationFactory.CliqueOptions CLIQUE_OPTIONS = - new GenesisConfigurationFactory.CliqueOptions(5, 30000, true); - - @Test - 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)); - - 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); - } - - @Test - public void shouldNotAddValidatorWhenInsufficientVotes() 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)); - minerNode1.verify(blockchain.reachesHeight(minerNode1, 1)); - cluster.verify(clique.validatorsEqual(minerNode1, minerNode2)); - } - - @Test - public void shouldNotRemoveValidatorWhenInsufficientVotes() 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)); - - minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3)); - minerNode1.verify(blockchain.reachesHeight(minerNode1, 1)); - cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3)); - } - - @Test - public void shouldIncludeVoteInBlockHeader() 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)); - 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... nodes) { - // verify nodes are fully connected otherwise blocks could not be propagated - 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(nodes[0], 1); - final var firstNodeChainHead = nodes[0].execute(ethTransactions.block()); - Arrays.stream(nodes) - .skip(1) - .forEach(node -> waitForBlockHeight(node, firstNodeChainHead.getNumber().longValue())); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueZeroValidatorsAcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueZeroValidatorsAcceptanceTest.java deleted file mode 100644 index e124e669d92..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/clique/CliqueZeroValidatorsAcceptanceTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.tests.acceptance.clique; - -import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; -import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; - -import java.io.IOException; - -import org.junit.jupiter.api.Test; - -public class CliqueZeroValidatorsAcceptanceTest extends AcceptanceTestBase { - - @Test - public void zeroValidatorsFormValidCluster() throws IOException { - final String[] signers = {}; - final BesuNode node1 = besu.createCliqueNodeWithValidators("node1", signers); - final BesuNode node2 = besu.createCliqueNodeWithValidators("node2", signers); - - cluster.start(node1, node2); - - cluster.verify(net.awaitPeerCount(1)); - } -} diff --git a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java index 338020d41f4..776a345b57b 100644 --- a/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java +++ b/acceptance-tests/tests/src/acceptanceTest/java/org/hyperledger/besu/tests/acceptance/crypto/SECP256R1AcceptanceTest.java @@ -40,8 +40,6 @@ public class SECP256R1AcceptanceTest extends AcceptanceTestBase { private Node otherNode; private Cluster noDiscoveryCluster; - private static final String GENESIS_FILE = "/crypto/secp256r1.json"; - private static final String MINER_NODE_PRIVATE_KEY = "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"; private static final String OTHER_NODE_PRIVATE_KEY = @@ -59,13 +57,12 @@ public void setUp() throws Exception { noDiscoveryCluster = new Cluster(clusterConfiguration, net); minerNode = - besu.createNodeWithNonDefaultSignatureAlgorithm( - "minerNode", GENESIS_FILE, minerNodeKeyPair, List.of()); + besu.createNodeWithNonDefaultSignatureAlgorithm("minerNode", minerNodeKeyPair, List.of()); noDiscoveryCluster.start(minerNode); otherNode = besu.createNodeWithNonDefaultSignatureAlgorithm( - "otherNode", GENESIS_FILE, otherNodeKeyPair, List.of(minerNode)); + "otherNode", otherNodeKeyPair, List.of(minerNode)); noDiscoveryCluster.addNode(otherNode); minerNode.verify(net.awaitPeerCount(1)); diff --git a/acceptance-tests/tests/src/acceptanceTest/resources/clique/clique.json.tpl b/acceptance-tests/tests/src/acceptanceTest/resources/clique/clique.json.tpl deleted file mode 100644 index 0dce4f83020..00000000000 --- a/acceptance-tests/tests/src/acceptanceTest/resources/clique/clique.json.tpl +++ /dev/null @@ -1,40 +0,0 @@ -{ - "config": { - "chainId": 4, - "byzantiumBlock": 0, - "constantinopleBlock": 6, - "petersburgBlock": 7, - "clique": { - "blockperiodseconds": %blockperiodseconds%, - "epochlength": %epochlength%, - "createemptyblocks": %createemptyblocks% - } - }, - "nonce": "0x0", - "timestamp": "0x58ee40ba", - "extraData": "%extraData%", - "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" -}