Merge branch 'main' into zkbesu

# Conflicts:
#	.github/workflows/acceptance-tests.yml
#	.github/workflows/codeql.yml
#	.github/workflows/integration-tests.yml
#	.github/workflows/pre-review.yml
#	.github/workflows/reference-tests.yml
#	build.gradle
This commit is contained in:
Fabio Di Fabio
2025-03-18 11:18:55 +01:00
526 changed files with 22840 additions and 22574 deletions

1
.gitattributes vendored
View File

@@ -17,4 +17,5 @@
*.p12 binary
*.db binary
*.woff2 binary
*.era1 binary
goss-linux-amd64 binary

View File

@@ -1,28 +1,71 @@
# Changelog
## Unreleased
### Breaking Changes
NOTE: This release breaks native Windows compatibility for mainnet ethereum configurations. As the prague(pectra) hardfork require
BLS12-381 precompiles and besu does not currently have a pure java implementation of bls12-381, only platforms which
have support in besu-native can run mainnet ethereum configurations. Windows support via WSL should still continue to work.
- k8s (KUBERNETES) Nat method is removed. Use docker or none instead. [#8289](https://github.com/hyperledger/besu/pull/8289)
- Change `Invalid block, unable to parse RLP` RPC error message to `Invalid block param (block not found)` [#8328](https://github.com/hyperledger/besu/pull/8328)
- Mainnet ethereum now REQUIRES native crypto libraries, so only linux and macos(darwin) are supported mainnet configurations [#8418](https://github.com/hyperledger/besu/pull/8418)
### Upcoming Breaking Changes
- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge`
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release. Use docker or none instead.
- `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated, use `--Xbonsai-full-flat-db-enabled` instead.
- `--Xbonsai-limit-trie-logs-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
- `--Xbonsai-trie-log-pruning-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
- `--Xbonsai-trie-logs-pruning-window-size` is deprecated, use `--bonsai-trie-logs-pruning-window-size` instead.
- `--Xsnapsync-bft-enabled` is deprecated and will be removed in a future release. SNAP sync is supported for BFT networks.
- `--tx-pool-disable-locals` has been deprecated, use `--tx-pool-no-local-priority`, instead.
- Sunsetting features - for more context on the reasoning behind the deprecation of these features, including alternative options, read [this blog post](https://www.lfdecentralizedtrust.org/blog/sunsetting-tessera-and-simplifying-hyperledger-besu)
- Tessera privacy
- Smart-contract-based (onchain) permissioning
- Proof of Work consensus
- Fast Sync
- Transaction indexing will be disabled by default in a future release for snap sync and checkpoint sync modes. This will break RPCs that use transaction hash for historical queries.
- Support for block creation on networks running a pre-Byzantium fork is deprecated for removal in a future release, after that in order to update Besu on nodes that build blocks, your network needs to be upgraded at least to the Byzantium fork. The main reason is to simplify world state management during block creation, since before Byzantium for each selected transaction, the receipt must contain the root hash of the modified world state, and this does not play well with the new plugin features and future work on parallelism.
### Additions and Improvements
- Add TLS/mTLS options and configure the GraphQL HTTP service[#7910](https://github.com/hyperledger/besu/pull/7910)
#### Prague
- Increase mainnet and Sepolia gas limit to 36M [#8249](https://github.com/hyperledger/besu/pull/8249)
- Update Holesky and Sepolia deposit contract addresses [#8346](https://github.com/hyperledger/besu/pull/8346)
#### Plugins
- Allow plugins to propose transactions during block creation [#8268](https://github.com/hyperledger/besu/pull/8268)
- Update `eth_getLogs` to return a `Block not found` error when the requested block is not found. [#8290](https://github.com/hyperledger/besu/pull/8290)
### Bug fixes
- Add support for transaction permissioning rules in Plugin API [#8365](https://github.com/hyperledger/besu/pull/8365)
#### Parallelization
- Improve conflict detection by considering slots to reduce false positives [#7923](https://github.com/hyperledger/besu/pull/7923)
#### Dependencies
- Upgrade Netty to version 4.1.118 to fix CVE-2025-24970 [#8275](https://github.com/hyperledger/besu/pull/8275)
- Add missing RPC method `debug_accountRange` to `RpcMethod.java` and implemented its handler. [#8153](https://github.com/hyperledger/besu/issues/8153)
- Update the jc-kzg-4844 dependency from 1.0.0 to 2.0.0, which is now available on Maven Central [#7849](https://github.com/hyperledger/besu/pull/7849)
- Other dependency updates [#8293](https://github.com/hyperledger/besu/pull/8293) [#8315](https://github.com/hyperledger/besu/pull/8315) [#8350](https://github.com/hyperledger/besu/pull/8350)
- Update to gradle 8.11 [#8294](https://github.com/hyperledger/besu/pull/8294) and update usage of some deprecated features [#8295](https://github.com/hyperledger/besu/pull/8295) [#8340](https://github.com/hyperledger/besu/pull/8340)
- Update gradle plugins [#8296](https://github.com/hyperledger/besu/pull/8296) [#8333](https://github.com/hyperledger/besu/pull/8333) [#8334](https://github.com/hyperledger/besu/pull/8334)
#### Other improvements
- Add TLS/mTLS options and configure the GraphQL HTTP service[#7910](https://github.com/hyperledger/besu/pull/7910)
- Update `eth_getLogs` to return a `Block not found` error when the requested block is not found. [#8290](https://github.com/hyperledger/besu/pull/8290)
- Change `Invalid block, unable to parse RLP` RPC error message to `Invalid block param (block not found)` [#8328](https://github.com/hyperledger/besu/pull/8328)
- Add IBFT1 to QBFT migration capability [#8262](https://github.com/hyperledger/besu/pull/8262)
- Support pending transaction score when saving and restoring txpool [#8363](https://github.com/hyperledger/besu/pull/8363)
- Upgrade to execution-spec-tests v4.1.0 including better EIP-2537 coverage for BLS [#8402](https://github.com/hyperledger/besu/pull/8402)
- Add era1 format to blocks import subcommand [#7935](https://github.com/hyperledger/besu/issues/7935)
- Replace tuweni libs with https://github.com/Consensys/tuweni
- Performance: Consensys/tuweni 2.6.0 reduces boxing/unboxing overhead on some EVM opcodes, like PushX and Caller
- Add Hoodi as new named testnet [#8428](https://github.com/hyperledger/besu/issues/8428)
### Bug fixes
- Add missing RPC method `debug_accountRange` to `RpcMethod.java` so this method can be used with `--rpc-http-api-method-no-auth` [#8153](https://github.com/hyperledger/besu/issues/8153)
- Add a fallback pivot strategy when the safe block does not change for a long time, to make possible to complete the initial sync in case the chain is not finalizing [#8395](https://github.com/hyperledger/besu/pull/8395)
- Fix issue with new QBFT/IBFT blocks being produced under certain circumstances. [#8308](https://github.com/hyperledger/besu/issues/8308)
- Fix QBFT and IBFT transitions that change the mining beneficiary [#8387](https://github.com/hyperledger/besu/issues/8387)
- `eth_getLogs` - empty topic is a wildcard match [#8420](https://github.com/hyperledger/besu/pull/8420)
## 25.2.2 hotfix
- Pectra - Sepolia: Fix for deposit contract log decoding [#8383](https://github.com/hyperledger/besu/pull/8383)
## 25.2.1 hotfix
- Pectra - update Holesky and Sepolia deposit contract addresses [#8346](https://github.com/hyperledger/besu/pull/8346)
## 25.2.0
@@ -40,6 +83,7 @@
- Smart-contract-based (onchain) permissioning
- Proof of Work consensus
- Fast Sync
- Support for block creation on networks running a pre-Byzantium fork is deprecated for removal in a future release, after that in order to update Besu on nodes that build blocks, your network needs to be upgraded at least to the Byzantium fork. The main reason is to simplify world state management during block creation, since before Byzantium for each selected transaction, the receipt must contain the root hash of the modified world state, and this does not play well with the new plugin features and future work on parallelism.
### Additions and Improvements
- Add a tx selector to skip txs from the same sender after the first not selected [#8216](https://github.com/hyperledger/besu/pull/8216)
- `rpc-gas-cap` default value has changed from 0 (unlimited) to 50M [#8251](https://github.com/hyperledger/besu/issues/8251)
@@ -76,6 +120,8 @@
- Smart-contract-based (onchain) permissioning
- Proof of Work consensus
- Fast Sync
- Plugins
- `BesuConfiguration` methods `getRpcHttpHost` and `getRpcHttpPort` (which return Optionals) have been deprecated in favour of `getConfiguredRpcHttpHost` and `getConfiguredRpcHttpPort` which return the actual values, which will always be populated since these options have defaults. [#8127](https://github.com/hyperledger/besu/pull/8127)
### Additions and Improvements
- Add RPC HTTP options to specify custom truststore and its password [#7978](https://github.com/hyperledger/besu/pull/7978)
@@ -142,7 +188,6 @@ This is a hotfix to address publishing besu maven artifacts. There are no issue
- Smart-contract-based (onchain) permissioning
- Proof of Work consensus
- Fast Sync
### Additions and Improvements
- Fine tune already seen txs tracker when a tx is removed from the pool [#7755](https://github.com/hyperledger/besu/pull/7755)
- Support for enabling and configuring TLS/mTLS in WebSocket service. [#7854](https://github.com/hyperledger/besu/pull/7854)
@@ -667,7 +712,7 @@ https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/23.10.3/besu-23.10.3
- Implement new `miner_setMinPriorityFee` and `miner_getMinPriorityFee` RPC methods [#6080](https://github.com/hyperledger/besu/pull/6080)
- Clique config option `createemptyblocks` to not create empty blocks [#6082](https://github.com/hyperledger/besu/pull/6082)
- Upgrade EVM Reference Tests to v13 (Cancun) [#6114](https://github.com/hyperledger/besu/pull/6114)
- Add `yParity` to GraphQL and JSON-RPC for relevant querise. [6119](https://github.com/hyperledger/besu/pull/6119)
- Add `yParity` to GraphQL and JSON-RPC for relevant queries. [6119](https://github.com/hyperledger/besu/pull/6119)
- Force tx replacement price bump to zero when zero base fee market is configured or `--min-gas-price` is set to 0. This allows for easier tx replacement in networks where there is not gas price. [#6079](https://github.com/hyperledger/besu/pull/6079)
- Introduce the possibility to limit the time spent selecting pending transactions during block creation, using the new experimental option `Xblock-txs-selection-max-time` on PoS and PoW networks (by default set to 5000ms) or `Xpoa-block-txs-selection-max-time` on PoA networks (by default 75% of the min block time) [#6044](https://github.com/hyperledger/besu/pull/6044)
- Remove LowestInvalidNonceCache from `legacy` transaction pool to make it more private networks friendly [#6148](https://github.com/hyperledger/besu/pull/6148)

View File

@@ -27,6 +27,7 @@
| Matthew Whitehead| matthew1001 | matthew.whitehead |
| Meredith Baxter | mbaxter | mbaxter |
| Stefan Pingel | pinges | pinges |
| Bhanu Pulluri | pullurib | bpulluri |
| Simon Dudley | siladu | siladu |
| Usman Saleem | usmansaleem | usmansaleem |

View File

@@ -32,16 +32,15 @@ dependencies {
implementation 'io.reactivex.rxjava2:rxjava'
implementation 'io.vertx:vertx-core'
implementation 'io.opentelemetry:opentelemetry-api'
implementation 'io.tmio:tuweni-bytes'
implementation 'io.tmio:tuweni-io'
implementation 'io.tmio:tuweni-units'
implementation 'io.consensys.protocols:tuweni-bytes'
implementation 'io.consensys.protocols:tuweni-io'
implementation 'io.consensys.protocols:tuweni-units'
implementation 'org.assertj:assertj-core'
implementation 'org.awaitility:awaitility'
implementation 'org.java-websocket:Java-WebSocket'
implementation 'org.web3j:abi'
implementation 'org.web3j:besu'
implementation 'org.web3j:crypto'
implementation 'org.wiremock:wiremock'
implementation 'org.junit.jupiter:junit-jupiter'
}

View File

@@ -45,6 +45,10 @@ public class Blockchain {
return new ExpectBlockNumberAbove(eth, BigInteger.valueOf(blockNumber));
}
public Condition minimumHeight(final long blockNumber, final int timeout) {
return new ExpectBlockNumberAbove(eth, BigInteger.valueOf(blockNumber), timeout);
}
public Condition reachesHeight(final BesuNode node, final int blocksAheadOfLatest) {
return new ExpectBlockNumberAbove(eth, futureHeight(node, blocksAheadOfLatest));
}

View File

@@ -27,15 +27,25 @@ public class AwaitNetPeerCount implements Condition {
private final NetPeerCountTransaction transaction;
private final BigInteger expectedPeerCount;
private final int timeout;
public AwaitNetPeerCount(
final NetPeerCountTransaction transaction, final BigInteger expectedPeerCount) {
this(transaction, expectedPeerCount, 30);
}
public AwaitNetPeerCount(
final NetPeerCountTransaction transaction,
final BigInteger expectedPeerCount,
final int timeout) {
this.transaction = transaction;
this.expectedPeerCount = expectedPeerCount;
this.timeout = timeout;
}
@Override
public void verify(final Node node) {
WaitUtils.waitFor(() -> assertThat(node.execute(transaction)).isEqualTo(expectedPeerCount));
WaitUtils.waitFor(
timeout, () -> assertThat(node.execute(transaction)).isEqualTo(expectedPeerCount));
}
}

View File

@@ -47,6 +47,11 @@ public class NetConditions {
return new AwaitNetPeerCount(transactions.peerCount(), BigInteger.valueOf(awaitPeerCount));
}
public Condition awaitPeerCount(final int awaitPeerCount, final int timeout) {
return new AwaitNetPeerCount(
transactions.peerCount(), BigInteger.valueOf(awaitPeerCount), timeout);
}
public Condition netVersionExceptional(final String expectedMessage) {
return new ExpectNetVersionConnectionException(transactions.netVersion(), expectedMessage);
}

View File

@@ -1,37 +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.dsl.condition.perm;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.AccountSmartContractPermissioningTransactions;
public class AccountSmartContractPermissioningConditions {
private final AccountSmartContractPermissioningTransactions transactions;
public AccountSmartContractPermissioningConditions(
final AccountSmartContractPermissioningTransactions transactions) {
this.transactions = transactions;
}
public Condition accountIsAllowed(final String address, final Account account) {
return new WaitForTrueResponse(transactions.isAccountAllowed(address, account));
}
public Condition accountIsForbidden(final String address, final Account account) {
return new WaitForFalseResponse(transactions.isAccountAllowed(address, account));
}
}

View File

@@ -1,46 +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.dsl.condition.perm;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.NodeSmartContractPermissioningTransactions;
public class NodeSmartContractPermissioningConditions {
private final NodeSmartContractPermissioningTransactions transactions;
public NodeSmartContractPermissioningConditions(
final NodeSmartContractPermissioningTransactions transactions) {
this.transactions = transactions;
}
public Condition nodeIsAllowed(final String address, final Node node) {
return new WaitForTrueResponse(transactions.isNodeAllowed(address, node));
}
public Condition nodeIsForbidden(final String address, final Node node) {
return new WaitForFalseResponse(transactions.isNodeAllowed(address, node));
}
public Condition connectionIsAllowed(final String address, final Node source, final Node target) {
return new WaitForTrueResponse(transactions.isConnectionAllowed(address, source, target));
}
public Condition connectionIsForbidden(
final String address, final Node source, final Node target) {
return new WaitForFalseResponse(transactions.isConnectionAllowed(address, source, target));
}
}

View File

@@ -1,46 +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.dsl.condition.perm;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.NodeSmartContractPermissioningV2Transactions;
public class NodeSmartContractPermissioningV2Conditions {
private final NodeSmartContractPermissioningV2Transactions transactions;
public NodeSmartContractPermissioningV2Conditions(
final NodeSmartContractPermissioningV2Transactions transactions) {
this.transactions = transactions;
}
public Condition connectionIsAllowed(final String address, final Node node) {
return new WaitForTrueResponse(transactions.isConnectionAllowed(address, node));
}
public Condition connectionIsAllowed(final String address, final EnodeURL enodeURL) {
return new WaitForTrueResponse(transactions.isConnectionAllowed(address, enodeURL));
}
public Condition connectionIsForbidden(final String address, final Node node) {
return new WaitForFalseResponse(transactions.isConnectionAllowed(address, node));
}
public Condition connectionIsForbidden(final String address, final EnodeURL enodeURL) {
return new WaitForFalseResponse(transactions.isConnectionAllowed(address, enodeURL));
}
}

View File

@@ -30,6 +30,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguratio
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
@@ -134,6 +135,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
private Optional<Integer> exitCode = Optional.empty();
private final boolean isStrictTxReplayProtectionEnabled;
private final Map<String, String> environment;
private SynchronizerConfiguration synchronizerConfiguration;
private final Optional<KeyValueStorageFactory> storageFactory;
public BesuNode(
@@ -234,6 +236,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
this.isDnsEnabled = isDnsEnabled;
privacyParameters.ifPresent(this::setPrivacyParameters);
this.environment = environment;
this.synchronizerConfiguration = SynchronizerConfiguration.builder().build(); // Default config
LOG.info("Created BesuNode {}", this);
}
@@ -790,6 +793,20 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
nodeRequests.shutdown();
nodeRequests = null;
}
deleteRuntimeFiles();
}
private void deleteRuntimeFiles() {
try {
Files.deleteIfExists(homeDirectory.resolve("besu.networks"));
} catch (IOException e) {
LOG.error("Failed to clean up besu.networks file in {}", homeDirectory, e);
}
try {
Files.deleteIfExists(homeDirectory.resolve("besu.ports"));
} catch (IOException e) {
LOG.error("Failed to clean up besu.ports file in {}", homeDirectory, e);
}
}
@Override
@@ -841,6 +858,15 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable
return apiConfiguration;
}
public SynchronizerConfiguration getSynchronizerConfiguration() {
return synchronizerConfiguration;
}
public BesuNode setSynchronizerConfiguration(final SynchronizerConfiguration config) {
this.synchronizerConfiguration = config;
return this;
}
public Optional<KeyValueStorageFactory> getStorageFactory() {
return storageFactory;
}

View File

@@ -48,6 +48,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -152,8 +153,20 @@ public class ProcessBesuNodeRunner implements BesuNodeRunner {
params.add(node.getNetwork().name());
}
params.add("--sync-mode");
params.add("FULL");
if (node.getSynchronizerConfiguration() != null) {
if (node.getSynchronizerConfiguration().getSyncMode() != null) {
params.add("--sync-mode");
params.add(node.getSynchronizerConfiguration().getSyncMode().toString());
}
params.add("--sync-min-peers");
params.add(Integer.toString(node.getSynchronizerConfiguration().getSyncMinimumPeerCount()));
} else {
params.add("--sync-mode");
params.add("FULL");
}
params.add("--Xsnapsync-server-enabled");
params.add("--discovery-enabled");
params.add(Boolean.toString(node.isDiscoveryEnabled()));
@@ -529,9 +542,11 @@ public class ProcessBesuNodeRunner implements BesuNodeRunner {
return;
}
LOG.info("Killing {} process, pid {}", name, process.pid());
process.destroy();
Stream.concat(process.descendants(), Stream.of(process.toHandle()))
.peek(
processHandle ->
LOG.info("Killing {} process, pid {}", processHandle.info(), processHandle.pid()))
.forEach(ProcessHandle::destroy);
try {
process.waitFor(30, TimeUnit.SECONDS);
} catch (final InterruptedException e) {

View File

@@ -19,6 +19,7 @@ import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
import org.hyperledger.besu.Runner;
import org.hyperledger.besu.RunnerBuilder;
import org.hyperledger.besu.chainexport.RlpBlockExporter;
import org.hyperledger.besu.chainimport.Era1BlockImporter;
import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.BesuCommand;
@@ -31,7 +32,6 @@ import org.hyperledger.besu.controller.BesuControllerBuilder;
import org.hyperledger.besu.crypto.KeyPairUtil;
import org.hyperledger.besu.cryptoservices.KeyPairSecurityModule;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.InProcessRpcConfiguration;
@@ -50,7 +50,7 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.trie.pathbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@@ -480,7 +480,6 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.clock(Clock.systemUTC())
.storageProvider(storageProvider)
.gasLimitCalculator(GasLimitCalculator.constant())
.evmConfiguration(EvmConfiguration.DEFAULT)
.maxPeers(25)
.maxRemotelyInitiatedPeers(15)
@@ -634,6 +633,7 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner {
new BesuCommand(
RlpBlockImporter::new,
JsonBlockImporter::new,
Era1BlockImporter::new,
RlpBlockExporter::new,
new RunnerBuilder(),
new BesuController.Builder(),

View File

@@ -91,12 +91,14 @@ public class Cluster implements AutoCloseable {
.forEach(this::startNode);
if (clusterConfiguration.isAwaitPeerDiscovery()) {
int timeoutSeconds = clusterConfiguration.getPeerDiscoveryTimeoutSeconds();
for (final RunnableNode node : nodes) {
LOG.info(
"Awaiting peer discovery for node {}, expecting {} peers",
"Awaiting peer discovery for node {}, expecting {} peers, timeout {} seconds",
node.getName(),
nodes.size() - 1);
node.awaitPeerDiscovery(net.awaitPeerCount(nodes.size() - 1));
nodes.size() - 1,
timeoutSeconds);
node.awaitPeerDiscovery(net.awaitPeerCount(nodes.size() - 1, timeoutSeconds));
}
}
LOG.info("Cluster startup complete.");

View File

@@ -17,12 +17,18 @@ package org.hyperledger.besu.tests.acceptance.dsl.node.cluster;
public class ClusterConfiguration {
private final boolean awaitPeerDiscovery;
private final int peerDiscoveryTimeoutSeconds;
ClusterConfiguration(final boolean awaitPeerDiscovery) {
ClusterConfiguration(final boolean awaitPeerDiscovery, final int peerDiscoveryTimeoutSeconds) {
this.awaitPeerDiscovery = awaitPeerDiscovery;
this.peerDiscoveryTimeoutSeconds = peerDiscoveryTimeoutSeconds;
}
public boolean isAwaitPeerDiscovery() {
return awaitPeerDiscovery;
}
public int getPeerDiscoveryTimeoutSeconds() {
return peerDiscoveryTimeoutSeconds;
}
}

View File

@@ -16,13 +16,19 @@ package org.hyperledger.besu.tests.acceptance.dsl.node.cluster;
public class ClusterConfigurationBuilder {
private boolean awaitPeerDiscovery = true;
private int peerDiscoveryTimeoutSeconds = 60; // Default 60 second timeout
public ClusterConfigurationBuilder awaitPeerDiscovery(final boolean awaitPeerDiscovery) {
this.awaitPeerDiscovery = awaitPeerDiscovery;
return this;
}
public ClusterConfigurationBuilder peerDiscoveryTimeout(final int timeoutSeconds) {
this.peerDiscoveryTimeoutSeconds = timeoutSeconds;
return this;
}
public ClusterConfiguration build() {
return new ClusterConfiguration(awaitPeerDiscovery);
return new ClusterConfiguration(awaitPeerDiscovery, peerDiscoveryTimeoutSeconds);
}
}

View File

@@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
@@ -73,6 +74,7 @@ public class BesuNodeConfiguration {
private final Optional<KeyPair> keyPair;
private final boolean strictTxReplayProtectionEnabled;
private final Map<String, String> environment;
private final SynchronizerConfiguration synchronizerConfiguration;
private final Optional<KeyValueStorageFactory> storageFactory;
BesuNodeConfiguration(
@@ -111,6 +113,7 @@ public class BesuNodeConfiguration {
final Optional<KeyPair> keyPair,
final boolean strictTxReplayProtectionEnabled,
final Map<String, String> environment,
final SynchronizerConfiguration synchronizerConfiguration,
final Optional<KeyValueStorageFactory> storageFactory) {
this.name = name;
this.miningConfiguration = miningConfiguration;
@@ -147,6 +150,7 @@ public class BesuNodeConfiguration {
this.keyPair = keyPair;
this.strictTxReplayProtectionEnabled = strictTxReplayProtectionEnabled;
this.environment = environment;
this.synchronizerConfiguration = synchronizerConfiguration;
this.storageFactory = storageFactory;
}
@@ -290,6 +294,10 @@ public class BesuNodeConfiguration {
return environment;
}
public SynchronizerConfiguration getSynchronizerConfiguration() {
return synchronizerConfiguration;
}
public Optional<KeyValueStorageFactory> storageImplementation() {
return storageFactory;
}

View File

@@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
@@ -96,6 +97,7 @@ public class BesuNodeConfigurationBuilder {
private Optional<KeyPair> keyPair = Optional.empty();
private Boolean strictTxReplayProtectionEnabled = false;
private Map<String, String> environment = new HashMap<>();
private SynchronizerConfiguration synchronizerConfiguration;
private Optional<KeyValueStorageFactory> storageImplementation = Optional.empty();
public BesuNodeConfigurationBuilder() {
@@ -467,7 +469,17 @@ public class BesuNodeConfigurationBuilder {
return this;
}
public BesuNodeConfigurationBuilder synchronizerConfiguration(
final SynchronizerConfiguration config) {
this.synchronizerConfiguration = config;
return this;
}
public BesuNodeConfiguration build() {
if (name == null) {
throw new IllegalStateException("Name is required");
}
return new BesuNodeConfiguration(
name,
dataPath,
@@ -504,6 +516,7 @@ public class BesuNodeConfigurationBuilder {
keyPair,
strictTxReplayProtectionEnabled,
environment,
synchronizerConfiguration,
storageImplementation);
}
}

View File

@@ -490,6 +490,39 @@ public class BesuNodeFactory {
return create(builder.build());
}
public BesuNode createQbftMigrationNode(
final String name, final boolean fixedPort, final DataStorageFormat storageFormat)
throws IOException {
JsonRpcConfiguration rpcConfig = node.createJsonRpcWithQbftEnabledConfig(false);
rpcConfig.addRpcApi("ADMIN,TXPOOL");
if (fixedPort) {
rpcConfig.setPort(
Math.abs(name.hashCode() % 60000)
+ 1024); // Generate a consistent port for p2p based on node name
}
BesuNodeConfigurationBuilder builder =
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(rpcConfig)
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.dataStorageConfiguration(
storageFormat == DataStorageFormat.FOREST
? DataStorageConfiguration.DEFAULT_FOREST_CONFIG
: DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)
.genesisConfigProvider(GenesisConfigurationFactory::createQbftMigrationGenesisConfig);
if (fixedPort) {
builder.p2pPort(
Math.abs(name.hashCode() % 60000)
+ 1024
+ 500); // Generate a consistent port for p2p based on node name (+ 500 to avoid
// clashing with RPC port or other nodes with a similar name)
}
return create(builder.build());
}
public BesuNode createCustomGenesisNode(
final String name, final String genesisPath, final boolean canBeBootnode) throws IOException {
return createCustomGenesisNode(name, genesisPath, canBeBootnode, false);
@@ -539,6 +572,12 @@ public class BesuNodeFactory {
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()
@@ -553,7 +592,9 @@ public class BesuNodeFactory {
node.createGenesisConfigForValidators(
asList(validators),
nodes,
GenesisConfigurationFactory::createCliqueGenesisConfig))
vs ->
GenesisConfigurationFactory.createCliqueGenesisConfig(
vs, cliqueOptions)))
.build());
}

View File

@@ -96,6 +96,13 @@ public class GenesisConfigurationFactory {
validators, template, QbftExtraDataCodec::createGenesisExtraDataString);
}
public static Optional<String> createQbftMigrationGenesisConfig(
final Collection<? extends RunnableNode> validators) {
final String template = readGenesisFile("/qbft/migration-ibft1/qbft-migration.json");
return updateGenesisExtraData(
validators, template, QbftExtraDataCodec::createGenesisExtraDataString);
}
@SuppressWarnings("unchecked")
public static Optional<String> createQbftValidatorContractGenesisConfig(
final Collection<? extends RunnableNode> validators) throws UncheckedIOException {

View File

@@ -1,78 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class AccountSmartContractPermissioningAllowAccountTransaction implements Transaction<Hash> {
private static final Bytes ADD_ACCOUNT_SIGNATURE =
org.hyperledger.besu.crypto.Hash.keccak256(Bytes.of("addAccount(address)".getBytes(UTF_8)))
.slice(0, 4);
private final Account sender;
private final Address contractAddress;
private final Address account;
public AccountSmartContractPermissioningAllowAccountTransaction(
final Account sender, final Address contractAddress, final Address account) {
this.sender = sender;
this.contractAddress = contractAddress;
this.account = account;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload =
Bytes.concatenate(
ADD_ACCOUNT_SIGNATURE, Bytes.fromHexString("0x000000000000000000000000"), account);
final RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(100_000),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
}

View File

@@ -1,79 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class AccountSmartContractPermissioningForbidAccountTransaction
implements Transaction<Hash> {
private static final Bytes REMOVE_ACCOUNT_SIGNATURE =
org.hyperledger.besu.crypto.Hash.keccak256(Bytes.of("removeAccount(address)".getBytes(UTF_8)))
.slice(0, 4);
private final Account sender;
private final Address contractAddress;
private final Address account;
public AccountSmartContractPermissioningForbidAccountTransaction(
final Account sender, final Address contractAddress, final Address account) {
this.sender = sender;
this.contractAddress = contractAddress;
this.account = account;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload =
Bytes.concatenate(
REMOVE_ACCOUNT_SIGNATURE, Bytes.fromHexString("0x000000000000000000000000"), account);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(100_000),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
}

View File

@@ -1,88 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class AccountSmartContractPermissioningIsAllowedTransaction implements Transaction<Boolean> {
private static final Bytes IS_ACCOUNT_ALLOWED_SIGNATURE =
Hash.keccak256(Bytes.of("whitelistContains(address)".getBytes(UTF_8))).slice(0, 4);
private final Address contractAddress;
private final Address account;
public AccountSmartContractPermissioningIsAllowedTransaction(
final Address contractAddress, final Address account) {
this.contractAddress = contractAddress;
this.account = account;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return checkTransactionResult(Bytes.fromHexString(value));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
// Checks the returned bytes from the permissioning contract call to see if it's a value we
// understand
static Boolean checkTransactionResult(final Bytes result) {
// booleans are padded to 32 bytes
if (result.size() != 32) {
throw new IllegalArgumentException("Unexpected result size");
}
// 0 is false
if (result.equals(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000000"))) {
return false;
// 1 filled to 32 bytes is true
} else if (result.equals(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000001"))) {
return true;
// Anything else is wrong
} else {
throw new IllegalStateException("Unexpected result form");
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final Bytes payload =
Bytes.concatenate(
IS_ACCOUNT_ALLOWED_SIGNATURE,
Bytes.fromHexString("0x000000000000000000000000"),
account);
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
}

View File

@@ -1,50 +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.dsl.transaction.perm;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
public class AccountSmartContractPermissioningTransactions {
private final Accounts accounts;
public AccountSmartContractPermissioningTransactions(final Accounts accounts) {
this.accounts = accounts;
}
public Transaction<Hash> allowAccount(final String contractAddress, final Account account) {
return new AccountSmartContractPermissioningAllowAccountTransaction(
accounts.getPrimaryBenefactor(),
Address.fromHexString(contractAddress),
Address.fromHexString(account.getAddress()));
}
public Transaction<Hash> forbidAccount(final String contractAddress, final Account account) {
return new AccountSmartContractPermissioningForbidAccountTransaction(
accounts.getPrimaryBenefactor(),
Address.fromHexString(contractAddress),
Address.fromHexString(account.getAddress()));
}
public Transaction<Boolean> isAccountAllowed(
final String contractAddress, final Account account) {
return new AccountSmartContractPermissioningIsAllowedTransaction(
Address.fromHexString(contractAddress), Address.fromHexString(account.getAddress()));
}
}

View File

@@ -1,95 +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.dsl.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningAllowNodeByURLV2Transaction
implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningAllowNodeByURLV2Transaction(
final Account sender, final Address contractAddress, final EnodeURL enodeUrl) {
this.sender = sender;
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload = createPayload(enodeUrl);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1_000L),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function addNodeFunction =
FunctionEncoder.makeFunction(
"addEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(addNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error adding node to allowlist", e);
}
}
}

View File

@@ -1,84 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractPermissioningController;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningAllowNodeTransaction implements Transaction<Hash> {
private static final Bytes ADD_ENODE_SIGNATURE =
org.hyperledger.besu.crypto.Hash.keccak256(
Bytes.of("addEnode(bytes32,bytes32,bytes16,uint16)".getBytes(UTF_8)))
.slice(0, 4);
private final Account sender;
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningAllowNodeTransaction(
final Account sender, final Address contractAddress, final Node node) {
this.sender = sender;
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final String enodeURL = ((RunnableNode) node).enodeUrl().toASCIIString();
final Bytes payload =
NodeSmartContractPermissioningController.createPayload(
ADD_ENODE_SIGNATURE, EnodeURLImpl.fromString(enodeURL));
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(100_000),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
}

View File

@@ -1,98 +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.dsl.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningAllowNodeV2Transaction implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningAllowNodeV2Transaction(
final Account sender, final Address contractAddress, final Node node) {
this.sender = sender;
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final EnodeURL enodeURL = EnodeURLImpl.fromURI(((RunnableNode) node).enodeUrl());
final Bytes payload = createPayload(enodeURL);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1_000L),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.getIp().getHostAddress();
final int port = enodeUrl.getListeningPortOrZero();
final Function addNodeFunction =
FunctionEncoder.makeFunction(
"addEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(addNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error adding node to allowlist", e);
}
}
}

View File

@@ -1,80 +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.dsl.transaction.perm;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractV2PermissioningController;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction
implements Transaction<Boolean> {
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction(
final Address contractAddress, final EnodeURL enodeUrl) {
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return Bytes.fromHexString(value)
.equals(NodeSmartContractV2PermissioningController.TRUE_RESPONSE);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final Bytes payload = createPayload(this.enodeUrl);
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function connectionAllowedFunction =
FunctionEncoder.makeFunction(
"connectionAllowed",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(connectionAllowedFunction));
} catch (Exception e) {
throw new RuntimeException("Error calling connectionAllowed", e);
}
}
}

View File

@@ -1,78 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hyperledger.besu.ethereum.permissioning.NodeSmartContractPermissioningController.checkTransactionResult;
import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractPermissioningController;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class NodeSmartContractPermissioningConnectionIsAllowedTransaction
implements Transaction<Boolean> {
private static final Bytes IS_CONNECTION_ALLOWED_SIGNATURE =
Hash.keccak256(
Bytes.of(
"connectionAllowed(bytes32,bytes32,bytes16,uint16,bytes32,bytes32,bytes16,uint16)"
.getBytes(UTF_8)))
.slice(0, 4);
private final Address contractAddress;
private final Node source;
private final Node target;
public NodeSmartContractPermissioningConnectionIsAllowedTransaction(
final Address contractAddress, final Node source, final Node target) {
this.contractAddress = contractAddress;
this.source = source;
this.target = target;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return checkTransactionResult(Bytes.fromHexString(value));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final String sourceEnodeURL = ((RunnableNode) source).enodeUrl().toASCIIString();
final String targetEnodeURL = ((RunnableNode) target).enodeUrl().toASCIIString();
final Bytes payload =
NodeSmartContractPermissioningController.createPayload(
IS_CONNECTION_ALLOWED_SIGNATURE,
EnodeURLImpl.fromString(sourceEnodeURL),
EnodeURLImpl.fromString(targetEnodeURL));
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
}

View File

@@ -1,84 +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.dsl.transaction.perm;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractV2PermissioningController;
import org.hyperledger.besu.plugin.data.EnodeURL;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class NodeSmartContractPermissioningConnectionIsAllowedV2Transaction
implements Transaction<Boolean> {
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningConnectionIsAllowedV2Transaction(
final Address contractAddress, final Node node) {
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return Bytes.fromHexString(value)
.equals(NodeSmartContractV2PermissioningController.TRUE_RESPONSE);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final EnodeURL enodeURL = EnodeURLImpl.fromURI(((RunnableNode) node).enodeUrl());
final Bytes payload = createPayload(enodeURL);
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.getIp().getHostAddress();
final int port = enodeUrl.getListeningPortOrZero();
final Function connectionAllowedFunction =
FunctionEncoder.makeFunction(
"connectionAllowed",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(connectionAllowedFunction));
} catch (Exception e) {
throw new RuntimeException("Error calling connectionAllowed", e);
}
}
}

View File

@@ -1,95 +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.dsl.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningForbidNodeByURLV2Transaction
implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningForbidNodeByURLV2Transaction(
final Account sender, final Address contractAddress, final EnodeURL enodeUrl) {
this.sender = sender;
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload = createPayload(this.enodeUrl);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function removeNodeFunction =
FunctionEncoder.makeFunction(
"removeEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(removeNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error removing node from allowlist", e);
}
}
}

View File

@@ -1,84 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractPermissioningController;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningForbidNodeTransaction implements Transaction<Hash> {
private static final Bytes REMOVE_ENODE_SIGNATURE =
org.hyperledger.besu.crypto.Hash.keccak256(
Bytes.of("removeEnode(bytes32,bytes32,bytes16,uint16)".getBytes(UTF_8)))
.slice(0, 4);
private final Account sender;
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningForbidNodeTransaction(
final Account sender, final Address contractAddress, final Node node) {
this.sender = sender;
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final String enodeURL = ((RunnableNode) node).enodeUrl().toASCIIString();
final Bytes payload =
NodeSmartContractPermissioningController.createPayload(
REMOVE_ENODE_SIGNATURE, EnodeURLImpl.fromString(enodeURL));
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(100_000),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
}

View File

@@ -1,98 +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.dsl.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningForbidNodeV2Transaction implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningForbidNodeV2Transaction(
final Account sender, final Address contractAddress, final Node node) {
this.sender = sender;
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final EnodeURL enodeURL = EnodeURLImpl.fromURI(((RunnableNode) node).enodeUrl());
final Bytes payload = createPayload(enodeURL);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.getIp().getHostAddress();
final int port = enodeUrl.getListeningPortOrZero();
final Function removeNodeFunction =
FunctionEncoder.makeFunction(
"removeEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(removeNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error removing node from allowlist", e);
}
}
}

View File

@@ -1,92 +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.dsl.transaction.perm;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.hyperledger.besu.crypto.Hash;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractPermissioningController;
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.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class NodeSmartContractPermissioningIsAllowedTransaction implements Transaction<Boolean> {
private static final Bytes IS_NODE_ALLOWED_SIGNATURE =
Hash.keccak256(Bytes.of("enodeAllowed(bytes32,bytes32,bytes16,uint16)".getBytes(UTF_8)))
.slice(0, 4);
private final Address contractAddress;
private final Node node;
public NodeSmartContractPermissioningIsAllowedTransaction(
final Address contractAddress, final Node node) {
this.contractAddress = contractAddress;
this.node = node;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return checkTransactionResult(Bytes.fromHexString(value));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
// Checks the returned bytes from the permissioning contract call to see if it's a value we
// understand
static Boolean checkTransactionResult(final Bytes result) {
// booleans are padded to 32 bytes
if (result.size() != 32) {
throw new IllegalArgumentException("Unexpected result size");
}
// 0 is false
if (result.equals(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000000"))) {
return false;
// 1 filled to 32 bytes is true
} else if (result.equals(
Bytes.fromHexString(
"0x0000000000000000000000000000000000000000000000000000000000000001"))) {
return true;
// Anything else is wrong
} else {
throw new IllegalStateException("Unexpected result form");
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final String sourceEnodeURL = ((RunnableNode) node).enodeUrl().toASCIIString();
final Bytes payload =
NodeSmartContractPermissioningController.createPayload(
IS_NODE_ALLOWED_SIGNATURE, EnodeURLImpl.fromString(sourceEnodeURL));
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
}

View File

@@ -1,51 +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.dsl.transaction.perm;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
public class NodeSmartContractPermissioningTransactions {
private final Accounts accounts;
public NodeSmartContractPermissioningTransactions(final Accounts accounts) {
this.accounts = accounts;
}
public Transaction<Hash> allowNode(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningAllowNodeTransaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Hash> forbidNode(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningForbidNodeTransaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Boolean> isNodeAllowed(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningIsAllowedTransaction(
Address.fromHexString(contractAddress), node);
}
public Transaction<Boolean> isConnectionAllowed(
final String contractAddress, final Node source, final Node target) {
return new NodeSmartContractPermissioningConnectionIsAllowedTransaction(
Address.fromHexString(contractAddress), source, target);
}
}

View File

@@ -1,62 +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.dsl.transaction.perm;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
public class NodeSmartContractPermissioningV2Transactions {
private final Accounts accounts;
public NodeSmartContractPermissioningV2Transactions(final Accounts accounts) {
this.accounts = accounts;
}
public Transaction<Hash> allowNode(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningAllowNodeV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Hash> allowNode(final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningAllowNodeByURLV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), enodeURL);
}
public Transaction<Hash> forbidNode(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningForbidNodeV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Hash> forbidNode(final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningForbidNodeByURLV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), enodeURL);
}
public Transaction<Boolean> isConnectionAllowed(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningConnectionIsAllowedV2Transaction(
Address.fromHexString(contractAddress), node);
}
public Transaction<Boolean> isConnectionAllowed(
final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction(
Address.fromHexString(contractAddress), enodeURL);
}
}

View File

@@ -75,6 +75,20 @@ public class TestPermissioningPlugin implements BesuPlugin {
}
return true;
});
service.registerTransactionPermissioningProvider(
transaction -> {
long configuredGasLimitThreshold = 22000L;
long gasLimit = transaction.getGasLimit();
LOG.info(
"Transaction gas limit: {} | Configured threshold: {} ",
gasLimit,
configuredGasLimitThreshold);
// Sample logic to testing. If the gas limit is exactly 21000 (intrinsic gas limit)
// we let the transaction pass. This is helpful for not making additional configuration
// options in PermssioningPluginTest
return gasLimit > configuredGasLimitThreshold || gasLimit == 21000;
});
}
}

View File

@@ -12,8 +12,8 @@
*/
plugins {
id 'org.web3j' version '4.11.3'
id 'org.web3j.solidity' version '0.4.1'
id 'org.web3j' version '4.12.2'
id 'org.web3j.solidity' version '0.5.2'
}
web3j { generatedPackageName = 'org.hyperledger.besu.tests.web3j.generated' }
@@ -73,14 +73,13 @@ dependencies {
testImplementation 'io.vertx:vertx-core'
testImplementation 'org.apache.commons:commons-compress'
testImplementation 'org.apache.logging.log4j:log4j-core'
testImplementation 'io.tmio:tuweni-crypto'
testImplementation 'io.consensys.protocols:tuweni-crypto'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.web3j:abi'
testImplementation 'org.web3j:besu'
testImplementation 'org.web3j:core'
testImplementation 'org.wiremock:wiremock'
testImplementation 'com.google.dagger:dagger'
testAnnotationProcessor 'com.google.dagger:dagger-compiler'
testImplementation project(path: ':acceptance-tests:tests:shanghai')

View File

@@ -1,7 +1,7 @@
plugins {
id 'org.web3j' version '4.11.3'
id 'org.web3j.solidity' version '0.4.1'
id 'org.web3j' version '4.12.2'
id 'org.web3j.solidity' version '0.5.2'
}
jar { enabled = true }

View File

@@ -48,7 +48,7 @@ public class AbstractPreexistingNodeTest extends AcceptanceTestBase {
new TarArchiveInputStream(
new GzipCompressorInputStream(new FileInputStream(path.toAbsolutePath().toString())))) {
TarArchiveEntry entry;
while ((entry = fin.getNextTarEntry()) != null) {
while ((entry = fin.getNextEntry()) != null) {
if (entry.isDirectory()) {
continue;
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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;
import static org.apache.logging.log4j.util.LoaderUtil.getClassLoader;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.junit.jupiter.api.Test;
public class QuorumIBFTMigrationTest extends AcceptanceTestBase {
public static void copyKeyFilesToNodeDataDirs(final BesuNode... nodes) throws IOException {
for (BesuNode node : nodes) {
copyKeyFile(node, "key");
copyKeyFile(node, "key.pub");
}
}
private static void copyKeyFile(final BesuNode node, final String keyFileName)
throws IOException {
String resourceFileName = "qbft/migration-ibft1/" + node.getName() + keyFileName;
try (InputStream keyFileStream = getClassLoader().getResourceAsStream(resourceFileName)) {
if (keyFileStream == null) {
throw new IOException("Resource not found: " + resourceFileName);
}
Path targetPath = node.homeDirectory().resolve(keyFileName);
Files.createDirectories(targetPath.getParent());
Files.copy(keyFileStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
}
public static void runBesuCommand(final Path dataPath) throws IOException, InterruptedException {
ProcessBuilder processBuilder =
new ProcessBuilder(
"../../build/install/besu/bin/besu",
"--genesis-file",
"src/test/resources/qbft/migration-ibft1/qbft-migration.json",
"--data-path",
dataPath.toString(),
"--data-storage-format",
"FOREST",
"blocks",
"import",
"src/test/resources/qbft/migration-ibft1/ibft.blocks");
processBuilder.directory(new File(System.getProperty("user.dir")));
processBuilder.inheritIO(); // This will redirect the output to the console
Process process = processBuilder.start();
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("Import command executed successfully.");
} else {
throw new RuntimeException("Import command execution failed with exit code: " + exitCode);
}
}
@Test
public void shouldImportIBFTBlocksAndTransitionToQBFT() throws Exception {
// Create a mix of Bonsai and Forest DB nodes
final BesuNode minerNode1 =
besu.createQbftMigrationNode("miner1", false, DataStorageFormat.FOREST);
final BesuNode minerNode2 =
besu.createQbftMigrationNode("miner2", false, DataStorageFormat.FOREST);
final BesuNode minerNode3 =
besu.createQbftMigrationNode("miner3", false, DataStorageFormat.FOREST);
final BesuNode minerNode4 =
besu.createQbftMigrationNode("miner4", false, DataStorageFormat.FOREST);
final BesuNode minerNode5 =
besu.createQbftMigrationNode("miner5", false, DataStorageFormat.FOREST);
// Copy key files to the node datadirs
// Use the key files saved in resources directory
copyKeyFilesToNodeDataDirs(minerNode1, minerNode2, minerNode3, minerNode4, minerNode5);
// start one node and import blocks from import file
// Use import file, genesis saved in resources directory
runBesuCommand(minerNode1.homeDirectory());
// After the import is done, start the rest of the nodes using the same genesis and respective
// node keys
cluster.start(minerNode1, minerNode2, minerNode3, minerNode4, minerNode5);
// Check that the chain is progressing as expected
cluster.verify(blockchain.reachesHeight(minerNode2, 1, 120));
}
@Override
public void tearDownAcceptanceTestBase() {
cluster.stop();
super.tearDownAcceptanceTestBase();
}
}

View File

@@ -1,290 +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.bft;
import org.hyperledger.besu.config.JsonUtil;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.AddressHelpers;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.util.List;
import java.util.Optional;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class BftMiningAcceptanceTest extends ParameterizedBftTestBase {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithPaidGas_Berlin(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
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));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_Berlin(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
final MiningConfiguration zeroGasMiningParams =
ImmutableMiningConfiguration.builder()
.mutableInitValues(
MutableInitValues.builder()
.isMiningEnabled(true)
.minTransactionGasPrice(Wei.ZERO)
.coinbase(AddressHelpers.ofValue(1))
.build())
.build();
minerNode.setMiningParameters(zeroGasMiningParams);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 2, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithPaidGas_London(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToLondon(minerNode, false);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
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.create1559Transfer(sender, 50, 4));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_London(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToLondon(minerNode, true);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(accountTransactions.create1559Transfer(sender, 50, 4, Amount.ZERO));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_Shanghai(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToShanghai(minerNode, true);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(accountTransactions.create1559Transfer(sender, 50, 4, Amount.ZERO));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnMultipleNodes(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1");
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2");
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3");
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4");
cluster.start(minerNode1, minerNode2, minerNode3, minerNode4);
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85));
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));
minerNode4.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 3));
cluster.verify(receiver.balanceEquals(6));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnMultipleNodesEvenWhenClusterContainsNonValidator(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final String[] validators = {"validator1", "validator2", "validator3"};
final BesuNode validator1 =
nodeFactory.createNodeWithValidators(besu, "validator1", validators);
final BesuNode validator2 =
nodeFactory.createNodeWithValidators(besu, "validator2", validators);
final BesuNode validator3 =
nodeFactory.createNodeWithValidators(besu, "validator3", validators);
final BesuNode nonValidatorNode =
nodeFactory.createNodeWithValidators(besu, "non-validator", validators);
cluster.start(validator1, validator2, validator3, nonValidatorNode);
cluster.verify(blockchain.reachesHeight(validator1, 1, 85));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
validator1.execute(accountTransactions.createTransfer(sender, 50));
cluster.verify(sender.balanceEquals(50));
validator2.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1));
cluster.verify(receiver.balanceEquals(1));
nonValidatorNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldStillMineWhenANonProposerNodeFailsAndHasSufficientValidators(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1");
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2");
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3");
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4");
final List<BesuNode> validators =
bft.validators(new BesuNode[] {minerNode1, minerNode2, minerNode3, minerNode4});
final BesuNode nonProposerNode = validators.get(validators.size() - 1);
cluster.start(validators);
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85));
final Account receiver = accounts.createAccount("account2");
cluster.stopNode(nonProposerNode);
validators.get(0).execute(accountTransactions.createTransfer(receiver, 80));
cluster.verifyOnActiveNodes(receiver.balanceEquals(80));
}
private static void updateGenesisConfigToLondon(
final BesuNode minerNode, final boolean zeroBaseFeeEnabled) {
final Optional<String> genesisConfig =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final ObjectNode genesisConfigNode = JsonUtil.objectNodeFromString(genesisConfig.orElseThrow());
final ObjectNode config = (ObjectNode) genesisConfigNode.get("config");
config.remove("berlinBlock");
config.put("londonBlock", 0);
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
private static void updateGenesisConfigToShanghai(
final BesuNode minerNode, final boolean zeroBaseFeeEnabled) {
final Optional<String> genesisConfig =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final ObjectNode genesisConfigNode = JsonUtil.objectNodeFromString(genesisConfig.orElseThrow());
final ObjectNode config = (ObjectNode) genesisConfigNode.get("config");
config.remove("berlinBlock");
config.put("shanghaiTime", 100);
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright contributors to Besu.
*
* 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.bft;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.AddressHelpers;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration;
import org.hyperledger.besu.ethereum.core.ImmutableMiningConfiguration.MutableInitValues;
import org.hyperledger.besu.ethereum.core.MiningConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class BftMiningAcceptanceTest_Part1 extends ParameterizedBftTestBase {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithPaidGas_Berlin(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
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));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_Berlin(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
final MiningConfiguration zeroGasMiningParams =
ImmutableMiningConfiguration.builder()
.mutableInitValues(
MutableInitValues.builder()
.isMiningEnabled(true)
.minTransactionGasPrice(Wei.ZERO)
.coinbase(AddressHelpers.ofValue(1))
.build())
.build();
minerNode.setMiningParameters(zeroGasMiningParams);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 2, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithPaidGas_London(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToLondon(minerNode, false);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
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.create1559Transfer(sender, 50, 4));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4));
cluster.verify(receiver.balanceEquals(3));
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright contributors to Besu.
*
* 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.bft;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class BftMiningAcceptanceTest_Part2 extends ParameterizedBftTestBase {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_London(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToLondon(minerNode, true);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(accountTransactions.create1559Transfer(sender, 50, 4, Amount.ZERO));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_Shanghai(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToShanghai(minerNode, true);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(accountTransactions.create1559Transfer(sender, 50, 4, Amount.ZERO));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnMultipleNodes(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1");
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2");
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3");
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4");
cluster.start(minerNode1, minerNode2, minerNode3, minerNode4);
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85));
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));
minerNode4.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 3));
cluster.verify(receiver.balanceEquals(6));
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright contributors to Besu.
*
* 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.bft;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.util.List;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class BftMiningAcceptanceTest_Part3 extends ParameterizedBftTestBase {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnMultipleNodesEvenWhenClusterContainsNonValidator(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final String[] validators = {"validator1", "validator2", "validator3"};
final BesuNode validator1 =
nodeFactory.createNodeWithValidators(besu, "validator1", validators);
final BesuNode validator2 =
nodeFactory.createNodeWithValidators(besu, "validator2", validators);
final BesuNode validator3 =
nodeFactory.createNodeWithValidators(besu, "validator3", validators);
final BesuNode nonValidatorNode =
nodeFactory.createNodeWithValidators(besu, "non-validator", validators);
cluster.start(validator1, validator2, validator3, nonValidatorNode);
cluster.verify(blockchain.reachesHeight(validator1, 1, 85));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
validator1.execute(accountTransactions.createTransfer(sender, 50));
cluster.verify(sender.balanceEquals(50));
validator2.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 1));
cluster.verify(receiver.balanceEquals(1));
nonValidatorNode.execute(accountTransactions.createIncrementalTransfers(sender, receiver, 2));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldStillMineWhenANonProposerNodeFailsAndHasSufficientValidators(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode1 = nodeFactory.createNode(besu, "miner1");
final BesuNode minerNode2 = nodeFactory.createNode(besu, "miner2");
final BesuNode minerNode3 = nodeFactory.createNode(besu, "miner3");
final BesuNode minerNode4 = nodeFactory.createNode(besu, "miner4");
final List<BesuNode> validators =
bft.validators(new BesuNode[] {minerNode1, minerNode2, minerNode3, minerNode4});
final BesuNode nonProposerNode = validators.get(validators.size() - 1);
cluster.start(validators);
cluster.verify(blockchain.reachesHeight(minerNode1, 1, 85));
final Account receiver = accounts.createAccount("account2");
cluster.stopNode(nonProposerNode);
validators.get(0).execute(accountTransactions.createTransfer(receiver, 80));
cluster.verifyOnActiveNodes(receiver.balanceEquals(80));
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright contributors to Besu.
*
* 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.bft;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class BftSyncAcceptanceTest extends ParameterizedBftTestBase {
private static final int TARGET_BLOCK_HEIGHT = 70;
static Stream<Arguments> syncModeTestParameters() {
return Stream.of(SyncMode.FULL, SyncMode.SNAP, SyncMode.CHECKPOINT)
.flatMap(
syncMode ->
factoryFunctions()
.map(args -> Arguments.of(args.get()[0], args.get()[1], syncMode)));
}
@ParameterizedTest(name = "{index}: {0} with {2} sync")
@MethodSource("syncModeTestParameters")
public void shouldSyncValidatorNode(
final String testName,
final BftAcceptanceTestParameterization nodeFactory,
final SyncMode syncMode)
throws Exception {
setUp(testName, nodeFactory);
// Create validator network with 4 validators
final BesuNode validator1 = nodeFactory.createBonsaiNodeFixedPort(besu, "validator1");
final BesuNode validator2 = nodeFactory.createBonsaiNodeFixedPort(besu, "validator2");
final BesuNode validator3 = nodeFactory.createBonsaiNodeFixedPort(besu, "validator3");
final BesuNode validator4 = nodeFactory.createBonsaiNodeFixedPort(besu, "validator4");
// Configure validators with specified sync mode
final SynchronizerConfiguration syncConfig =
SynchronizerConfiguration.builder().syncMode(syncMode).syncMinimumPeerCount(1).build();
validator4.setSynchronizerConfiguration(syncConfig);
// Start first three validators
cluster.start(validator1, validator2, validator3);
validator1.verify(blockchain.minimumHeight(TARGET_BLOCK_HEIGHT, TARGET_BLOCK_HEIGHT));
// Add validator4 to cluster and start
cluster.addNode(validator4);
validator4.verify(blockchain.minimumHeight(TARGET_BLOCK_HEIGHT, 60));
}
}

View File

@@ -14,10 +14,15 @@
*/
package org.hyperledger.besu.tests.acceptance.bft;
import org.hyperledger.besu.config.JsonUtil;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.provider.Arguments;
@@ -30,6 +35,30 @@ public abstract class ParameterizedBftTestBase extends AcceptanceTestBase {
return BftAcceptanceTestParameterization.getFactories();
}
protected static void updateGenesisConfigToLondon(
final BesuNode minerNode, final boolean zeroBaseFeeEnabled) {
final Optional<String> genesisConfig =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final ObjectNode genesisConfigNode = JsonUtil.objectNodeFromString(genesisConfig.orElseThrow());
final ObjectNode config = (ObjectNode) genesisConfigNode.get("config");
config.remove("berlinBlock");
config.put("londonBlock", 0);
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
static void updateGenesisConfigToShanghai(
final BesuNode minerNode, final boolean zeroBaseFeeEnabled) {
final Optional<String> genesisConfig =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final ObjectNode genesisConfigNode = JsonUtil.objectNodeFromString(genesisConfig.orElseThrow());
final ObjectNode config = (ObjectNode) genesisConfigNode.get("config");
config.remove("berlinBlock");
config.put("shanghaiTime", 100);
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
protected void setUp(final String bftType, final BftAcceptanceTestParameterization input) {
this.bftType = bftType;
this.nodeFactory = input;

View File

@@ -30,6 +30,7 @@ import java.time.temporal.ChronoUnit;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -41,8 +42,6 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
private static final long ONE_MINUTE = Duration.of(1, ChronoUnit.MINUTES).toMillis();
private static final long THREE_MINUTES = Duration.of(3, ChronoUnit.MINUTES).toMillis();
private static final long TEN_SECONDS = Duration.of(10, ChronoUnit.SECONDS).toMillis();
static int getTestDurationMins() {
@@ -156,9 +155,9 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
chainHeight = minerNode1.execute(ethTransactions.blockNumber());
lastChainHeight = chainHeight;
// Leave the chain stalled for 3 minutes. Check no new blocks are mined. Then
// Leave the chain stalled for 1 minute. Check no new blocks are mined. Then
// resume the other validators.
nextStepEndTime = previousStepEndTime.plus(3, ChronoUnit.MINUTES);
nextStepEndTime = previousStepEndTime.plus(1, ChronoUnit.MINUTES);
while (System.currentTimeMillis() < nextStepEndTime.toEpochMilli()) {
Thread.sleep(ONE_MINUTE);
chainHeight = minerNode1.execute(ethTransactions.blockNumber());
@@ -212,6 +211,8 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
upgradeToLondon(
minerNode1, minerNode2, minerNode3, minerNode4, lastChainHeight.intValue() + 120);
cluster.verify(blockchain.reachesHeight(minerNode4, 1, 180));
previousStepEndTime = Instant.now();
chainHeight = minerNode1.execute(ethTransactions.blockNumber());
@@ -240,7 +241,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
upgradeToShanghai(
minerNode1, minerNode2, minerNode3, minerNode4, Instant.now().getEpochSecond() + 120);
Thread.sleep(THREE_MINUTES);
cluster.verify(blockchain.reachesHeight(minerNode4, 1, 180));
SimpleStorageShanghai simpleStorageContractShanghai =
minerNode1.execute(contractTransactions.createSmartContract(SimpleStorageShanghai.class));
@@ -344,6 +345,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase {
Thread.sleep(TEN_SECONDS);
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
cluster.stop();

View File

@@ -20,6 +20,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -44,6 +45,7 @@ public class ClusterNoDiscoveryAcceptanceTest extends AcceptanceTestBase {
fullNode.verify(net.awaitPeerCount(0));
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
noDiscoveryCluster.stop();

View File

@@ -31,6 +31,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurati
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -79,6 +80,7 @@ public class ClusterThreadNodeRunnerAcceptanceTest extends AcceptanceTestBase {
miner.verify(recipient.balanceEquals(2));
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
noDiscoveryCluster.stop();

View File

@@ -20,6 +20,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -37,6 +38,7 @@ public class P2pDisabledAcceptanceTest extends AcceptanceTestBase {
p2pDisabledCluster.start(node);
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
p2pDisabledCluster.stop();

View File

@@ -18,61 +18,60 @@ 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.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("flaky see https://github.com/hyperledger/besu/issues/7973")
public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase {
private static final GenesisConfigurationFactory.CliqueOptions CLIQUE_OPTIONS =
new GenesisConfigurationFactory.CliqueOptions(5, 30000, true);
@Test
public void shouldAddValidators() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
public void shouldAddAndRemoveValidators() throws IOException {
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);
waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
}
@Test
public void shouldRemoveValidators() throws IOException {
final String[] initialValidators = {"miner1", "miner2", "miner3"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);
waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
final Condition cliqueValidatorsChanged = clique.awaitSignerSetChange(minerNode1);
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode3));
final Condition cliqueValidatorsChanged = clique.awaitSignerSetChange(minerNode2);
minerNode2.execute(cliqueTransactions.createRemoveProposal(minerNode1));
minerNode3.execute(cliqueTransactions.createRemoveProposal(minerNode1));
cluster.verify(clique.validatorsEqual(minerNode2, minerNode3));
cluster.verify(cliqueValidatorsChanged);
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
}
@Disabled
@Test
public void shouldNotAddValidatorWhenInsufficientVotes() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);
waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
@@ -80,34 +79,57 @@ public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase {
@Test
public void shouldNotRemoveValidatorWhenInsufficientVotes() throws IOException {
final BesuNode minerNode1 = besu.createCliqueNode("miner1");
final BesuNode minerNode2 = besu.createCliqueNode("miner2");
final BesuNode minerNode3 = besu.createCliqueNode("miner3");
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);
waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2));
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode2.execute(cliqueTransactions.createAddProposal(minerNode3));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
minerNode1.execute(cliqueTransactions.createRemoveProposal(minerNode3));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
cluster.verify(clique.validatorsEqual(minerNode1, minerNode2, minerNode3));
}
@Disabled
@Test
public void shouldIncludeVoteInBlockHeader() throws IOException {
final String[] initialValidators = {"miner1", "miner2"};
final BesuNode minerNode1 = besu.createCliqueNodeWithValidators("miner1", initialValidators);
final BesuNode minerNode2 = besu.createCliqueNodeWithValidators("miner2", initialValidators);
final BesuNode minerNode3 = besu.createCliqueNodeWithValidators("miner3", initialValidators);
final String[] initialValidators = {"miner1"};
final BesuNode minerNode1 =
besu.createCliqueNodeWithValidators("miner1", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode2 =
besu.createCliqueNodeWithValidators("miner2", CLIQUE_OPTIONS, initialValidators);
final BesuNode minerNode3 =
besu.createCliqueNodeWithValidators("miner3", CLIQUE_OPTIONS, initialValidators);
cluster.start(minerNode1, minerNode2, minerNode3);
waitForNodesConnectedAndInSync(minerNode1, minerNode2, minerNode3);
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode3));
minerNode1.execute(cliqueTransactions.createAddProposal(minerNode2));
minerNode1.verify(blockchain.reachesHeight(minerNode1, 1));
minerNode1.verify(blockchain.beneficiaryEquals(minerNode3));
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));
@@ -115,17 +137,15 @@ public class CliqueProposeRpcAcceptanceTest extends AcceptanceTestBase {
minerNode1.verify(clique.nonceVoteEquals(CLIQUE_NONCE_VOTE.DROP));
}
private void waitForNodesConnectedAndInSync(
final BesuNode minerNode1, final BesuNode minerNode2, final BesuNode minerNode3) {
private void waitForNodesConnectedAndInSync(final BesuNode... nodes) {
// verify nodes are fully connected otherwise blocks could not be propagated
minerNode1.verify(net.awaitPeerCount(2));
minerNode2.verify(net.awaitPeerCount(2));
minerNode3.verify(net.awaitPeerCount(2));
Arrays.stream(nodes).forEach(node -> node.verify(net.awaitPeerCount(nodes.length - 1)));
// verify that the miner started producing blocks and all other nodes are syncing from it
waitForBlockHeight(minerNode1, 1);
final var minerChainHead = minerNode1.execute(ethTransactions.block());
minerNode2.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
minerNode3.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
waitForBlockHeight(nodes[0], 1);
final var firstNodeChainHead = nodes[0].execute(ethTransactions.block());
Arrays.stream(nodes)
.skip(1)
.forEach(node -> waitForBlockHeight(node, firstNodeChainHead.getNumber().longValue()));
}
}

View File

@@ -31,6 +31,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurati
import java.util.List;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -93,6 +94,7 @@ public class SECP256R1AcceptanceTest extends AcceptanceTestBase {
noDiscoveryCluster.verify(recipient.balanceEquals(5));
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
super.tearDownAcceptanceTestBase();

View File

@@ -0,0 +1,168 @@
/*
* Copyright contributors to Besu.
*
* 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.jsonrpc;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
public abstract class AbstractJsonRpcAuthenticationAcceptanceTest extends AcceptanceTestBase {
protected Cluster authenticatedCluster;
protected BesuNode nodeUsingAuthFile;
protected BesuNode nodeUsingRsaJwtPublicKey;
protected BesuNode nodeUsingEcdsaJwtPublicKey;
protected BesuNode nodeUsingAuthFileWithNoAuthApi;
protected static final String AUTH_FILE = "authentication/auth.toml";
// token with payload{"iat": 1516239022,"exp": 4729363200,"permissions": ["net:peerCount"]}
protected static final String RSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWl"
+ "zc2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.Y6mNV0nvjzOdqAgMgxknFAOUTKoeRAo4aifNgNrWtuXbJJgz6-"
+ "H_0GvLgjlToohPiDZbBJXJJlgb4zzLLB-sRtFnGoPaMgz_d_6z958GjFD7x_Fl0HW-WrTjRNenZNfTyD86OEAf"
+ "XHy-7N3OYY2a5yeDbppTJy6nnHTq9hY-ad22-oWL1RbK3T_hnUJII_uXCZ9bJggSfu5m-NNUrm3TeqdnQzIaIz"
+ "DqHlL0wNZwVPB4cFGN7zKghReBpkRJ8OFlxexQ491Q5eSpuYquhef-yGCIaMfy7GVtpDSD3Y-hjOErr7gUNCUh"
+ "1wlc3Rb7ru_0qNgCWTBPJeRK32GppYotwQ";
protected static final String ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWlz"
+ "c2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.pWXniN6XQ7G8b1nawy8sviPCMxrfbcI6c7UFzeXm26CMGMUEZxiC"
+ "JjRntB8ueuZcsxnGlEhCHt-KngpFEmx5TA";
protected static final List<String> NO_AUTH_API_METHODS = Arrays.asList("net_services");
@Test
public void shouldFailLoginWithWrongCredentials() {
nodeUsingAuthFile.verify(login.failure("user", "badpassword"));
nodeUsingAuthFileWithNoAuthApi.verify(login.failure("user", "badpassword"));
}
@Test
public void shouldSucceedLoginWithCorrectCredentials() {
nodeUsingAuthFile.verify(login.success("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.verify(login.success("user", "pegasys"));
}
@Test
public void jsonRpcMethodShouldSucceedWithAuthenticatedUserAndPermission() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.awaitPeerCount(3));
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void jsonRpcMethodShouldFailOnNonPermittedMethod() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFile.verify(net.netServicesUnauthorized());
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void jsonRpcMethodsNotIncludedInNoAuthListShouldFailWithoutToken() {
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void noAuthJsonRpcMethodShouldSucceedWithoutToken() {
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
}
@Test
public void noAuthJsonRpcConfiguredNodeShouldWorkAsIntended() {
// No token -> all methods other than specified no auth methods should fail
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
// Should behave the same with valid token
String token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingRsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingEcdsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void jsonRpcMethodShouldFailWhenThereIsNoToken() {
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingRsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void loginShouldBeDisabledWhenUsingExternalJwtPublicKey() {
nodeUsingRsaJwtPublicKey.verify(login.disabled());
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
authenticatedCluster.stop();
super.tearDownAcceptanceTestBase();
}
}

View File

@@ -14,43 +14,17 @@
*/
package org.hyperledger.besu.tests.acceptance.jsonrpc;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class JsonRpcHttpAuthenticationAcceptanceTest extends AcceptanceTestBase {
private Cluster authenticatedCluster;
private BesuNode nodeUsingAuthFile;
private BesuNode nodeUsingRsaJwtPublicKey;
private BesuNode nodeUsingEcdsaJwtPublicKey;
private BesuNode nodeUsingAuthFileWithNoAuthApi;
private static final String AUTH_FILE = "authentication/auth.toml";
// token with payload{"iat": 1516239022,"exp": 4729363200,"permissions": ["net:peerCount"]}
private static final String RSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWl"
+ "zc2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.Y6mNV0nvjzOdqAgMgxknFAOUTKoeRAo4aifNgNrWtuXbJJgz6-"
+ "H_0GvLgjlToohPiDZbBJXJJlgb4zzLLB-sRtFnGoPaMgz_d_6z958GjFD7x_Fl0HW-WrTjRNenZNfTyD86OEAf"
+ "XHy-7N3OYY2a5yeDbppTJy6nnHTq9hY-ad22-oWL1RbK3T_hnUJII_uXCZ9bJggSfu5m-NNUrm3TeqdnQzIaIz"
+ "DqHlL0wNZwVPB4cFGN7zKghReBpkRJ8OFlxexQ491Q5eSpuYquhef-yGCIaMfy7GVtpDSD3Y-hjOErr7gUNCUh"
+ "1wlc3Rb7ru_0qNgCWTBPJeRK32GppYotwQ";
private static final String ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWlz"
+ "c2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.pWXniN6XQ7G8b1nawy8sviPCMxrfbcI6c7UFzeXm26CMGMUEZxiC"
+ "JjRntB8ueuZcsxnGlEhCHt-KngpFEmx5TA";
private static final List<String> NO_AUTH_API_METHODS = Arrays.asList("net_services");
public class JsonRpcHttpAuthenticationAcceptanceTest
extends AbstractJsonRpcAuthenticationAcceptanceTest {
@BeforeEach
public void setUp() throws IOException, URISyntaxException {
@@ -75,121 +49,4 @@ public class JsonRpcHttpAuthenticationAcceptanceTest extends AcceptanceTestBase
nodeUsingEcdsaJwtPublicKey.verify(login.awaitResponse("user", "badpassword"));
nodeUsingAuthFileWithNoAuthApi.verify(login.awaitResponse("user", "badpassword"));
}
@Test
public void shouldFailLoginWithWrongCredentials() {
nodeUsingAuthFile.verify(login.failure("user", "badpassword"));
nodeUsingAuthFileWithNoAuthApi.verify(login.failure("user", "badpassword"));
}
@Test
public void shouldSucceedLoginWithCorrectCredentials() {
nodeUsingAuthFile.verify(login.success("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.verify(login.success("user", "pegasys"));
}
@Test
public void jsonRpcMethodShouldSucceedWithAuthenticatedUserAndPermission() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.awaitPeerCount(3));
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void jsonRpcMethodShouldFailOnNonPermittedMethod() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFile.verify(net.netServicesUnauthorized());
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void jsonRpcMethodsNotIncludedInNoAuthListShouldFailWithoutToken() {
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void noAuthJsonRpcMethodShouldSucceedWithoutToken() {
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
}
@Test
public void noAuthJsonRpcConfiguredNodeShouldWorkAsIntended() {
// No token -> all methods other than specified no auth methods should fail
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
// Should behave the same with valid token
String token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingRsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingEcdsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void jsonRpcMethodShouldFailWhenThereIsNoToken() {
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingRsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void loginShouldBeDisabledWhenUsingExternalJwtPublicKey() {
nodeUsingRsaJwtPublicKey.verify(login.disabled());
}
@Override
public void tearDownAcceptanceTestBase() {
authenticatedCluster.stop();
super.tearDownAcceptanceTestBase();
}
}

View File

@@ -14,43 +14,17 @@
*/
package org.hyperledger.besu.tests.acceptance.jsonrpc;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class JsonRpcWebsocketAuthenticationAcceptanceTest extends AcceptanceTestBase {
private BesuNode nodeUsingAuthFile;
private BesuNode nodeUsingRsaJwtPublicKey;
private BesuNode nodeUsingEcdsaJwtPublicKey;
private BesuNode nodeUsingAuthFileWithNoAuthApi;
private Cluster authenticatedCluster;
private static final String AUTH_FILE = "authentication/auth.toml";
private static final List<String> NO_AUTH_API_METHODS = Arrays.asList("net_services");
// token with payload{"iat": 1516239022,"exp": 4729363200,"permissions": ["net:peerCount"]}
private static final String RSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWl"
+ "zc2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.Y6mNV0nvjzOdqAgMgxknFAOUTKoeRAo4aifNgNrWtuXbJJgz6-"
+ "H_0GvLgjlToohPiDZbBJXJJlgb4zzLLB-sRtFnGoPaMgz_d_6z958GjFD7x_Fl0HW-WrTjRNenZNfTyD86OEAf"
+ "XHy-7N3OYY2a5yeDbppTJy6nnHTq9hY-ad22-oWL1RbK3T_hnUJII_uXCZ9bJggSfu5m-NNUrm3TeqdnQzIaIz"
+ "DqHlL0wNZwVPB4cFGN7zKghReBpkRJ8OFlxexQ491Q5eSpuYquhef-yGCIaMfy7GVtpDSD3Y-hjOErr7gUNCUh"
+ "1wlc3Rb7ru_0qNgCWTBPJeRK32GppYotwQ";
private static final String ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT =
"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MTYyMzkwMjIsImV4cCI6NDcyOTM2MzIwMCwicGVybWlz"
+ "c2lvbnMiOlsibmV0OnBlZXJDb3VudCJdfQ.pWXniN6XQ7G8b1nawy8sviPCMxrfbcI6c7UFzeXm26CMGMUEZxiC"
+ "JjRntB8ueuZcsxnGlEhCHt-KngpFEmx5TA";
public class JsonRpcWebsocketAuthenticationAcceptanceTest
extends AbstractJsonRpcAuthenticationAcceptanceTest {
@BeforeEach
public void setUp() throws IOException, URISyntaxException {
@@ -78,121 +52,4 @@ public class JsonRpcWebsocketAuthenticationAcceptanceTest extends AcceptanceTest
nodeUsingEcdsaJwtPublicKey.verify(login.awaitResponse("user", "badpassword"));
nodeUsingAuthFileWithNoAuthApi.verify(login.awaitResponse("user", "badpassword"));
}
@Test
public void shouldFailLoginWithWrongCredentials() {
nodeUsingAuthFile.verify(login.failure("user", "badpassword"));
nodeUsingAuthFileWithNoAuthApi.verify(login.failure("user", "badpassword"));
}
@Test
public void shouldSucceedLoginWithCorrectCredentials() {
nodeUsingAuthFile.verify(login.success("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.verify(login.success("user", "pegasys"));
}
@Test
public void jsonRpcMethodShouldSucceedWithAuthenticatedUserAndPermission() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.awaitPeerCount(3));
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void jsonRpcMethodShouldFailOnNonPermittedMethod() {
String token =
nodeUsingAuthFile.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFile.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFile.verify(net.netServicesUnauthorized());
token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void jsonRpcMethodsNotIncludedInNoAuthListShouldFailWithoutToken() {
nodeUsingAuthFile.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
}
@Test
public void noAuthJsonRpcMethodShouldSucceedWithoutToken() {
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
}
@Test
public void noAuthJsonRpcConfiguredNodeShouldWorkAsIntended() {
// No token -> all methods other than specified no auth methods should fail
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
// Should behave the same with valid token
String token =
nodeUsingAuthFileWithNoAuthApi.execute(
permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
nodeUsingAuthFileWithNoAuthApi.useAuthenticationTokenInHeaderForJsonRpc(token);
nodeUsingAuthFileWithNoAuthApi.verify(net.netVersionUnauthorized());
nodeUsingAuthFileWithNoAuthApi.verify(net.netServicesAllActive());
nodeUsingAuthFileWithNoAuthApi.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalRsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingRsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
RSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingAuthFile.verify(net.netServicesUnauthorized());
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldSucceed() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.awaitPeerCount(3));
}
@Test
public void externalEcdsaJwtPublicKeyUsedOnJsonRpcMethodShouldFailOnNonPermittedMethod() {
nodeUsingEcdsaJwtPublicKey.useAuthenticationTokenInHeaderForJsonRpc(
ECDSA_TOKEN_ALLOWING_NET_PEER_COUNT);
nodeUsingEcdsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingEcdsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void jsonRpcMethodShouldFailWhenThereIsNoToken() {
nodeUsingRsaJwtPublicKey.verify(net.netVersionUnauthorized());
nodeUsingRsaJwtPublicKey.verify(net.netServicesUnauthorized());
}
@Test
public void loginShouldBeDisabledWhenUsingExternalJwtPublicKey() {
nodeUsingRsaJwtPublicKey.verify(login.disabled());
}
@Override
public void tearDownAcceptanceTestBase() {
authenticatedCluster.stop();
super.tearDownAcceptanceTestBase();
}
}

View File

@@ -1,123 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransaction;
import java.math.BigInteger;
import java.util.Arrays;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("permissioning tests flaky with timeouts")
public class AccountLocalAndOnchainPermissioningAcceptanceTest
extends AccountSmartContractPermissioningAcceptanceTestBase {
private Account senderC;
@BeforeEach
public void setUp() {
senderC = accounts.createAccount("Account-C");
}
@Test
public void testAccountCannotSendTxWhenNotOnLocalAllowList() {
// Onchain allowlist: Primary, Secondary, C
// Local allowlist: Primary, Secondary
final Node node =
permissionedNode(
"node1",
Arrays.asList(
accounts.getPrimaryBenefactor().getAddress(),
accounts.getSecondaryBenefactor().getAddress()));
permissionedCluster.start(node);
// ensure SenderC has got some ether available
node.execute(accountTransactions.createTransfer(senderC, 10));
node.verify(senderC.balanceEquals(10));
// add accounts to onchain allowlist
node.execute(allowAccount(accounts.getPrimaryBenefactor()));
node.verify(accountIsAllowed(accounts.getPrimaryBenefactor()));
node.execute(allowAccount(accounts.getSecondaryBenefactor()));
node.verify(accountIsAllowed(accounts.getSecondaryBenefactor()));
node.execute(allowAccount(senderC));
node.verify(accountIsAllowed(senderC));
// sender C should not be able to send Tx
verifyTransferForbidden(node, senderC, accounts.getSecondaryBenefactor());
}
@Test
public void testAccountCannotSendTxWhenNotOnOnchainAllowList() {
// Onchain allowlist: Primary, Secondary, Receiver
// Local allowlist: Primary, Secondary, C, Receiver
final Account receiverAccount = accounts.createAccount("Rec-A");
final Node node =
permissionedNode(
"node1",
Arrays.asList(
accounts.getPrimaryBenefactor().getAddress(),
accounts.getSecondaryBenefactor().getAddress(),
senderC.getAddress(),
receiverAccount.getAddress()));
permissionedCluster.start(node);
// ensure SenderC has got some ether available
node.execute(accountTransactions.createTransfer(senderC, 10));
node.verify(senderC.balanceEquals(10));
// add accounts to onchain allowlist
node.execute(allowAccount(accounts.getPrimaryBenefactor()));
node.verify(accountIsAllowed(accounts.getPrimaryBenefactor()));
node.execute(allowAccount(accounts.getSecondaryBenefactor()));
node.verify(accountIsAllowed(accounts.getSecondaryBenefactor()));
node.execute(allowAccount(receiverAccount));
node.verify(accountIsAllowed(receiverAccount));
// verify senderC is forbidden because it is not on Onchain allowlist
node.verify(accountIsForbidden(senderC));
// sender C should not be able to send Tx
verifyTransferForbidden(node, senderC, accounts.getSecondaryBenefactor());
// final check, other account should be able to send tx
node.execute(
accountTransactions.createTransfer(accounts.getPrimaryBenefactor(), receiverAccount, 5));
node.verify(receiverAccount.balanceEquals(5));
}
private void verifyTransferForbidden(
final Node node, final Account sender, final Account beneficiary) {
final BigInteger nonce = node.execute(ethTransactions.getTransactionCount(sender.getAddress()));
final TransferTransaction transfer =
accountTransactions.createTransfer(sender, beneficiary, 1, nonce);
node.verify(
eth.expectEthSendRawTransactionException(
transfer.signedTransactionData(),
"Sender account not authorized to send transactions"));
}
}

View File

@@ -1,77 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransaction;
import java.math.BigInteger;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class AccountSmartContractPermissioningAcceptanceTest
extends AccountSmartContractPermissioningAcceptanceTestBase {
private Node node;
private Account allowedSender;
private Account otherAccount;
@BeforeEach
public void setUp() {
node = permissionedNode("node1", Collections.emptyList());
permissionedCluster.start(node);
allowedSender = accounts.createAccount("authorized-account");
otherAccount = accounts.createAccount("other-account");
// ensure primary benefactor is permitted (account used to permit/forbid other accounts)
node.execute(allowAccount(accounts.getPrimaryBenefactor()));
node.verify(accountIsAllowed(accounts.getPrimaryBenefactor()));
// ensure allowedSender has got some ether available
node.execute(accountTransactions.createTransfer(allowedSender, 10));
node.verify(allowedSender.balanceEquals(10));
}
@Test
public void allowedAccountCanTransferValue() {
node.execute(allowAccount(allowedSender));
node.verify(accountIsAllowed(allowedSender));
node.execute(accountTransactions.createTransfer(allowedSender, otherAccount, 5));
node.verify(otherAccount.balanceEquals(5));
}
@Test
public void forbiddenAccountCannotTransferValue() {
node.execute(forbidAccount(allowedSender));
node.verify(accountIsForbidden(allowedSender));
verifyTransferForbidden(allowedSender, otherAccount);
}
private void verifyTransferForbidden(final Account sender, final Account beneficiary) {
final BigInteger nonce = node.execute(ethTransactions.getTransactionCount(sender.getAddress()));
final TransferTransaction transfer =
accountTransactions.createTransfer(sender, beneficiary, 1, nonce);
node.verify(
eth.expectEthSendRawTransactionException(
transfer.signedTransactionData(),
"Sender account not authorized to send transactions"));
}
}

View File

@@ -1,102 +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.permissioning;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.condition.perm.AccountSmartContractPermissioningConditions;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.permissioning.PermissionedNodeBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.AccountSmartContractPermissioningTransactions;
import java.io.IOException;
import java.util.List;
class AccountSmartContractPermissioningAcceptanceTestBase extends AcceptanceTestBase {
private final AccountSmartContractPermissioningTransactions smartContractAccountPermissioning;
private final AccountSmartContractPermissioningConditions
accountSmartContractPermissioningConditions;
private static final String CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008888";
private static final String GENESIS_FILE = "/permissioning/simple_permissioning_genesis.json";
protected final Cluster permissionedCluster;
protected AccountSmartContractPermissioningAcceptanceTestBase() {
super();
smartContractAccountPermissioning = new AccountSmartContractPermissioningTransactions(accounts);
accountSmartContractPermissioningConditions =
new AccountSmartContractPermissioningConditions(smartContractAccountPermissioning);
this.permissionedCluster = permissionedCluster();
}
private Cluster permissionedCluster() {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().awaitPeerDiscovery(false).build();
return new Cluster(clusterConfiguration, net);
}
protected Node permissionedNode(final String name, final List<String> accountsPermittedInConfig) {
PermissionedNodeBuilder permissionedNodeBuilder =
this.permissionedNodeBuilder
.name(name)
.genesisFile(GENESIS_FILE)
.accountsContractEnabled(CONTRACT_ADDRESS);
if (accountsPermittedInConfig != null && !accountsPermittedInConfig.isEmpty()) {
permissionedNodeBuilder.accountsPermittedInConfig(accountsPermittedInConfig);
}
return permissionedNodeBuilder.build();
}
protected Node node(final String name) {
try {
return besu.createCustomGenesisNode(name, GENESIS_FILE, false);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
@Override
public void tearDownAcceptanceTestBase() {
permissionedCluster.stop();
super.tearDownAcceptanceTestBase();
}
protected Transaction<Hash> allowAccount(final Account account) {
return smartContractAccountPermissioning.allowAccount(CONTRACT_ADDRESS, account);
}
protected Transaction<Hash> forbidAccount(final Account account) {
return smartContractAccountPermissioning.forbidAccount(CONTRACT_ADDRESS, account);
}
protected Condition accountIsAllowed(final Account account) {
return accountSmartContractPermissioningConditions.accountIsAllowed(CONTRACT_ADDRESS, account);
}
protected Condition accountIsForbidden(final Account account) {
return accountSmartContractPermissioningConditions.accountIsForbidden(
CONTRACT_ADDRESS, account);
}
}

View File

@@ -1,117 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("permissioning tests flaky with timeouts")
public class NodeLocalAndOnchainPermissioningAcceptanceTest
extends NodeSmartContractPermissioningAcceptanceTestBase {
private Node bootnode;
private Node permissionedNode;
private Node allowedNode;
private Node forbiddenNode;
@BeforeEach
public void setUp() {
bootnode = bootnode("bootnode");
forbiddenNode = node("forbidden-node");
allowedNode = node("allowed-node");
permissionedCluster.start(bootnode, allowedNode, forbiddenNode);
}
@Test
public void testNodeCannotConnectWhenAllowedOnchainButNotLocally() {
// add permissioned node after cluster start because we need enode URI for local config
permissionedNode = permissionedNode("permissioned-node", bootnode, allowedNode);
permissionedCluster.addNode(permissionedNode);
// update Onchain smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(nodeIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(nodeIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(nodeIsAllowed(permissionedNode));
permissionedNode.execute(allowNode(forbiddenNode));
permissionedNode.verify(nodeIsAllowed(forbiddenNode));
permissionedNodeShouldDiscoverOnlyAllowedNodes();
}
@Test
public void testNodeCannotConnectWhenAllowedLocallyButNotOnchain() {
// onchain allowlist: A, B
// local allowlist: A, B, C
// add permissioned node after cluster start because we need enode URI for local config
permissionedNode = permissionedNode("permissioned-node", bootnode, allowedNode, forbiddenNode);
permissionedCluster.addNode(permissionedNode);
// update Onchain smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(nodeIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(nodeIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(nodeIsAllowed(permissionedNode));
permissionedNodeShouldDiscoverOnlyAllowedNodes();
}
@Test
public void testNodesCanConnectWhenAllowedBothOnchainAndLocally() {
// add permissioned node after cluster start because we need enode URI for local config
permissionedNode = permissionedNode("permissioned-node", bootnode, allowedNode, forbiddenNode);
permissionedCluster.addNode(permissionedNode);
// update Onchain smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(nodeIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(nodeIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(nodeIsAllowed(permissionedNode));
permissionedNode.execute(allowNode(forbiddenNode));
permissionedNode.verify(nodeIsAllowed(forbiddenNode));
bootnode.verify(net.awaitPeerCount(3));
allowedNode.verify(net.awaitPeerCount(3));
forbiddenNode.verify(net.awaitPeerCount(3));
permissionedNode.verify(net.awaitPeerCount(3));
}
private void permissionedNodeShouldDiscoverOnlyAllowedNodes() {
bootnode.verify(net.awaitPeerCount(3));
allowedNode.verify(net.awaitPeerCount(3));
forbiddenNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(net.awaitPeerCount(2));
}
}

View File

@@ -20,6 +20,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -80,6 +81,7 @@ public class NodeLocalConfigPermissioningAcceptanceTest extends AcceptanceTestBa
permissionedNode.verify(net.awaitPeerCount(3));
}
@AfterEach
@Override
public void tearDownAcceptanceTestBase() {
permissionedCluster.stop();

View File

@@ -1,98 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class NodeSmartContractPermissioningAcceptanceTest
extends NodeSmartContractPermissioningAcceptanceTestBase {
private Node bootnode;
private Node permissionedNode;
private Node allowedNode;
private Node forbiddenNode;
@BeforeEach
public void setUp() {
bootnode = bootnode("bootnode");
forbiddenNode = node("forbidden-node");
allowedNode = node("allowed-node");
permissionedNode = permissionedNode("permissioned-node");
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
// updating permissioning smart contract with allowed nodes
permissionedNode.verify(nodeIsForbidden(bootnode));
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(nodeIsAllowed(bootnode));
permissionedNode.verify(admin.hasPeer(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(nodeIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(nodeIsAllowed(permissionedNode));
permissionedNode.verify(admin.addPeer(allowedNode));
allowedNode.verify(eth.syncingStatus(false));
bootnode.verify(eth.syncingStatus(false));
permissionedNode.verify(eth.syncingStatus(false));
forbiddenNode.verify(eth.syncingStatus(false));
}
@Test
@Disabled("test is flaky")
public void permissionedNodeShouldPeerOnlyWithAllowedNodes() {
bootnode.verify(net.awaitPeerCount(3));
allowedNode.verify(net.awaitPeerCount(3));
forbiddenNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(net.awaitPeerCount(2));
}
@Test
public void permissionedNodeShouldDisconnectFromNodeNotPermittedAnymore() {
permissionedNode.execute(forbidNode(allowedNode));
permissionedNode.verify(connectionIsForbidden(permissionedNode, allowedNode));
permissionedNode.verify(net.awaitPeerCount(1));
}
@Test
public void permissioningUpdatesPropagateThroughNetwork() {
// connection to newly permitted node is allowed
allowedNode.execute(allowNode(forbiddenNode));
allowedNode.verify(connectionIsAllowed(permissionedNode, forbiddenNode));
// permissioning changes in peer should propagate to permissioned node
permissionedNode.verify(connectionIsAllowed(permissionedNode, forbiddenNode));
permissionedNode.verify(admin.addPeer(forbiddenNode));
permissionedNode.verify(net.awaitPeerCount(3));
}
@Test
public void onchainPermissioningAllowlistShouldPersistAcrossRestarts() {
permissionedCluster.stop();
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
permissionedNode.verify(nodeIsAllowed(allowedNode));
permissionedNode.verify(nodeIsAllowed(bootnode));
permissionedNode.verify(nodeIsAllowed(permissionedNode));
}
}

View File

@@ -1,131 +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.permissioning;
import org.hyperledger.besu.datatypes.Hash;
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.perm.NodeSmartContractPermissioningConditions;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.permissioning.PermissionedNodeBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.NodeSmartContractPermissioningTransactions;
import java.io.IOException;
class NodeSmartContractPermissioningAcceptanceTestBase extends AcceptanceTestBase {
private final NodeSmartContractPermissioningTransactions smartContractNodePermissioning;
private final NodeSmartContractPermissioningConditions nodeSmartContractPermissioningConditions;
protected static final String CONTRACT_ADDRESS = "0x0000000000000000000000000000000000009999";
protected static final String GENESIS_FILE = "/permissioning/simple_permissioning_genesis.json";
protected final Cluster permissionedCluster;
protected NodeSmartContractPermissioningAcceptanceTestBase() {
super();
smartContractNodePermissioning = new NodeSmartContractPermissioningTransactions(accounts);
nodeSmartContractPermissioningConditions =
new NodeSmartContractPermissioningConditions(smartContractNodePermissioning);
this.permissionedCluster = permissionedCluster();
}
private Cluster permissionedCluster() {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().awaitPeerDiscovery(false).build();
return new Cluster(clusterConfiguration, net);
}
protected Node permissionedNode(final String name, final Node... localConfigAllowedNodes) {
return permissionedNode(name, GENESIS_FILE, localConfigAllowedNodes);
}
protected Node permissionedNode(
final String name, final String genesisFile, final Node... localConfigAllowedNodes) {
PermissionedNodeBuilder permissionedNodeBuilder =
this.permissionedNodeBuilder
.name(name)
.genesisFile(genesisFile)
.nodesContractEnabled(CONTRACT_ADDRESS);
if (localConfigAllowedNodes != null && localConfigAllowedNodes.length > 0) {
permissionedNodeBuilder.nodesPermittedInConfig(localConfigAllowedNodes);
}
return permissionedNodeBuilder.build();
}
protected Node bootnode(final String name) {
return bootnode(name, GENESIS_FILE);
}
protected Node bootnode(final String name, final String genesisFile) {
try {
return besu.createCustomGenesisNode(name, genesisFile, true);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
protected Node node(final String name) {
try {
return besu.createCustomGenesisNode(name, GENESIS_FILE, false);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
protected Node miner(final String name) {
try {
return besu.createCustomGenesisNode(name, GENESIS_FILE, false, true);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
@Override
public void tearDownAcceptanceTestBase() {
permissionedCluster.stop();
super.tearDownAcceptanceTestBase();
}
protected Transaction<Hash> allowNode(final Node node) {
return smartContractNodePermissioning.allowNode(CONTRACT_ADDRESS, node);
}
protected Condition nodeIsAllowed(final Node node) {
return nodeSmartContractPermissioningConditions.nodeIsAllowed(CONTRACT_ADDRESS, node);
}
protected Transaction<Hash> forbidNode(final Node node) {
return smartContractNodePermissioning.forbidNode(CONTRACT_ADDRESS, node);
}
protected Condition nodeIsForbidden(final Node node) {
return nodeSmartContractPermissioningConditions.nodeIsForbidden(CONTRACT_ADDRESS, node);
}
protected Condition connectionIsAllowed(final Node source, final Node target) {
return nodeSmartContractPermissioningConditions.connectionIsAllowed(
CONTRACT_ADDRESS, source, target);
}
protected Condition connectionIsForbidden(final Node source, final Node target) {
return nodeSmartContractPermissioningConditions.connectionIsForbidden(
CONTRACT_ADDRESS, source, target);
}
}

View File

@@ -1,76 +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.permissioning;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import java.io.IOException;
import java.util.Optional;
import org.junit.jupiter.api.Test;
public class NodeSmartContractPermissioningIbft2StallAcceptanceTest
extends NodeSmartContractPermissioningAcceptanceTestBase {
private static final String GENESIS_FILE =
"/permissioning/simple_permissioning_ibft_genesis.json";
@Test
public void restartedIbftClusterShouldNotStall() throws IOException {
final BesuNode bootnode = besu.createIbft2NonValidatorBootnode("bootnode", GENESIS_FILE);
final BesuNode nodeA = besu.createIbft2Node("nodeA", GENESIS_FILE);
final BesuNode nodeB = besu.createIbft2Node("nodeB", GENESIS_FILE);
permissionedCluster.start(bootnode, nodeA, nodeB);
// make sure we are producing blocks before sending any transactions
waitForBlockHeight(bootnode, 1);
// allow nodes in onchain smart contract
nodeA.execute(allowNode(bootnode));
nodeA.execute(allowNode(nodeA));
nodeA.execute(allowNode(nodeB));
// verify the nodes are allowed
nodeA.verify(nodeIsAllowed(bootnode));
nodeA.verify(nodeIsAllowed(nodeA));
nodeA.verify(nodeIsAllowed(nodeB));
permissionedCluster.stop();
// Create permissioning config
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
new SmartContractPermissioningConfiguration();
smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true);
smartContractPermissioningConfiguration.setNodeSmartContractAddress(
Address.fromHexString(CONTRACT_ADDRESS));
final PermissioningConfiguration permissioningConfiguration =
new PermissioningConfiguration(
Optional.empty(), Optional.of(smartContractPermissioningConfiguration));
// Set permissioning configurations on nodes
bootnode.setPermissioningConfiguration(permissioningConfiguration);
nodeA.setPermissioningConfiguration(permissioningConfiguration);
nodeB.setPermissioningConfiguration(permissioningConfiguration);
permissionedCluster.start(bootnode, nodeA, nodeB);
// Verify blockchain is progressing
permissionedCluster.verify(blockchain.reachesHeight(bootnode, 1, 120));
}
}

View File

@@ -1,67 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class NodeSmartContractPermissioningOutOfSyncAcceptanceTest
extends NodeSmartContractPermissioningAcceptanceTestBase {
private Node bootnode;
private Node permissionedNodeA;
private Node permissionedNodeB;
@BeforeEach
public void setUp() throws InterruptedException {
bootnode = bootnode("bootnode");
permissionedNodeA = permissionedNode("permissioned-node-A");
permissionedNodeB = permissionedNode("permissioned-node-B");
permissionedCluster.start(bootnode, permissionedNodeA);
// update onchain smart contract to allowlist nodes
permissionedNodeA.execute(allowNode(bootnode));
permissionedNodeA.verify(nodeIsAllowed(bootnode));
permissionedNodeA.execute(allowNode(permissionedNodeA));
permissionedNodeA.verify(nodeIsAllowed(permissionedNodeA));
permissionedNodeA.verify(admin.addPeer(bootnode));
}
@Test
@Disabled("test is flaky #7108")
public void addNodeToClusterAndVerifyNonBootNodePeerConnectionWorksAfterSync() {
final long blockchainHeight = 25L;
waitForBlockHeight(permissionedNodeA, blockchainHeight);
// verify Node A is in sync with bootnode
final var minerChainHead = bootnode.execute(ethTransactions.block());
permissionedNodeA.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
// check that connection is forbidden (before node b is permitted)
permissionedCluster.addNode(permissionedNodeB);
permissionedNodeB.verify(connectionIsForbidden(permissionedNodeA, permissionedNodeB));
// Permit Node B
permissionedNodeA.execute(allowNode(permissionedNodeB));
permissionedNodeA.verify(admin.addPeer(permissionedNodeB));
// connection should be allowed after node B syncs
waitForBlockHeight(permissionedNodeB, blockchainHeight);
permissionedNodeB.verify(connectionIsAllowed(permissionedNodeA, permissionedNodeB));
}
}

View File

@@ -1,128 +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.permissioning;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class NodeSmartContractPermissioningV2AcceptanceTest
extends NodeSmartContractPermissioningV2AcceptanceTestBase {
private Node bootnode;
private Node permissionedNode;
private Node allowedNode;
private Node forbiddenNode;
@BeforeEach
public void setUp() {
bootnode = bootnode("bootnode");
forbiddenNode = node("forbidden-node");
allowedNode = node("allowed-node");
permissionedNode = permissionedNode("permissioned-node");
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
verifyAllNodesAreInSyncWithMiner();
// updating permissioning smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(connectionIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(connectionIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(connectionIsAllowed(permissionedNode));
}
@Test
@Disabled("test is flaky")
public void permissionedNodeShouldPeerOnlyWithAllowedNodes() {
bootnode.verify(net.awaitPeerCount(3));
allowedNode.verify(net.awaitPeerCount(3));
forbiddenNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(net.awaitPeerCount(2));
}
@Test
public void permissionedNodeShouldDisconnectFromNodeNotPermittedAnymore() {
permissionedNode.verify(admin.hasPeer(bootnode));
permissionedNode.verify(admin.addPeer(allowedNode));
permissionedNode.verify(net.awaitPeerCount(2));
permissionedNode.execute(forbidNode(allowedNode));
permissionedNode.verify(connectionIsForbidden(allowedNode));
permissionedNode.verify(net.awaitPeerCount(1));
}
@Test
public void permissionedNodeShouldConnectToNewlyPermittedNode() {
permissionedNode.verify(admin.hasPeer(bootnode));
permissionedNode.verify(admin.addPeer(allowedNode));
permissionedNode.verify(net.awaitPeerCount(2));
verifyAllNodesAreInSyncWithMiner();
permissionedNode.execute(allowNode(forbiddenNode));
permissionedNode.verify(connectionIsAllowed(forbiddenNode));
permissionedNode.verify(admin.addPeer(forbiddenNode));
permissionedNode.verify(net.awaitPeerCount(3));
}
@Test
public void permissioningUpdatesPropagateThroughNetwork() {
permissionedNode.verify(admin.hasPeer(bootnode));
permissionedNode.verify(admin.addPeer(allowedNode));
permissionedNode.verify(net.awaitPeerCount(2));
verifyAllNodesAreInSyncWithMiner();
// permissioning changes in peer should propagate to permissioned node
allowedNode.execute(allowNode(forbiddenNode));
allowedNode.verify(connectionIsAllowed(forbiddenNode));
permissionedNode.verify(connectionIsAllowed(forbiddenNode));
permissionedNode.verify(admin.addPeer(forbiddenNode));
permissionedNode.verify(net.awaitPeerCount(3));
}
private void verifyAllNodesAreInSyncWithMiner() {
// verify the miner (permissionedNode) started producing blocks and other nodes are syncing
// from it
waitForBlockHeight(permissionedNode, 1);
final var minerChainHead = permissionedNode.execute(ethTransactions.block());
bootnode.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
allowedNode.verify(blockchain.minimumHeight(minerChainHead.getNumber().longValue()));
}
@Test
public void onchainPermissioningAllowlistShouldPersistAcrossRestarts() {
permissionedCluster.stop();
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
verifyAllNodesAreInSyncWithMiner();
permissionedNode.verify(connectionIsAllowed(allowedNode));
permissionedNode.verify(connectionIsAllowed(bootnode));
permissionedNode.verify(connectionIsAllowed(permissionedNode));
permissionedNode.verify(connectionIsForbidden(forbiddenNode));
}
}

View File

@@ -1,135 +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.permissioning;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
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.perm.NodeSmartContractPermissioningV2Conditions;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.permissioning.PermissionedNodeBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.NodeSmartContractPermissioningV2Transactions;
import java.io.IOException;
class NodeSmartContractPermissioningV2AcceptanceTestBase extends AcceptanceTestBase {
private final NodeSmartContractPermissioningV2Transactions smartContractNodePermissioningV2;
private final NodeSmartContractPermissioningV2Conditions
nodeSmartContractPermissioningConditionsV2;
protected static final String CONTRACT_ADDRESS = "0x0000000000000000000000000000000000009999";
protected static final String GENESIS_FILE =
"/permissioning/simple_permissioning_v2_genesis.json";
protected final Cluster permissionedCluster;
protected NodeSmartContractPermissioningV2AcceptanceTestBase() {
super();
smartContractNodePermissioningV2 = new NodeSmartContractPermissioningV2Transactions(accounts);
nodeSmartContractPermissioningConditionsV2 =
new NodeSmartContractPermissioningV2Conditions(smartContractNodePermissioningV2);
this.permissionedCluster = permissionedCluster();
}
private Cluster permissionedCluster() {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().awaitPeerDiscovery(false).build();
return new Cluster(clusterConfiguration, net);
}
protected Node permissionedNode(final String name, final Node... localConfigAllowedNodes) {
return permissionedNode(name, GENESIS_FILE, localConfigAllowedNodes);
}
protected Node permissionedNode(
final String name, final String genesisFile, final Node... localConfigAllowedNodes) {
PermissionedNodeBuilder permissionedNodeBuilder =
this.permissionedNodeBuilder
.name(name)
.genesisFile(genesisFile)
.nodesContractV2Enabled(CONTRACT_ADDRESS);
if (localConfigAllowedNodes != null && localConfigAllowedNodes.length > 0) {
permissionedNodeBuilder.nodesPermittedInConfig(localConfigAllowedNodes);
}
return permissionedNodeBuilder.build();
}
protected Node bootnode(final String name) {
return bootnode(name, GENESIS_FILE);
}
protected Node bootnode(final String name, final String genesisFile) {
try {
return besu.createCustomGenesisNode(name, genesisFile, true);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
protected Node node(final String name) {
try {
return besu.createCustomGenesisNode(name, GENESIS_FILE, false);
} catch (IOException e) {
throw new RuntimeException("Error creating node", e);
}
}
@Override
public void tearDownAcceptanceTestBase() {
permissionedCluster.stop();
super.tearDownAcceptanceTestBase();
}
protected Transaction<Hash> allowNode(final Node node) {
return smartContractNodePermissioningV2.allowNode(CONTRACT_ADDRESS, node);
}
protected Transaction<Hash> allowNode(final EnodeURL enodeURL) {
return smartContractNodePermissioningV2.allowNode(CONTRACT_ADDRESS, enodeURL);
}
protected Transaction<Hash> forbidNode(final Node node) {
return smartContractNodePermissioningV2.forbidNode(CONTRACT_ADDRESS, node);
}
protected Transaction<Hash> forbidNode(final EnodeURL enodeURL) {
return smartContractNodePermissioningV2.forbidNode(CONTRACT_ADDRESS, enodeURL);
}
protected Condition connectionIsForbidden(final Node node) {
return nodeSmartContractPermissioningConditionsV2.connectionIsForbidden(CONTRACT_ADDRESS, node);
}
protected Condition connectionIsForbidden(final EnodeURL enodeURL) {
return nodeSmartContractPermissioningConditionsV2.connectionIsForbidden(
CONTRACT_ADDRESS, enodeURL);
}
protected Condition connectionIsAllowed(final Node node) {
return nodeSmartContractPermissioningConditionsV2.connectionIsAllowed(CONTRACT_ADDRESS, node);
}
protected Condition connectionIsAllowed(final EnodeURL enodeURL) {
return nodeSmartContractPermissioningConditionsV2.connectionIsAllowed(
CONTRACT_ADDRESS, enodeURL);
}
}

View File

@@ -1,107 +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.permissioning;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("test is flaky #7191")
public class NodeSmartContractPermissioningV2DNSAcceptanceTest
extends NodeSmartContractPermissioningV2AcceptanceTestBase {
private Node bootnode;
private Node permissionedNode;
private Node allowedNode;
private Node forbiddenNode;
final ImmutableEnodeDnsConfiguration enodeDnsConfiguration =
ImmutableEnodeDnsConfiguration.builder().dnsEnabled(true).updateEnabled(true).build();
@BeforeEach
public void setUp() {
bootnode = bootnode("bootnode");
forbiddenNode = node("forbidden-node");
allowedNode = node("allowed-node");
permissionedNode = permissionedNode("permissioned-node");
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
// updating permissioning smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(connectionIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(connectionIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(connectionIsAllowed(permissionedNode));
}
@Test
public void permissionedNodeShouldAddDnsRuleAndAllowNode() throws UnknownHostException {
final EnodeURL forbiddenEnodeURL = getForbiddenEnodeURL();
Assertions.assertThat(forbiddenEnodeURL.toURI().getHost()).isEqualTo("127.0.0.1");
final EnodeURL forbiddenDnsEnodeURL = buildDnsEnodeUrl(forbiddenEnodeURL);
Assertions.assertThat(forbiddenDnsEnodeURL.toURI().getHost())
.isEqualTo(InetAddress.getLocalHost().getHostName());
permissionedNode.verify(connectionIsForbidden(forbiddenNode));
permissionedNode.verify(connectionIsForbidden(forbiddenDnsEnodeURL));
permissionedNode.execute(allowNode(forbiddenDnsEnodeURL));
permissionedNode.verify(connectionIsAllowed(forbiddenDnsEnodeURL));
permissionedNode.execute(forbidNode(forbiddenEnodeURL));
}
@Test
public void permissionedNodeShouldAddDNSRuleAndConnectToNewPeer() throws UnknownHostException {
final EnodeURL forbiddenEnodeURL = getForbiddenEnodeURL();
Assertions.assertThat(forbiddenEnodeURL.toURI().getHost()).isEqualTo("127.0.0.1");
final EnodeURL forbiddenDnsEnodeURL = buildDnsEnodeUrl(forbiddenEnodeURL);
Assertions.assertThat(forbiddenDnsEnodeURL.toURI().getHost())
.isEqualTo(InetAddress.getLocalHost().getHostName());
permissionedNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(connectionIsForbidden(forbiddenNode));
permissionedNode.verify(connectionIsForbidden(forbiddenDnsEnodeURL));
permissionedNode.execute(allowNode(forbiddenDnsEnodeURL));
permissionedNode.verify(connectionIsAllowed(forbiddenDnsEnodeURL));
permissionedNode.verify(admin.addPeer(forbiddenNode));
permissionedNode.verify(net.awaitPeerCount(3));
permissionedNode.execute(forbidNode(forbiddenEnodeURL));
}
private EnodeURL getForbiddenEnodeURL() {
return EnodeURLImpl.fromURI(((RunnableNode) forbiddenNode).enodeUrl());
}
private EnodeURL buildDnsEnodeUrl(final EnodeURL forbiddenEnodeURL) {
return EnodeURLImpl.builder()
.configureFromEnode(forbiddenEnodeURL)
.ipAddress("localhost", enodeDnsConfiguration)
.build();
}
}

View File

@@ -1,85 +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.permissioning;
import static java.util.stream.Collectors.toList;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("flaky test #7155")
public class NodesSmartContractPermissioningStaticNodesAcceptanceTest
extends NodeSmartContractPermissioningAcceptanceTestBase {
private Node miner;
private Node permissionedNode;
@BeforeEach
public void setUp() {
miner = miner("miner");
permissionedCluster.start(miner);
}
@Test
public void onlyTrustStaticNodesWhileOutOfSync() {
// wait for some blocks so the permissioned node has some syncing to do
waitForBlockHeight(miner, 25);
stopMining(miner);
// start permissioned node with miner node in the static nodes list
permissionedNode = permissionedNodeWithStaticNodes(Arrays.asList(miner));
permissionedCluster.addNode(permissionedNode);
// as soon as we start the node should connect to static nodes
permissionedNode.verify(net.awaitPeerCount(1));
waitForBlockHeight(permissionedNode, 25);
// after syncing up with the network the node won't trust static nodes anymore
permissionedNode.verify(net.awaitPeerCount(0));
}
private void stopMining(final Node node) {
node.execute(minerTransactions.minerStop());
node.verify(eth.miningStatus(false));
}
private Node permissionedNodeWithStaticNodes(final List<Node> staticNodes) {
return permissionedNodeBuilder
.name("node-with-static-nodes")
.genesisFile(GENESIS_FILE)
.nodesContractEnabled(CONTRACT_ADDRESS)
.staticNodes(mapNodesToEnodeURLs(staticNodes))
.disableMining()
.build();
}
@Nonnull
private List<String> mapNodesToEnodeURLs(final List<Node> staticNodes) {
return staticNodes.stream()
.map(node -> (RunnableNode) node)
.map(RunnableNode::enodeUrl)
.map(URI::toASCIIString)
.collect(toList());
}
}

View File

@@ -14,18 +14,27 @@
*/
package org.hyperledger.besu.tests.acceptance.plugins;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.SignUtil;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransaction;
import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.RawTransaction;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;
public class PermissioningPluginTest extends AcceptanceTestBase {
private BesuNode minerNode;
@@ -34,6 +43,8 @@ public class PermissioningPluginTest extends AcceptanceTestBase {
private BesuNode bobNode;
private BesuNode charlieNode;
private static final long GAS_LIMIT_THRESHOLD = 22000L;
@BeforeEach
public void setUp() throws Exception {
minerNode = besu.create(createNodeBuilder().name("miner").build());
@@ -96,4 +107,54 @@ public class PermissioningPluginTest extends AcceptanceTestBase {
charlieNode.verify(txPoolConditions.notInTransactionPool(txHash));
minerNode.verify(txPoolConditions.inTransactionPool(txHash));
}
@Test
public void allowFilteredByGasLimit() {
final Account sender = accounts.getPrimaryBenefactor();
final Account recipient = accounts.createAccount("account-two");
final BigInteger GAS_LIMIT = BigInteger.valueOf(GAS_LIMIT_THRESHOLD + 100);
final BigInteger GAS_PRICE = BigInteger.valueOf(1000);
final Amount amount = Amount.wei(BigInteger.valueOf(29));
final RawTransaction tx =
RawTransaction.createEtherTransaction(
sender.getNextNonce(),
GAS_PRICE,
GAS_LIMIT,
recipient.getAddress(),
Convert.toWei(amount.getValue(), amount.getUnit()).toBigIntegerExact());
final String rawSigned =
Numeric.toHexString(
SignUtil.signTransaction(tx, sender, new SECP256K1(), Optional.empty()));
final String txHash = aliceNode.execute(ethTransactions.sendRawTransaction(rawSigned));
aliceNode.verify(txPoolConditions.inTransactionPool(Hash.fromHexString(txHash)));
}
@Test
public void blockedFilteredByGasLimit() {
final Account sender = accounts.getPrimaryBenefactor();
final Account recipient = accounts.createAccount("account-two");
final BigInteger GAS_LIMIT = BigInteger.valueOf(GAS_LIMIT_THRESHOLD - 100);
final BigInteger GAS_PRICE = BigInteger.valueOf(1000);
final Amount amount = Amount.wei(BigInteger.valueOf(29));
final RawTransaction tx =
RawTransaction.createEtherTransaction(
sender.getNextNonce(),
GAS_PRICE,
GAS_LIMIT,
recipient.getAddress(),
Convert.toWei(amount.getValue(), amount.getUnit()).toBigIntegerExact());
final String rawSigned =
Numeric.toHexString(
SignUtil.signTransaction(tx, sender, new SECP256K1(), Optional.empty()));
assertThatThrownBy(() -> aliceNode.execute(ethTransactions.sendRawTransaction(rawSigned)))
.isInstanceOf(RuntimeException.class)
.hasMessageContaining("not authorized");
}
}

View File

@@ -18,12 +18,12 @@
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"blockNumber": "0x1",
"gasLimit": "0x1c9c380",
"gasLimit": "0x1ca35ef",
"gasUsed": "0x0",
"timestamp": "0x5",
"extraData": "0x",
"baseFeePerGas": "0x7",
"blockHash": "0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858",
"blockHash": "0x48513c8021d27d6555aacf2a3a124952c5514f80ab280de32da330f528ad1a11",
"transactions": []
}
},

View File

@@ -18,12 +18,12 @@
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"blockNumber": "0x1",
"gasLimit": "0x1c9c380",
"gasLimit": "0x1ca35ef",
"gasUsed": "0x0",
"timestamp": "0x5",
"extraData": "0x",
"baseFeePerGas": "0x7",
"blockHash": "0xf4a1d287dd3bb7e877c57476912e6a6052bc4eed8ea70d032b55d77f26ee985f",
"blockHash": "0xcdda91dbfe90c051ab1bdb703c9996fdb8cebaa7b9e7bc9e430e7e743e1b9682",
"transactions": []
}
},

View File

@@ -17,7 +17,7 @@
"stateRoot": "0xa61c2a422a4f7d7d7f456c1a83d5484eaf0d49e2b6b6d5716f875e782c66a9f0",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
"gasLimit": "0x1ca35ef",
"gasUsed": "0x0",
"timestamp": "0x10",
"extraData": "0x",
@@ -38,7 +38,7 @@
}
],
"blockNumber": "0x2",
"blockHash": "0x612abd8615f544759d4aeb3dbab32f5f198a8b818e9c5436e9f7a674ef3b0f20",
"blockHash": "0xc7f79c3547adc7886a1607bfd1efb9de3d277991037dba01cffdd67e298aa2bf",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
},
"blockValue": "0x0"

View File

@@ -0,0 +1 @@
0a46b91fe0c770a4355d1fec9ccd72d39264f46a74ed67a69a12ed4c265aa768

View File

@@ -0,0 +1 @@
8093fb3200c783555ed487b8b5210ef3369b062a1f3ce5762d83d7a62205693d1e4f253e840ca48ec98d8f20c5b41bbbd43f34f87a1f68324ab51afe73732b96

View File

@@ -0,0 +1 @@
17c2aacfdf1f6defde20e6ae7132c6d3991e758af3799a307a75b38135678a48

View File

@@ -0,0 +1 @@
d81f65976ccc44c5e7e6ca859c5ede06b0f484f72c52d35dd8f7bd7581a8b7020d9ef45878696b4593daf5575b48dda5259f78f192a3445d5cc97c032660642f

View File

@@ -0,0 +1 @@
917fb1b03034e5d7156b89bc2a3bc2aae1d146d2640d75e095f07110b0871bc1

View File

@@ -0,0 +1 @@
67785a2ac328648d94245abb25bdcfab853d06e68c70026d90f2fd5c8338b65c19235398eac205e4bbdb3fc1de9669ad6309e43ab203c8e7430664cea6451f56

View File

@@ -0,0 +1 @@
3b3cbae8c034c4ba2d5f4df44faa013888216a6eabb7fffa0b224003ea770ba7

View File

@@ -0,0 +1 @@
ec403552908986b5d9e4def3be9ddcb26d5b03def3b44ef2d5d728bb9a3028603405e7379c3e185cb2bc3e784548fcdd0e7616162029c3f407155b2fb25ba0ca

View File

@@ -0,0 +1 @@
4ddfb30d4fcd6f5a9f959961f734e4c1469af223bc16b217eef0d3796e64973d

View File

@@ -0,0 +1 @@
28c02b375d62b0adef8213b76882dfec264d5dcbb0a8ba73f167bc718a6d02f1833af80ab9f51a5f007e5f3b8320e8fc5ab287d4bd59ad497f8949bf4abb9e80

View File

@@ -0,0 +1,63 @@
{
"nonce": "0x0",
"timestamp": "0x58ee40ba",
"extraData": "0x0000000000000000000000000000000000000000000000000000000000000000f86df86994a18182ee8ca476f2f0fb8170a1d4620edb39c5e194065541903bf3bb8c088a18046b441f5d286288c994d1e106d68cac92668b100f6f43791ddcb2c7588094d156777a1e1539fe654fc82266f41fd5d4aa548494efbbd8900222d7b2f75d081c3e7446a1f4fe10ce80c0",
"gasLimit": "700000000",
"gasUsed": "0x0",
"number": "0x0",
"difficulty": "0x1",
"coinbase": "0x0000000000000000000000000000000000000000",
"mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"config": {
"chainId": 1337,
"homesteadBlock": 10,
"eip150Block": 20,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 25,
"eip158Block": 30,
"byzantiumBlock": 50,
"constantinopleBlock": 60,
"petersburgBlock": 70,
"istanbulBlock": 80,
"ibft": {
"epochlength": 100,
"blockperiodseconds": 5,
"requesttimeoutseconds": 10,
"policy": 0,
"ceil2Nby3Block": 0,
"validatorcontractaddress": "0x0000000000000000000000000000000000000000"
},
"qbft": {
"epochLength": 30000,
"blockPeriodSeconds" : 1,
"requestTimeoutSeconds": 10,
"startBlock": 101
},
"txnSizeLimit": 64,
"maxCodeSize": 0,
"maxCodeSizeConfig": [
{
"block": 0,
"size": 64
}
]
},
"alloc": {
"0xde8e2ae09f2ee2c6c282c054b2384f8b5f9debee": {
"balance": "1000000000000000000000000000"
},
"0x23bcbca17fc4978909ab44ac82559c7d379aa006": {
"balance": "1000000000000000000000000000"
},
"0x870276532cca9f33e66273cfa494cf41e04b5a66": {
"balance": "1000000000000000000000000000"
},
"0x7d7fc9fdfa49e2db22fc6ebab593dcf3aeffbde8": {
"balance": "1000000000000000000000000000"
},
"0x4df76ad0678513846699056e0070c5f587580eb5": {
"balance": "1000000000000000000000000000"
}
}
}

View File

@@ -36,4 +36,4 @@
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
}

View File

@@ -37,6 +37,7 @@ dependencies {
implementation project(':consensus:clique')
implementation project(':consensus:common')
implementation project(':consensus:ibft')
implementation project(':consensus:ibftlegacy')
implementation project(':consensus:merge')
implementation project(':consensus:qbft')
implementation project(':consensus:qbft-core')
@@ -71,17 +72,17 @@ dependencies {
implementation 'info.picocli:picocli'
implementation 'io.vertx:vertx-core'
implementation 'io.vertx:vertx-web'
implementation 'io.tmio:tuweni-bytes'
implementation 'io.tmio:tuweni-config'
implementation 'io.tmio:tuweni-toml'
implementation 'io.tmio:tuweni-units'
implementation 'io.consensys.protocols:tuweni-bytes'
implementation 'io.consensys.protocols:tuweni-config'
implementation 'io.consensys.protocols:tuweni-toml'
implementation 'io.consensys.protocols:tuweni-units'
implementation 'org.apache.commons:commons-lang3'
implementation 'org.apache.logging.log4j:log4j-core'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.rocksdb:rocksdbjni'
implementation 'org.springframework.security:spring-security-crypto'
implementation 'org.xerial.snappy:snappy-java'
implementation 'tech.pegasys:jc-kzg-4844'
implementation 'io.consensys.protocols:jc-kzg-4844'
runtimeOnly 'org.apache.logging.log4j:log4j-jul'
runtimeOnly 'com.splunk.logging:splunk-library-javalogging'
@@ -97,8 +98,8 @@ dependencies {
testImplementation 'io.opentelemetry:opentelemetry-api'
testImplementation 'org.mockito:mockito-junit-jupiter'
testImplementation 'org.apache.commons:commons-text'
testImplementation 'io.tmio:tuweni-bytes'
testImplementation 'io.tmio:tuweni-units'
testImplementation 'io.consensys.protocols:tuweni-bytes'
testImplementation 'io.consensys.protocols:tuweni-units'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.junit.jupiter:junit-jupiter'

View File

@@ -173,6 +173,7 @@ public class Runner implements AutoCloseable {
LOG.info("Starting Ethereum main loop ... ");
natService.start();
networkRunner.start();
besuController.getMiningCoordinator().subscribe();
if (networkRunner.getNetwork().isP2pEnabled()) {
besuController.getSynchronizer().start();
}

View File

@@ -118,8 +118,6 @@ import org.hyperledger.besu.nat.NatService;
import org.hyperledger.besu.nat.core.NatManager;
import org.hyperledger.besu.nat.docker.DockerDetector;
import org.hyperledger.besu.nat.docker.DockerNatManager;
import org.hyperledger.besu.nat.kubernetes.KubernetesDetector;
import org.hyperledger.besu.nat.kubernetes.KubernetesNatManager;
import org.hyperledger.besu.nat.upnp.UpnpNatManager;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.data.EnodeURL;
@@ -170,7 +168,6 @@ public class RunnerBuilder {
private String p2pListenInterface = NetworkUtility.INADDR_ANY;
private int p2pListenPort;
private NatMethod natMethod = NatMethod.AUTO;
private String natManagerServiceName;
private boolean natMethodFallbackEnabled;
private EthNetworkConfig ethNetworkConfig;
private EthstatsOptions ethstatsOptions;
@@ -313,17 +310,6 @@ public class RunnerBuilder {
return this;
}
/**
* Add Nat manager service name.
*
* @param natManagerServiceName the nat manager service name
* @return the runner builder
*/
public RunnerBuilder natManagerServiceName(final String natManagerServiceName) {
this.natManagerServiceName = natManagerServiceName;
return this;
}
/**
* Enable Nat method fallback.
*
@@ -1191,10 +1177,17 @@ public class RunnerBuilder {
final BesuController besuController,
final TransactionSimulator transactionSimulator) {
if (permissioningConfiguration.isPresent()) {
if (permissioningConfiguration.isPresent()
|| permissioningService.getTransactionPermissioningProviders().size() > 0) {
final PermissioningConfiguration configuration =
permissioningConfiguration.orElse(
new PermissioningConfiguration(Optional.empty(), Optional.empty()));
final Optional<AccountPermissioningController> accountPermissioningController =
AccountPermissioningControllerFactory.create(
permissioningConfiguration.get(), transactionSimulator, metricsSystem);
configuration,
transactionSimulator,
metricsSystem,
permissioningService.getTransactionPermissioningProviders());
accountPermissioningController.ifPresent(
permissioningController ->
@@ -1213,15 +1206,13 @@ public class RunnerBuilder {
final NatMethod detectedNatMethod =
Optional.of(natMethod)
.filter(not(isEqual(NatMethod.AUTO)))
.orElse(NatService.autoDetectNatMethod(new KubernetesDetector(), new DockerDetector()));
.orElse(NatService.autoDetectNatMethod(new DockerDetector()));
switch (detectedNatMethod) {
case UPNP:
return Optional.of(new UpnpNatManager());
case DOCKER:
return Optional.of(
new DockerNatManager(p2pAdvertisedHost, p2pListenPort, jsonRpcConfiguration.getPort()));
case KUBERNETES:
return Optional.of(new KubernetesNatManager(natManagerServiceName));
case NONE:
default:
return Optional.empty();

View File

@@ -0,0 +1,171 @@
/*
* Copyright contributors to Besu.
*
* 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.chainimport;
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.util.era1.Era1BlockIndex;
import org.hyperledger.besu.util.era1.Era1ExecutionBlockBody;
import org.hyperledger.besu.util.era1.Era1ExecutionBlockHeader;
import org.hyperledger.besu.util.era1.Era1ExecutionBlockReceipts;
import org.hyperledger.besu.util.era1.Era1Reader;
import org.hyperledger.besu.util.era1.Era1ReaderListener;
import org.hyperledger.besu.util.snappy.SnappyFactory;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tool for importing era1-encoded block data, headers, and transaction receipts from era1 files.
*/
public class Era1BlockImporter implements Closeable {
private static final Logger LOG = LoggerFactory.getLogger(Era1BlockImporter.class);
private static final int ERA1_BLOCK_COUNT_MAX = 8192;
private static final int IMPORT_COUNT_FOR_LOG_UPDATE = 1000;
/** Default Constructor. */
public Era1BlockImporter() {}
/**
* Imports the blocks, headers, and transaction receipts from the file found at the supplied path
*
* @param controller The BesuController
* @param path The path
* @throws IOException IOException
* @throws ExecutionException ExecutionException
* @throws InterruptedException InterruptedException
* @throws TimeoutException TimeoutException
*/
public void importBlocks(final BesuController controller, final Path path)
throws IOException, ExecutionException, InterruptedException, TimeoutException {
final ProtocolSchedule protocolSchedule = controller.getProtocolSchedule();
final BlockHeaderFunctions blockHeaderFunctions =
ScheduleBasedBlockHeaderFunctions.create(protocolSchedule);
final ProtocolContext context = controller.getProtocolContext();
Era1Reader reader = new Era1Reader(new SnappyFactory());
final List<Future<BlockHeader>> headersFutures = new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
final List<Future<BlockBody>> bodiesFutures = new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
final List<Future<List<TransactionReceipt>>> receiptsFutures =
new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
reader.read(
new FileInputStream(path.toFile()),
new Era1ReaderListener() {
@Override
public void handleExecutionBlockHeader(
final Era1ExecutionBlockHeader executionBlockHeader) {
headersFutures.add(
CompletableFuture.supplyAsync(
() ->
BlockHeader.readFrom(
new BytesValueRLPInput(
Bytes.wrap(executionBlockHeader.header()), false),
blockHeaderFunctions)));
}
@Override
public void handleExecutionBlockBody(final Era1ExecutionBlockBody executionBlockBody) {
bodiesFutures.add(
CompletableFuture.supplyAsync(
() ->
BlockBody.readWrappedBodyFrom(
new BytesValueRLPInput(Bytes.wrap(executionBlockBody.block()), false),
blockHeaderFunctions,
true)));
}
@Override
public void handleExecutionBlockReceipts(
final Era1ExecutionBlockReceipts executionBlockReceipts) {
receiptsFutures.add(
CompletableFuture.supplyAsync(
() -> {
RLPInput input =
new BytesValueRLPInput(
Bytes.wrap(executionBlockReceipts.receipts()), false);
final List<TransactionReceipt> receiptsForBlock = new ArrayList<>();
input.readList((in) -> receiptsForBlock.add(TransactionReceipt.readFrom(in)));
return receiptsForBlock;
}));
}
@Override
public void handleBlockIndex(final Era1BlockIndex blockIndex) {
// not really necessary, do nothing
}
});
LOG.info("Read {} blocks, now importing", headersFutures.size());
Block block = null;
for (int i = 0; i < headersFutures.size(); i++) {
BlockHeader blockHeader = headersFutures.get(i).get(10, TimeUnit.SECONDS);
BlockImporter blockImporter =
protocolSchedule.getByBlockHeader(blockHeader).getBlockImporter();
block = new Block(blockHeader, bodiesFutures.get(i).get(10, TimeUnit.SECONDS));
BlockImportResult importResult =
blockImporter.importBlockForSyncing(
context,
block,
receiptsFutures.get(i).get(10, TimeUnit.SECONDS),
HeaderValidationMode.NONE,
HeaderValidationMode.NONE,
BodyValidationMode.NONE,
false);
if (importResult.getStatus() != BlockImportResult.BlockImportStatus.IMPORTED) {
LOG.warn(
"Failed to import block {} due to {}",
blockHeader.getNumber(),
importResult.getStatus());
} else if (i % IMPORT_COUNT_FOR_LOG_UPDATE == 0) {
LOG.info("{}/{} blocks imported", i, headersFutures.size());
}
}
LOG.info("Done importing {} blocks", headersFutures.size());
}
@Override
public void close() throws IOException {}
}

View File

@@ -267,14 +267,19 @@ public class RlpBlockImporter implements Closeable {
private BlockHeader lookupPreviousHeader(
final MutableBlockchain blockchain, final BlockHeader header) {
return blockchain
.getBlockHeader(header.getParentHash())
.orElseThrow(
() ->
new IllegalStateException(
String.format(
"Block %s does not connect to the existing chain. Current chain head %s",
header.getNumber(), blockchain.getChainHeadBlockNumber())));
try {
return blockchain
.getBlockHeader(header.getParentHash())
.orElseThrow(
() ->
new IllegalStateException(
String.format(
"Block %s does not connect to the existing chain. Current chain head %s",
header.getNumber(), blockchain.getChainHeadBlockNumber())));
} catch (IllegalStateException e) {
LOG.info("Block {} does not connect to the existing chain.", header.getNumber());
}
return null;
}
@Override

View File

@@ -26,15 +26,16 @@ import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE;
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
import org.hyperledger.besu.BesuInfo;
import org.hyperledger.besu.Runner;
import org.hyperledger.besu.RunnerBuilder;
import org.hyperledger.besu.chainexport.RlpBlockExporter;
import org.hyperledger.besu.chainimport.Era1BlockImporter;
import org.hyperledger.besu.chainimport.JsonBlockImporter;
import org.hyperledger.besu.chainimport.RlpBlockImporter;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NativeRequirement.NativeRequirementResult;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.cli.config.ProfilesCompletionCandidates;
import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty;
@@ -68,7 +69,7 @@ import org.hyperledger.besu.cli.options.RpcWebsocketOptions;
import org.hyperledger.besu.cli.options.SynchronizerOptions;
import org.hyperledger.besu.cli.options.TransactionPoolOptions;
import org.hyperledger.besu.cli.options.storage.DataStorageOptions;
import org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions;
import org.hyperledger.besu.cli.options.storage.PathBasedExtraStorageOptions;
import org.hyperledger.besu.cli.options.unstable.QBFTOptions;
import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner;
import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask;
@@ -102,7 +103,6 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.enclave.EnclaveFactory;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.InProcessRpcConfiguration;
@@ -121,7 +121,6 @@ import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.FrontierTargetingGasLimitCalculator;
import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.discovery.P2PDiscoveryConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
@@ -136,9 +135,9 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutablePathBasedExtraStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract;
import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract;
@@ -279,7 +278,6 @@ import picocli.CommandLine.ParameterException;
"%nMore info and other profiles at https://besu.hyperledger.org%n"
})
public class BesuCommand implements DefaultCommandValues, Runnable {
@SuppressWarnings("PrivateStaticFinalLoggers")
// non-static for testing
private final Logger logger;
@@ -288,6 +286,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final Supplier<RlpBlockImporter> rlpBlockImporter;
private final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory;
private final Supplier<Era1BlockImporter> era1BlockImporter;
private final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory;
// Unstable CLI options
@@ -694,7 +693,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
@CommandLine.Option(
names = {"--cache-last-blocks"},
description = "Specifies the number of last blocks to cache (default: ${DEFAULT-VALUE})")
private final Integer numberOfblocksToCache = 0;
private final Integer numberOfBlocksToCache = 0;
// Plugins Configuration Option Group
@CommandLine.ArgGroup(validate = false)
@@ -723,6 +722,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*
* @param rlpBlockImporter RlpBlockImporter supplier
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
* @param era1BlockImporter Era1BlockImporter supplier
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
* @param runnerBuilder instance of RunnerBuilder
* @param controllerBuilder instance of BesuController.Builder
@@ -733,6 +733,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
public BesuCommand(
final Supplier<RlpBlockImporter> rlpBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Supplier<Era1BlockImporter> era1BlockImporter,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
final RunnerBuilder runnerBuilder,
final BesuController.Builder controllerBuilder,
@@ -742,6 +743,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this(
rlpBlockImporter,
jsonBlockImporterFactory,
era1BlockImporter,
rlpBlockExporterFactory,
runnerBuilder,
controllerBuilder,
@@ -764,6 +766,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
*
* @param rlpBlockImporter RlpBlockImporter supplier
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
* @param era1BlockImporter Era1BlockImporter supplier
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
* @param runnerBuilder instance of RunnerBuilder
* @param controllerBuilder instance of BesuController.Builder
@@ -784,6 +787,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
protected BesuCommand(
final Supplier<RlpBlockImporter> rlpBlockImporter,
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
final Supplier<Era1BlockImporter> era1BlockImporter,
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
final RunnerBuilder runnerBuilder,
final BesuController.Builder controllerBuilder,
@@ -802,8 +806,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this.logger = commandLogger;
this.rlpBlockImporter = rlpBlockImporter;
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
this.jsonBlockImporterFactory = jsonBlockImporterFactory;
this.era1BlockImporter = era1BlockImporter;
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
this.runnerBuilder = runnerBuilder;
this.controllerBuilder = controllerBuilder;
this.besuPluginContext = besuPluginContext;
@@ -970,7 +975,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
// explicitly enabled, perform compatibility check
VersionMetadata.versionCompatibilityChecks(versionCompatibilityProtection, dataDir());
configureNativeLibs();
configureNativeLibs(Optional.ofNullable(network));
besuController = buildController();
besuPluginContext.beforeExternalServices();
@@ -990,7 +995,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
runner.awaitStop();
} catch (final Exception e) {
logger.error("Failed to start Besu", e);
logger.error("Failed to start Besu: {}", e.getMessage());
logger.debug("Startup failure cause", e);
throw new ParameterException(this.commandLine, e.getMessage(), e);
}
}
@@ -1104,6 +1110,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
new BlocksSubCommand(
rlpBlockImporter,
jsonBlockImporterFactory,
era1BlockImporter,
rlpBlockExporterFactory,
commandLine.getOut()));
commandLine.addSubcommand(
@@ -1383,7 +1390,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
return Optional.ofNullable(colorEnabled);
}
private void configureNativeLibs() {
@VisibleForTesting
void configureNativeLibs(final Optional<NetworkName> configuredNetwork) {
if (unstableNativeLibraryOptions.getNativeAltbn128()
&& AbstractAltBnPrecompiledContract.maybeEnableNative()) {
logger.info("Using the native implementation of alt bn128");
@@ -1430,6 +1438,37 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
this.commandLine,
"--kzg-trusted-setup can only be specified on networks with data blobs enabled");
}
// assert required native libraries have been loaded
if (genesisFile == null && configuredNetwork.isPresent()) {
checkRequiredNativeLibraries(configuredNetwork.get());
}
}
@VisibleForTesting
void checkRequiredNativeLibraries(final NetworkName configuredNetwork) {
if (configuredNetwork == null) {
return;
}
// assert native library requirements for named networks:
List<NativeRequirementResult> failedNativeReqs =
configuredNetwork.getNativeRequirements().stream().filter(r -> !r.present()).toList();
if (!failedNativeReqs.isEmpty()) {
String failures =
failedNativeReqs.stream()
.map(r -> r.libname() + " " + r.errorMessage())
.collect(Collectors.joining("\n\t"));
throw new UnsupportedOperationException(
String.format(
"Failed to load required native libraries for network %s. "
+ "Verify whether your platform %s and arch %s are supported by besu. "
+ "Failures loading: \n%s",
configuredNetwork.name(),
System.getProperty("os.name"),
System.getProperty("os.arch"),
failures));
}
}
private void validateOptions() {
@@ -1447,27 +1486,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
validateTransactionPoolOptions();
validateDataStorageOptions();
validateGraphQlOptions();
validateConsensusSyncCompatibilityOptions();
validatePluginOptions();
}
private void validateConsensusSyncCompatibilityOptions() {
// snap and checkpoint are experimental for BFT
if ((genesisConfigOptionsSupplier.get().isIbftLegacy()
|| genesisConfigOptionsSupplier.get().isIbft2()
|| genesisConfigOptionsSupplier.get().isQbft())
&& !unstableSynchronizerOptions.isSnapSyncBftEnabled()) {
final String errorSuffix = "can't be used with BFT networks";
if (SyncMode.CHECKPOINT.equals(syncMode)) {
throw new ParameterException(
commandLine, String.format("%s %s", "Checkpoint sync", errorSuffix));
}
if (syncMode == SyncMode.SNAP) {
throw new ParameterException(commandLine, String.format("%s %s", "Snap sync", errorSuffix));
}
}
}
private void validatePluginOptions() {
pluginsConfigurationOptions.validate(commandLine);
}
@@ -1509,22 +1530,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
@SuppressWarnings("ConstantConditions")
private void validateNatParams() {
if (natMethod.equals(NatMethod.KUBERNETES)) {
logger.warn("Kubernetes NAT method is deprecated. Please use Docker or UPNP");
}
if (!unstableNatOptions.getNatManagerServiceName().equals(DEFAULT_BESU_SERVICE_NAME_FILTER)) {
logger.warn(
"`--Xnat-kube-service-name` and Kubernetes NAT method are deprecated. Please use Docker or UPNP");
}
if (!(natMethod.equals(NatMethod.AUTO) || natMethod.equals(NatMethod.KUBERNETES))
&& !unstableNatOptions
.getNatManagerServiceName()
.equals(DEFAULT_BESU_SERVICE_NAME_FILTER)) {
throw new ParameterException(
this.commandLine,
"The `--Xnat-kube-service-name` parameter is only used in kubernetes mode. Either remove --Xnat-kube-service-name"
+ " or select the KUBERNETES mode (via --nat--method=KUBERNETES)");
}
if (natMethod.equals(NatMethod.AUTO) && !unstableNatOptions.getNatMethodFallbackEnabled()) {
throw new ParameterException(
this.commandLine,
@@ -1681,7 +1686,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"--Xsnapsync-synchronizer-flat option can only be used when --Xbonsai-full-flat-db-enabled is true",
dataStorageOptions
.toDomainObject()
.getDiffBasedSubStorageConfiguration()
.getPathBasedExtraStorageConfiguration()
.getUnstable()
.getFullFlatDbEnabled(),
asList(
@@ -1822,10 +1827,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.isRevertReasonEnabled(isRevertReasonEnabled)
.storageProvider(storageProvider)
.isEarlyRoundChangeEnabled(unstableQbftOptions.isEarlyRoundChangeEnabled())
.gasLimitCalculator(
miningParametersSupplier.get().getTargetGasLimit().isPresent()
? new FrontierTargetingGasLimitCalculator()
: GasLimitCalculator.constant())
.requiredBlocks(requiredBlocks)
.reorgLoggingThreshold(reorgLoggingThreshold)
.evmConfiguration(unstableEvmOptions.toDomainObject())
@@ -1833,13 +1834,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers)
.randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority)
.chainPruningConfiguration(unstableChainPruningOptions.toDomainObject())
.cacheLastBlocks(numberOfblocksToCache)
.cacheLastBlocks(numberOfBlocksToCache)
.genesisStateHashCacheEnabled(genesisStateHashCacheEnabled)
.apiConfiguration(apiConfigurationSupplier.get())
.besuComponent(besuComponent);
if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getDiffBasedSubStorageConfiguration();
final PathBasedExtraStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getPathBasedExtraStorageConfiguration();
besuControllerBuilder.isParallelTxProcessingEnabled(
subStorageConfiguration.getUnstable().isParallelTxProcessingEnabled());
}
@@ -2156,13 +2157,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
getGenesisBlockPeriodSeconds(genesisConfigOptionsSupplier.get())
.ifPresent(miningParameters::setBlockPeriodSeconds);
initMiningParametersMetrics(miningParameters);
// if network = holesky, set targetGasLimit to 36,000,000 unless otherwise specified
if (miningParameters.getTargetGasLimit().isEmpty() && NetworkName.HOLESKY.equals(network)) {
logger.info(
"Setting target gas limit for holesky: {}",
MiningConfiguration.DEFAULT_TARGET_GAS_LIMIT_HOLESKY);
miningParameters.setTargetGasLimit(MiningConfiguration.DEFAULT_TARGET_GAS_LIMIT_HOLESKY);
}
return miningParameters;
}
@@ -2183,30 +2178,30 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
if (SyncMode.FULL.equals(getDefaultSyncModeIfNotSet())
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration diffBasedSubStorageConfiguration =
dataStorageConfiguration.getDiffBasedSubStorageConfiguration();
if (diffBasedSubStorageConfiguration.getLimitTrieLogsEnabled()) {
final PathBasedExtraStorageConfiguration pathBasedExtraStorageConfiguration =
dataStorageConfiguration.getPathBasedExtraStorageConfiguration();
if (pathBasedExtraStorageConfiguration.getLimitTrieLogsEnabled()) {
if (CommandLineUtils.isOptionSet(
commandLine, DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED)) {
commandLine, PathBasedExtraStorageOptions.LIMIT_TRIE_LOGS_ENABLED)) {
throw new ParameterException(
commandLine,
String.format(
"Cannot enable %s with --sync-mode=%s and --data-storage-format=%s. You must set %s or use a different sync-mode",
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED,
PathBasedExtraStorageOptions.LIMIT_TRIE_LOGS_ENABLED,
SyncMode.FULL,
DataStorageFormat.BONSAI,
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false"));
PathBasedExtraStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false"));
}
dataStorageConfiguration =
ImmutableDataStorageConfiguration.copyOf(dataStorageConfiguration)
.withDiffBasedSubStorageConfiguration(
ImmutableDiffBasedSubStorageConfiguration.copyOf(
dataStorageConfiguration.getDiffBasedSubStorageConfiguration())
.withPathBasedExtraStorageConfiguration(
ImmutablePathBasedExtraStorageConfiguration.copyOf(
dataStorageConfiguration.getPathBasedExtraStorageConfiguration())
.withLimitTrieLogsEnabled(false));
logger.warn(
"Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.",
DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false",
PathBasedExtraStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false",
SyncMode.FULL,
DataStorageFormat.BONSAI);
}
@@ -2264,7 +2259,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.besuController(controller)
.p2pEnabled(p2pEnabled)
.natMethod(natMethod)
.natManagerServiceName(unstableNatOptions.getNatManagerServiceName())
.natMethodFallbackEnabled(unstableNatOptions.getNatMethodFallbackEnabled())
.discoveryEnabled(peerDiscoveryEnabled)
.ethNetworkConfig(ethNetworkConfig)
@@ -2774,8 +2768,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) {
final DiffBasedSubStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getDiffBasedSubStorageConfiguration();
final PathBasedExtraStorageConfiguration subStorageConfiguration =
getDataStorageConfiguration().getPathBasedExtraStorageConfiguration();
if (subStorageConfiguration.getLimitTrieLogsEnabled()) {
builder.setLimitTrieLogsEnabled();
builder.setTrieLogRetentionLimit(subStorageConfiguration.getMaxLayersToLoad());
@@ -2784,7 +2778,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
}
builder.setSnapServerEnabled(this.unstableSynchronizerOptions.isSnapsyncServerEnabled());
builder.setSnapSyncBftEnabled(this.unstableSynchronizerOptions.isSnapSyncBftEnabled());
builder.setTxPoolImplementation(buildTransactionPoolConfiguration().getTxPoolImplementation());
builder.setWorldStateUpdateMode(unstableEvmOptions.toDomainObject().worldUpdaterMode());

View File

@@ -57,7 +57,6 @@ public class ConfigurationOverviewBuilder {
private long trieLogRetentionLimit = 0;
private Integer trieLogsPruningWindowSize = null;
private boolean isSnapServerEnabled = false;
private boolean isSnapSyncBftEnabled = false;
private TransactionPoolConfiguration.Implementation txPoolImplementation;
private EvmConfiguration.WorldUpdaterMode worldStateUpdateMode;
private Map<String, String> environment;
@@ -246,17 +245,6 @@ public class ConfigurationOverviewBuilder {
return this;
}
/**
* Sets snap sync BFT enabled/disabled
*
* @param snapSyncBftEnabled bool to indicate if snap sync for BFT is enabled
* @return the builder
*/
public ConfigurationOverviewBuilder setSnapSyncBftEnabled(final boolean snapSyncBftEnabled) {
isSnapSyncBftEnabled = snapSyncBftEnabled;
return this;
}
/**
* Sets trie logs pruning window size
*
@@ -386,10 +374,6 @@ public class ConfigurationOverviewBuilder {
lines.add("Experimental Snap Sync server enabled");
}
if (isSnapSyncBftEnabled) {
lines.add("Experimental Snap Sync for BFT enabled");
}
if (isLimitTrieLogsEnabled) {
final StringBuilder trieLogPruningString = new StringBuilder();
trieLogPruningString

View File

@@ -0,0 +1,69 @@
/*
* Copyright contributors to Besu.
*
* 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.cli.config;
import org.hyperledger.besu.crypto.SECP256K1;
import org.hyperledger.besu.evm.precompile.AltBN128PairingPrecompiledContract;
import org.hyperledger.besu.evm.precompile.BLS12PairingPrecompiledContract;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
/** Encapsulates the native library requirements of given networks. */
public interface NativeRequirement {
/**
* Record type to encapsulate the result of native library loading
*
* @param present boolean indicating library loading present or failure.
* @param libname string indicating the required library name.
* @param errorMessage Optional error message suitable to log.
*/
record NativeRequirementResult(Boolean present, String libname, Optional<String> errorMessage) {}
/** Ethereum mainnet-like performance requirements: */
Supplier<List<NativeRequirementResult>> MAINNET =
() -> {
List<NativeRequirementResult> requirements = new ArrayList<>();
var secp256k1 = new SECP256K1();
requirements.add(
new NativeRequirementResult(
secp256k1.maybeEnableNative(),
"secp256k1",
secp256k1.maybeEnableNative()
? Optional.empty()
: Optional.of("secp256k1: Native secp256k1 failed to load")));
requirements.add(
new NativeRequirementResult(
AltBN128PairingPrecompiledContract.isNative(),
"alt_bn128",
AltBN128PairingPrecompiledContract.isNative()
? Optional.empty()
: Optional.of("alt_bn128: EC native library failed to load")));
requirements.add(
new NativeRequirementResult(
BLS12PairingPrecompiledContract.isAvailable(),
"bls12-381",
BLS12PairingPrecompiledContract.isAvailable()
? Optional.empty()
: Optional.of("bls12-381: EC native library failed to load")));
return requirements;
};
}

View File

@@ -14,29 +14,34 @@
*/
package org.hyperledger.besu.cli.config;
import org.hyperledger.besu.cli.config.NativeRequirement.NativeRequirementResult;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.commons.lang3.StringUtils;
/** The enum Network name. */
public enum NetworkName {
/** Mainnet network name. */
MAINNET("/mainnet.json", BigInteger.valueOf(1)),
MAINNET("/mainnet.json", BigInteger.valueOf(1), true, NativeRequirement.MAINNET),
/** Sepolia network name. */
SEPOLIA("/sepolia.json", BigInteger.valueOf(11155111)),
SEPOLIA("/sepolia.json", BigInteger.valueOf(11155111), true, NativeRequirement.MAINNET),
/** Holešky network name. */
HOLESKY("/holesky.json", BigInteger.valueOf(17000)),
/** LUKSO mainnet network name. */
LUKSO("/lukso.json", BigInteger.valueOf(42)),
HOLESKY("/holesky.json", BigInteger.valueOf(17000), true, NativeRequirement.MAINNET),
/** Hoodi network name. */
HOODI("/hoodi.json", BigInteger.valueOf(560048), true, NativeRequirement.MAINNET),
/**
* EPHEMERY network name. The actual networkId used is calculated based on this default value and
* the current time. https://ephemery.dev/
*/
EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135)),
EPHEMERY("/ephemery.json", BigInteger.valueOf(39438135), true, NativeRequirement.MAINNET),
/** LUKSO mainnet network name. */
LUKSO("/lukso.json", BigInteger.valueOf(42)),
/** Dev network name. */
DEV("/dev.json", BigInteger.valueOf(2018), false),
/** Future EIPs network name. */
@@ -56,17 +61,27 @@ public enum NetworkName {
private final BigInteger networkId;
private final boolean canSnapSync;
private final String deprecationDate;
private final Supplier<List<NativeRequirementResult>> nativeRequirements;
NetworkName(final String genesisFile, final BigInteger networkId) {
this(genesisFile, networkId, true);
}
NetworkName(final String genesisFile, final BigInteger networkId, final boolean canSnapSync) {
this(genesisFile, networkId, canSnapSync, Collections::emptyList);
}
NetworkName(
final String genesisFile,
final BigInteger networkId,
final boolean canSnapSync,
final Supplier<List<NativeRequirementResult>> nativeRequirements) {
this.genesisFile = genesisFile;
this.networkId = networkId;
this.canSnapSync = canSnapSync;
// no deprecations planned
this.deprecationDate = null;
this.nativeRequirements = nativeRequirements;
}
/**
@@ -122,4 +137,13 @@ public enum NetworkName {
public Optional<String> getDeprecationDate() {
return Optional.ofNullable(deprecationDate);
}
/**
* Gets native requirements for this network.
*
* @return result of native library requirements defined for this network, as a list.
*/
public List<NativeRequirementResult> getNativeRequirements() {
return this.nativeRequirements.get();
}
}

View File

@@ -14,21 +14,11 @@
*/
package org.hyperledger.besu.cli.options;
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
import picocli.CommandLine;
/** The Nat Cli options. */
public class NatOptions {
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
hidden = true,
names = {"--Xnat-kube-service-name"},
description =
"Specify the name of the service that will be used by the nat manager in Kubernetes. (default: ${DEFAULT-VALUE})")
private String natManagerServiceName = DEFAULT_BESU_SERVICE_NAME_FILTER;
@CommandLine.Option(
hidden = true,
names = {"--Xnat-method-fallback-enabled"},
@@ -49,15 +39,6 @@ public class NatOptions {
return new NatOptions();
}
/**
* Gets nat manager service name.
*
* @return the nat manager service name
*/
public String getNatManagerServiceName() {
return natManagerServiceName;
}
/**
* Whether nat method fallback is enabled.
*

View File

@@ -306,12 +306,15 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
private Boolean checkpointPostMergeSyncEnabled =
SynchronizerConfiguration.DEFAULT_CHECKPOINT_POST_MERGE_ENABLED;
// TODO --Xsnapsync-bft-enabled is deprecated,
// remove in a future release
@CommandLine.Option(
names = SNAP_SYNC_BFT_ENABLED_FLAG,
names = SNAP_SYNC_BFT_ENABLED_FLAG, // deprecated
hidden = true,
paramLabel = "<Boolean>",
arity = "0..1",
description = "Snap sync enabled for BFT chains (default: ${DEFAULT-VALUE})")
description =
"This option is now deprecated and ignored, and will be removed in future release. Snap sync for BFT is supported by default.")
private Boolean snapsyncBftEnabled = SnapSyncConfiguration.DEFAULT_SNAP_SYNC_BFT_ENABLED;
@CommandLine.Option(
@@ -409,7 +412,6 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
config.getSnapSyncConfiguration().getLocalFlatStorageCountToHealPerRequest();
options.checkpointPostMergeSyncEnabled = config.isCheckpointPostMergeEnabled();
options.snapsyncServerEnabled = config.getSnapSyncConfiguration().isSnapServerEnabled();
options.snapsyncBftEnabled = config.getSnapSyncConfiguration().isSnapSyncBftEnabled();
options.snapTransactionIndexingEnabled =
config.getSnapSyncConfiguration().isSnapSyncTransactionIndexingEnabled();
return options;
@@ -444,7 +446,6 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
.localFlatAccountCountToHealPerRequest(snapsyncFlatAccountHealedCountPerRequest)
.localFlatStorageCountToHealPerRequest(snapsyncFlatStorageHealedCountPerRequest)
.isSnapServerEnabled(snapsyncServerEnabled)
.isSnapSyncBftEnabled(snapsyncBftEnabled)
.isSnapSyncTransactionIndexingEnabled(snapTransactionIndexingEnabled)
.build());
builder.checkpointPostMergeEnabled(checkpointPostMergeSyncEnabled);
@@ -504,8 +505,6 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
OptionParser.format(snapsyncFlatStorageHealedCountPerRequest),
SNAP_SERVER_ENABLED_FLAG,
OptionParser.format(snapsyncServerEnabled),
SNAP_SYNC_BFT_ENABLED_FLAG,
OptionParser.format(snapsyncBftEnabled),
SNAP_TRANSACTION_INDEXING_ENABLED_FLAG,
OptionParser.format(snapTransactionIndexingEnabled));
return value;

View File

@@ -50,12 +50,12 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
private Boolean receiptCompactionEnabled = DEFAULT_RECEIPT_COMPACTION_ENABLED;
/**
* Options specific to diff-based storage modes. Holds the necessary parameters to configure
* diff-based storage, such as the Bonsai mode or Verkle in the future.
* Options specific to path-based storage modes. Holds the necessary parameters to configure
* path-based storage, such as the Bonsai mode or Verkle in the future.
*/
@Mixin
private DiffBasedSubStorageOptions diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.create();
private PathBasedExtraStorageOptions pathBasedExtraStorageOptions =
PathBasedExtraStorageOptions.create();
/** Default Constructor. */
DataStorageOptions() {}
@@ -75,7 +75,7 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
* @param commandLine the full commandLine to check all the options specified by the user
*/
public void validate(final CommandLine commandLine) {
diffBasedSubStorageOptions.validate(commandLine, dataStorageFormat);
pathBasedExtraStorageOptions.validate(commandLine, dataStorageFormat);
}
/**
@@ -88,8 +88,9 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
dataStorageOptions.dataStorageFormat = domainObject.getDataStorageFormat();
dataStorageOptions.receiptCompactionEnabled = domainObject.getReceiptCompactionEnabled();
dataStorageOptions.diffBasedSubStorageOptions =
DiffBasedSubStorageOptions.fromConfig(domainObject.getDiffBasedSubStorageConfiguration());
dataStorageOptions.pathBasedExtraStorageOptions =
PathBasedExtraStorageOptions.fromConfig(
domainObject.getPathBasedExtraStorageConfiguration());
return dataStorageOptions;
}
@@ -99,14 +100,14 @@ public class DataStorageOptions implements CLIOptions<DataStorageConfiguration>
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(dataStorageFormat)
.receiptCompactionEnabled(receiptCompactionEnabled)
.diffBasedSubStorageConfiguration(diffBasedSubStorageOptions.toDomainObject());
.pathBasedExtraStorageConfiguration(pathBasedExtraStorageOptions.toDomainObject());
return builder.build();
}
@Override
public List<String> getCLIOptions() {
final List<String> cliOptions = CommandLineUtils.getCLIOptions(this, new DataStorageOptions());
cliOptions.addAll(diffBasedSubStorageOptions.getCLIOptions());
cliOptions.addAll(pathBasedExtraStorageOptions.getCLIOptions());
return cliOptions;
}

View File

@@ -14,17 +14,17 @@
*/
package org.hyperledger.besu.cli.options.storage;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_LIMIT_TRIE_LOGS_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DiffBasedUnstable.DEFAULT_CODE_USING_CODE_HASH_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.DiffBasedUnstable.DEFAULT_FULL_FLAT_DB_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.DEFAULT_LIMIT_TRIE_LOGS_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.DEFAULT_MAX_LAYERS_TO_LOAD;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.MINIMUM_TRIE_LOG_RETENTION_LIMIT;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.PathBasedUnstable.DEFAULT_CODE_USING_CODE_HASH_ENABLED;
import static org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration.PathBasedUnstable.DEFAULT_FULL_FLAT_DB_ENABLED;
import org.hyperledger.besu.cli.options.CLIOptions;
import org.hyperledger.besu.cli.util.CommandLineUtils;
import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutablePathBasedExtraStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.PathBasedExtraStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import java.util.List;
@@ -33,7 +33,8 @@ import picocli.CommandLine;
import picocli.CommandLine.Option;
/** The Data storage CLI options. */
public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorageConfiguration> {
public class PathBasedExtraStorageOptions
implements CLIOptions<PathBasedExtraStorageConfiguration> {
/** The maximum number of historical layers to load. */
public static final String MAX_LAYERS_TO_LOAD = "--bonsai-historical-block-limit";
@@ -80,10 +81,10 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
private Integer trieLogPruningWindowSize = DEFAULT_TRIE_LOG_PRUNING_WINDOW_SIZE;
@CommandLine.ArgGroup(validate = false)
private final DiffBasedSubStorageOptions.Unstable unstableOptions = new Unstable();
private final PathBasedExtraStorageOptions.Unstable unstableOptions = new Unstable();
/** Default Constructor. */
DiffBasedSubStorageOptions() {}
PathBasedExtraStorageOptions() {}
/** The unstable options for data storage. */
public static class Unstable {
@@ -125,8 +126,8 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
*
* @return the data storage options
*/
public static DiffBasedSubStorageOptions create() {
return new DiffBasedSubStorageOptions();
public static PathBasedExtraStorageOptions create() {
return new PathBasedExtraStorageOptions();
}
/**
@@ -168,7 +169,7 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
if (unstableOptions.isParallelTxProcessingEnabled) {
throw new CommandLine.ParameterException(
commandLine,
"Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai.");
"Transaction parallelization is not supported unless operating in a 'pathbased' mode, such as Bonsai.");
}
}
}
@@ -179,9 +180,9 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
* @param domainObject to be reversed
* @return the options that correspond to the configuration
*/
public static DiffBasedSubStorageOptions fromConfig(
final DiffBasedSubStorageConfiguration domainObject) {
final DiffBasedSubStorageOptions dataStorageOptions = DiffBasedSubStorageOptions.create();
public static PathBasedExtraStorageOptions fromConfig(
final PathBasedExtraStorageConfiguration domainObject) {
final PathBasedExtraStorageOptions dataStorageOptions = PathBasedExtraStorageOptions.create();
dataStorageOptions.maxLayersToLoad = domainObject.getMaxLayersToLoad();
dataStorageOptions.limitTrieLogsEnabled = domainObject.getLimitTrieLogsEnabled();
dataStorageOptions.trieLogPruningWindowSize = domainObject.getTrieLogPruningWindowSize();
@@ -196,13 +197,13 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
}
@Override
public final DiffBasedSubStorageConfiguration toDomainObject() {
return ImmutableDiffBasedSubStorageConfiguration.builder()
public final PathBasedExtraStorageConfiguration toDomainObject() {
return ImmutablePathBasedExtraStorageConfiguration.builder()
.maxLayersToLoad(maxLayersToLoad)
.limitTrieLogsEnabled(limitTrieLogsEnabled)
.trieLogPruningWindowSize(trieLogPruningWindowSize)
.unstable(
ImmutableDiffBasedSubStorageConfiguration.DiffBasedUnstable.builder()
ImmutablePathBasedExtraStorageConfiguration.PathBasedUnstable.builder()
.fullFlatDbEnabled(unstableOptions.fullFlatDbEnabled)
.codeStoredByCodeHashEnabled(unstableOptions.codeUsingCodeHashEnabled)
.isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled)
@@ -212,6 +213,6 @@ public class DiffBasedSubStorageOptions implements CLIOptions<DiffBasedSubStorag
@Override
public List<String> getCLIOptions() {
return CommandLineUtils.getCLIOptions(this, new DiffBasedSubStorageOptions());
return CommandLineUtils.getCLIOptions(this, new PathBasedExtraStorageOptions());
}
}

View File

@@ -19,5 +19,7 @@ public enum BlockImportFormat {
/** RLP block import format. */
RLP,
/** Json block import format. */
JSON
JSON,
/** Era1 block import format. */
ERA1,
}

Some files were not shown because too many files have changed in this diff Show More