mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-06 22:23:53 -05:00
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:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -17,4 +17,5 @@
|
||||
*.p12 binary
|
||||
*.db binary
|
||||
*.woff2 binary
|
||||
*.era1 binary
|
||||
goss-linux-amd64 binary
|
||||
|
||||
59
CHANGELOG.md
59
CHANGELOG.md
@@ -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)
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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": []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
|
||||
BIN
acceptance-tests/tests/src/test/resources/qbft/migration-ibft1/ibft.blocks
Executable file
BIN
acceptance-tests/tests/src/test/resources/qbft/migration-ibft1/ibft.blocks
Executable file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
0a46b91fe0c770a4355d1fec9ccd72d39264f46a74ed67a69a12ed4c265aa768
|
||||
@@ -0,0 +1 @@
|
||||
8093fb3200c783555ed487b8b5210ef3369b062a1f3ce5762d83d7a62205693d1e4f253e840ca48ec98d8f20c5b41bbbd43f34f87a1f68324ab51afe73732b96
|
||||
@@ -0,0 +1 @@
|
||||
17c2aacfdf1f6defde20e6ae7132c6d3991e758af3799a307a75b38135678a48
|
||||
@@ -0,0 +1 @@
|
||||
d81f65976ccc44c5e7e6ca859c5ede06b0f484f72c52d35dd8f7bd7581a8b7020d9ef45878696b4593daf5575b48dda5259f78f192a3445d5cc97c032660642f
|
||||
@@ -0,0 +1 @@
|
||||
917fb1b03034e5d7156b89bc2a3bc2aae1d146d2640d75e095f07110b0871bc1
|
||||
@@ -0,0 +1 @@
|
||||
67785a2ac328648d94245abb25bdcfab853d06e68c70026d90f2fd5c8338b65c19235398eac205e4bbdb3fc1de9669ad6309e43ab203c8e7430664cea6451f56
|
||||
@@ -0,0 +1 @@
|
||||
3b3cbae8c034c4ba2d5f4df44faa013888216a6eabb7fffa0b224003ea770ba7
|
||||
@@ -0,0 +1 @@
|
||||
ec403552908986b5d9e4def3be9ddcb26d5b03def3b44ef2d5d728bb9a3028603405e7379c3e185cb2bc3e784548fcdd0e7616162029c3f407155b2fb25ba0ca
|
||||
@@ -0,0 +1 @@
|
||||
4ddfb30d4fcd6f5a9f959961f734e4c1469af223bc16b217eef0d3796e64973d
|
||||
@@ -0,0 +1 @@
|
||||
28c02b375d62b0adef8213b76882dfec264d5dcbb0a8ba73f167bc718a6d02f1833af80ab9f51a5f007e5f3b8320e8fc5ab287d4bd59ad497f8949bf4abb9e80
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,4 +36,4 @@
|
||||
"number": "0x0",
|
||||
"gasUsed": "0x0",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user