Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
### Additions and Improvements
- Improve transaction simulation and gas estimation when no gas pricing is present [#8888](https://github.com/hyperledger/besu/pull/8888)
- Add option to trace reference tests during execution [#8878](https://github.com/hyperledger/besu/pull/8878)
- Expose methods to query hardfork by block header or for the next block in the Plugin API [#8909](https://github.com/hyperledger/besu/pull/8909)

#### Fusaka devnets
- EIP-7910 - `eth_config` JSON-RPC Method [#8417](https://github.com/hyperledger/besu/pull/8417)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,19 @@
import org.hyperledger.besu.tests.acceptance.dsl.transaction.web3.Web3Transactions;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.apache.logging.log4j.ThreadContext;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -193,6 +199,21 @@ protected void waitForBlockHeight(final Node node, final long blockchainHeight)
.isGreaterThanOrEqualTo(BigInteger.valueOf(blockchainHeight)));
}

protected void waitForFile(final Path path) {
final File file = path.toFile();
Awaitility.waitAtMost(30, TimeUnit.SECONDS)
.until(
() -> {
if (file.exists()) {
try (final Stream<String> s = Files.lines(path)) {
return s.count() > 0;
}
} else {
return false;
}
});
}

@Test
public void dryRunDetector() {
assertThat(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,21 @@ public BesuNode createPluginsNode(
.build());
}

public BesuNode createPluginsNode(
final String name,
final List<String> plugins,
final UnaryOperator<BesuNodeConfigurationBuilder> configBuilder)
throws IOException {

BesuNodeConfigurationBuilder builder =
new BesuNodeConfigurationBuilder()
.name(name)
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.plugins(plugins);

return create(configBuilder.apply(builder).build());
}

public BesuNode createArchiveNodeWithRpcApis(final String name, final String... enabledRpcApis)
throws IOException {
final JsonRpcConfiguration jsonRpcConfig = node.createJsonRpcEnabledConfig();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* 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.plugins;

import static java.nio.charset.StandardCharsets.UTF_8;

import org.hyperledger.besu.datatypes.HardforkId;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.ServiceManager;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.plugin.services.BlockchainService;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import com.google.auto.service.AutoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@AutoService(BesuPlugin.class)
public class TestBlockchainServicePlugin implements BesuPlugin {
private static final Logger LOG = LoggerFactory.getLogger(TestBlockchainServicePlugin.class);
private final List<HardforkSeen> seenHardforks = new ArrayList<>();
private ServiceManager serviceManager;
private File callbackDir;

@Override
public void register(final ServiceManager serviceManager) {
LOG.info("Registering TestBlockchainServicePlugin");
this.serviceManager = serviceManager;
callbackDir = new File(System.getProperty("besu.plugins.dir", "plugins"));
}

@Override
public void start() {
LOG.info("Starting TestBlockchainServicePlugin");
final var blockchainService = serviceManager.getService(BlockchainService.class).orElseThrow();

serviceManager
.getService(BesuEvents.class)
.orElseThrow()
.addBlockAddedListener(
addedBlockContext -> {
LOG.info("Block added: {}", addedBlockContext);
final var hardforkSeen =
queryHardfork(blockchainService, addedBlockContext.getBlockHeader());
seenHardforks.add(
queryHardfork(blockchainService, addedBlockContext.getBlockHeader()));
if (hardforkSeen.current.equals(HardforkId.MainnetHardforkId.LONDON)) {
LOG.info("Writing seen hardforks: {}", seenHardforks);
writeSeenHardforks();
}
});

seenHardforks.add(queryHardfork(blockchainService, blockchainService.getChainHeadHeader()));
}

private HardforkSeen queryHardfork(
final BlockchainService blockchainService, final BlockHeader header) {
final var currentHardfork = blockchainService.getHardforkId(header);
final var nextHardfork =
blockchainService.getNextBlockHardforkId(header, header.getTimestamp() + 1);

return new HardforkSeen(header.getNumber(), currentHardfork, nextHardfork);
}

@Override
public void stop() {}

private void writeSeenHardforks() {
try {
final File callbackFile = new File(callbackDir, "hardfork.list");
if (!callbackFile.getParentFile().exists()) {
callbackFile.getParentFile().mkdirs();
callbackFile.getParentFile().deleteOnExit();
}

final var content =
seenHardforks.stream()
.map(
r ->
String.join(
",", String.valueOf(r.blockNumber), r.current.name(), r.next.name()))
.collect(Collectors.joining("\n"));

Files.write(callbackFile.toPath(), content.getBytes(UTF_8));
callbackFile.deleteOnExit();
} catch (final IOException ioe) {
throw new RuntimeException(ioe);
}
}

private record HardforkSeen(long blockNumber, HardforkId current, HardforkId next) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,9 @@
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
Expand Down Expand Up @@ -78,19 +73,4 @@ public void shouldNotStop() {
assertThat(node.homeDirectory().resolve("plugins/badCliOptions.start")).doesNotExist();
assertThat(node.homeDirectory().resolve("plugins/badCliOptions.stop")).doesNotExist();
}

private void waitForFile(final Path path) {
final File file = path.toFile();
Awaitility.waitAtMost(30, TimeUnit.SECONDS)
.until(
() -> {
if (file.exists()) {
try (final Stream<String> s = Files.lines(path)) {
return s.count() > 0;
}
} else {
return false;
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,8 @@
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand All @@ -45,19 +39,4 @@ public void setUp() throws Exception {
public void blockIsAnnounced() {
waitForFile(pluginNode.homeDirectory().resolve("plugins/newBlock.2"));
}

private void waitForFile(final Path path) {
final File file = path.toFile();
Awaitility.waitAtMost(30, TimeUnit.SECONDS)
.until(
() -> {
if (file.exists()) {
try (final Stream<String> s = Files.lines(path)) {
return s.count() > 0;
}
} else {
return false;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* 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.plugins;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

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

public class BlockchainServicePluginTest extends AcceptanceTestBase {
private BesuNode minerNode;
private BesuNode pluginNode;

@BeforeEach
public void setUp() throws Exception {
minerNode =
besu.createMinerNode(
"minerNode",
besuNodeConfigurationBuilder -> besuNodeConfigurationBuilder.devMode(false));
minerNode.setGenesisConfig(GENESIS_CONFIG);
pluginNode =
besu.createPluginsNode(
"pluginNode",
Collections.singletonList("testPlugins"),
besuNodeConfigurationBuilder -> besuNodeConfigurationBuilder.devMode(false));
pluginNode.setGenesisConfig(GENESIS_CONFIG);

cluster.start(pluginNode, minerNode);
}

@Test
public void hardforkListIsCorrect() throws IOException {
final Path hardforkListFile = pluginNode.homeDirectory().resolve("plugins/hardfork.list");
waitForFile(hardforkListFile);
final var fileContents = Files.readAllLines(hardforkListFile);

final var expectedLines = List.of("0,BERLIN,BERLIN", "1,BERLIN,LONDON", "2,LONDON,LONDON");

for (int i = 0; i < expectedLines.size(); i++) {
assertThat(fileContents.get(i)).isEqualTo(expectedLines.get(i));
}
}

private static final String GENESIS_CONFIG =
"""
{
"config": {
"chainId": 1337,
"berlinBlock": 0,
"londonBlock": 2,
"contractSizeLimit": 2147483647,
"ethash": {
"fixeddifficulty": 100
}
},
"nonce": "0x42",
"baseFeePerGas":"0x0",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1fffffffffffff",
"difficulty": "0x10000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"fe3b557e8fb62b89f4916b721be55ceb828dbd73": {
"privateKey": "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "0xad78ebc5ac6200000"
},
"627306090abaB3A6e1400e9345bC60c78a8BEf57": {
"privateKey": "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "90000000000000000000000"
},
"f17f52151EbEF6C7334FAD080c5704D77216b732": {
"privateKey": "ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f",
"comment": "private key and this comment are ignored. In a real chain, the private key should NOT be stored",
"balance": "90000000000000000000000"
}
}
}
""";
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,11 @@
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.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import org.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -75,19 +71,4 @@ public void shouldStop() {
cluster.stopNode(node);
waitForFile(node.homeDirectory().resolve("plugins/pluginLifecycle.stopped"));
}

private void waitForFile(final Path path) {
final File file = path.toFile();
Awaitility.waitAtMost(30, TimeUnit.SECONDS)
.until(
() -> {
if (file.exists()) {
try (final Stream<String> s = Files.lines(path)) {
return s.count() > 0;
}
} else {
return false;
}
});
}
}
Loading
Loading