Skip to content

Commit 1c3cb0a

Browse files
committed
Add WorldStateService to the plugin API
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
1 parent f784ebf commit 1c3cb0a

File tree

9 files changed

+239
-2
lines changed

9 files changed

+239
-2
lines changed

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
7777
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
7878
import org.hyperledger.besu.plugin.services.TransactionValidatorService;
79+
import org.hyperledger.besu.plugin.services.WorldStateService;
7980
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
8081
import org.hyperledger.besu.plugin.services.mining.MiningService;
8182
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageFactory;
@@ -97,6 +98,7 @@
9798
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
9899
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
99100
import org.hyperledger.besu.services.TransactionValidatorServiceImpl;
101+
import org.hyperledger.besu.services.WorldStateServiceImpl;
100102
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
101103

102104
import java.io.File;
@@ -275,6 +277,9 @@ private void loadAdditionalServices(
275277
new TransactionPoolServiceImpl(besuController.getTransactionPool()));
276278
besuPluginContext.addService(
277279
MiningService.class, new MiningServiceImpl(besuController.getMiningCoordinator()));
280+
besuPluginContext.addService(
281+
WorldStateService.class,
282+
new WorldStateServiceImpl(besuController.getProtocolContext().getWorldStateArchive()));
278283
}
279284

280285
private void killRunner(final String name) {

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@ public BesuNode createQbftPluginsNode(
566566
.devMode(false)
567567
.jsonRpcTxPool()
568568
.genesisConfigProvider(GenesisConfigurationFactory::createQbftLondonGenesisConfig)
569+
.dataStorageConfiguration(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)
569570
.build());
570571
}
571572

acceptance-tests/test-plugins/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ dependencies {
88
implementation project(':ethereum:core')
99
implementation project(':ethereum:rlp')
1010
implementation project(':ethereum:api')
11+
implementation project(':evm')
1112
implementation project(':plugin-api')
1213
implementation 'com.google.auto.service:auto-service'
1314
implementation 'info.picocli:picocli'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright contributors to Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.tests.acceptance.plugins;
16+
17+
import static java.nio.charset.StandardCharsets.UTF_8;
18+
19+
import org.hyperledger.besu.datatypes.Address;
20+
import org.hyperledger.besu.datatypes.Wei;
21+
import org.hyperledger.besu.plugin.BesuPlugin;
22+
import org.hyperledger.besu.plugin.ServiceManager;
23+
import org.hyperledger.besu.plugin.services.WorldStateService;
24+
25+
import java.io.File;
26+
import java.io.IOException;
27+
import java.nio.file.Files;
28+
29+
import com.google.auto.service.AutoService;
30+
import org.slf4j.Logger;
31+
import org.slf4j.LoggerFactory;
32+
33+
@AutoService(BesuPlugin.class)
34+
public class TestWorldStateServicePlugin implements BesuPlugin {
35+
private static final Logger LOG = LoggerFactory.getLogger(TestWorldStateServicePlugin.class);
36+
private ServiceManager serviceManager;
37+
private File callbackDir;
38+
39+
@Override
40+
public void register(final ServiceManager serviceManager) {
41+
LOG.info("Registering TestWorldStateServicePlugin");
42+
this.serviceManager = serviceManager;
43+
callbackDir = new File(System.getProperty("besu.plugins.dir", "plugins"));
44+
}
45+
46+
@Override
47+
public void start() {
48+
LOG.info("Starting TestWorldStateServicePlugin");
49+
50+
try {
51+
final var worldStateService =
52+
serviceManager.getService(WorldStateService.class).orElseThrow();
53+
54+
final var account =
55+
worldStateService
56+
.getWorldView()
57+
.get(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"));
58+
final var balance = account.getBalance();
59+
writeBalance(balance);
60+
} catch (Exception e) {
61+
LOG.error("Error in TestWorldStateServicePlugin", e);
62+
throw new RuntimeException(e);
63+
}
64+
}
65+
66+
@Override
67+
public void stop() {}
68+
69+
private void writeBalance(final Wei balance) {
70+
try {
71+
final File callbackFile = new File(callbackDir, "TestWorldStateServicePlugin.txt");
72+
if (!callbackFile.getParentFile().exists()) {
73+
callbackFile.getParentFile().mkdirs();
74+
callbackFile.getParentFile().deleteOnExit();
75+
}
76+
77+
final var content = balance.toHexString();
78+
79+
Files.write(callbackFile.toPath(), content.getBytes(UTF_8));
80+
callbackFile.deleteOnExit();
81+
} catch (final IOException ioe) {
82+
throw new RuntimeException(ioe);
83+
}
84+
}
85+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright contributors to Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.tests.acceptance.plugins;
16+
17+
import org.hyperledger.besu.datatypes.Address;
18+
import org.hyperledger.besu.datatypes.Wei;
19+
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
20+
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
21+
import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount;
22+
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
23+
24+
import java.io.IOException;
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.util.Collections;
28+
import java.util.List;
29+
30+
import org.junit.jupiter.api.BeforeEach;
31+
import org.junit.jupiter.api.Test;
32+
33+
public class WorldStateServicePluginTest extends AcceptanceTestBase {
34+
private BesuNode pluginNode;
35+
36+
@BeforeEach
37+
public void setUp() throws Exception {
38+
pluginNode =
39+
besu.createQbftPluginsNode(
40+
"pluginNode", Collections.singletonList("testPlugins"), List.of());
41+
42+
cluster.start(pluginNode);
43+
}
44+
45+
@Test
46+
public void balanceFromPluginIsCorrect() throws IOException {
47+
final Path resultFile =
48+
pluginNode.homeDirectory().resolve("plugins/TestWorldStateServicePlugin.txt");
49+
waitForFile(resultFile);
50+
final var fileContents = Files.readString(resultFile);
51+
final var balanceFromPlugin = Wei.fromHexString(fileContents);
52+
53+
final Account account =
54+
Account.create(
55+
ethTransactions, Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"));
56+
cluster.verify(account.balanceEquals(Amount.wei(balanceFromPlugin.getAsBigInteger())));
57+
}
58+
}

app/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
import org.hyperledger.besu.plugin.services.TransactionSelectionService;
161161
import org.hyperledger.besu.plugin.services.TransactionSimulationService;
162162
import org.hyperledger.besu.plugin.services.TransactionValidatorService;
163+
import org.hyperledger.besu.plugin.services.WorldStateService;
163164
import org.hyperledger.besu.plugin.services.exception.StorageException;
164165
import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry;
165166
import org.hyperledger.besu.plugin.services.mining.MiningService;
@@ -190,6 +191,7 @@
190191
import org.hyperledger.besu.services.TransactionSelectionServiceImpl;
191192
import org.hyperledger.besu.services.TransactionSimulationServiceImpl;
192193
import org.hyperledger.besu.services.TransactionValidatorServiceImpl;
194+
import org.hyperledger.besu.services.WorldStateServiceImpl;
193195
import org.hyperledger.besu.services.kvstore.InMemoryStoragePlugin;
194196
import org.hyperledger.besu.util.BesuVersionUtils;
195197
import org.hyperledger.besu.util.EphemeryGenesisUpdater;
@@ -1201,7 +1203,9 @@ private void startPlugins(final Runner runner) {
12011203
besuController.getProtocolContext().getBadBlockManager()));
12021204
besuPluginContext.addService(MetricsSystem.class, getMetricsSystem());
12031205

1204-
besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl);
1206+
besuPluginContext.addService(
1207+
WorldStateService.class,
1208+
new WorldStateServiceImpl(besuController.getProtocolContext().getWorldStateArchive()));
12051209

12061210
besuPluginContext.addService(
12071211
SynchronizationService.class,
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.services;
16+
17+
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
18+
import org.hyperledger.besu.evm.worldstate.WorldView;
19+
import org.hyperledger.besu.plugin.Unstable;
20+
import org.hyperledger.besu.plugin.services.WorldStateService;
21+
22+
/**
23+
* Implementation of the {@link WorldStateService} that provides access to Besu's world state.
24+
*
25+
* <p>This implementation delegates world state operations to the underlying {@link
26+
* WorldStateArchive}.
27+
*/
28+
@Unstable
29+
public class WorldStateServiceImpl implements WorldStateService {
30+
private final WorldStateArchive worldStateArchive;
31+
32+
/**
33+
* Constructs a new WorldStateServiceImpl.
34+
*
35+
* @param worldStateArchive The world state archive that provides access to world state data
36+
*/
37+
public WorldStateServiceImpl(final WorldStateArchive worldStateArchive) {
38+
this.worldStateArchive = worldStateArchive;
39+
}
40+
41+
/**
42+
* {@inheritDoc}
43+
*
44+
* <p>Returns a view of the current world state by delegating to the underlying world state
45+
* archive.
46+
*
47+
* @return A view of the current world state
48+
*/
49+
@Override
50+
public WorldView getWorldView() {
51+
return worldStateArchive.getWorldState();
52+
}
53+
}

plugin-api/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Calculated : ${currentHash}
7171
tasks.register('checkAPIChanges', FileStateChecker) {
7272
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
7373
files = sourceSets.main.allJava.files
74-
knownHash = 'K53ycFTZR4uqRPa1c5WS1HYGisvxJu65zeaGAwfQ5uw='
74+
knownHash = 'JOV0yKVExHLhhiBc5ta2oidTIjUVgBdWw4E7u/qNseM='
7575
}
7676
check.dependsOn('checkAPIChanges')
7777

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright contributors to Hyperledger Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.plugin.services;
16+
17+
import org.hyperledger.besu.evm.worldstate.WorldView;
18+
import org.hyperledger.besu.plugin.Unstable;
19+
20+
/** A service that plugin can use to access world state */
21+
@Unstable
22+
public interface WorldStateService extends BesuService {
23+
24+
/**
25+
* Returns a view of the head world state.
26+
*
27+
* @return the head world view
28+
*/
29+
WorldView getWorldView();
30+
}

0 commit comments

Comments
 (0)