EvmTool - A CLI for ad hoc performance and fuzz testing (#786)

A standalone CLI that performs EVM execution with provided genesis
files and raw EVM bytecodes.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/812/head
Danno Ferrin 5 years ago committed by GitHub
parent 0cf6bd9aad
commit 912d125117
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .gitignore
  2. 73
      build.gradle
  3. 1
      config/build.gradle
  4. 1
      consensus/common/build.gradle
  5. 62
      ethereum/evmtool/build.gradle
  6. 73
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java
  7. 44
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CliqueGenesisFileModule.java
  8. 41
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/DataStoreModule.java
  9. 35
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmTool.java
  10. 285
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  11. 42
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommandOptionsModule.java
  12. 44
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolComponent.java
  13. 114
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/GenesisFileModule.java
  14. 43
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/IBFTGenesisFileModule.java
  15. 27
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/InMemoryDataStoreModule.java
  16. 43
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java
  17. 32
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MetricsSystemModule.java
  18. 29
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrometheusMetricsSystemModule.java
  19. 34
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/ProtocolModule.java
  20. 4
      gradle/versions.gradle
  21. 1
      plugin-api/build.gradle
  22. 9
      settings.gradle

1
.gitignore vendored

@ -28,3 +28,4 @@ out/
site/ site/
/kubernetes/reports/ /kubernetes/reports/
/kubernetes/besu-*.tar.gz /kubernetes/besu-*.tar.gz
**/src/*/generated

@ -294,6 +294,7 @@ check.dependsOn('checkPluginAPIChanges', 'checkMavenCoordinateCollisions')
subprojects { subprojects {
if (file('src/test-support').directory) {
sourceSets { sourceSets {
// test-support can be consumed as a library by other projects in their tests // test-support can be consumed as a library by other projects in their tests
testSupport { testSupport {
@ -304,6 +305,21 @@ subprojects {
} }
resources.srcDir file('src/test-support/resources') resources.srcDir file('src/test-support/resources')
} }
}
dependencies {
testImplementation sourceSets.testSupport.output
}
task testSupportJar(type: Jar) {
archiveBaseName = "${project.name}-support-test"
classifier = 'test-support'
from sourceSets.testSupport.output
}
}
if (file('src/integration-test').directory) {
sourceSets {
integrationTest { integrationTest {
java { java {
compileClasspath += main.output compileClasspath += main.output
@ -314,10 +330,26 @@ subprojects {
} }
} }
task testSupportJar(type: Jar) { if (file('src/test-support').directory) {
archiveBaseName = "${project.name}-support-test" dependencies {
classifier = 'test-support' integrationTestImplementation sourceSets.testSupport.output
from sourceSets.testSupport.output }
}
task integrationTest(type: Test, dependsOn: ["compileTestJava"]) {
group = "verification"
description = "Runs the Besu integration tests"
jvmArgs = [
'--add-opens',
'java.base/java.util=ALL-UNNAMED',
'--add-opens',
'java.base/java.util.concurrent=ALL-UNNAMED'
]
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
outputs.upToDateWhen { false }
}
} }
def sourceSetIsPopulated = { sourceSetName -> def sourceSetIsPopulated = { sourceSetName ->
@ -397,27 +429,6 @@ subprojects {
testSupportArtifacts testSupportArtifacts
} }
dependencies {
testImplementation sourceSets.testSupport.output
integrationTestImplementation sourceSets.testSupport.output
}
task integrationTest(type: Test, dependsOn: ["compileTestJava"]) {
group = "verification"
description = "Runs the Besu integration tests"
jvmArgs = [
'--add-opens',
'java.base/java.util=ALL-UNNAMED',
'--add-opens',
'java.base/java.util.concurrent=ALL-UNNAMED'
]
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
outputs.upToDateWhen { false }
}
if (file('src/jmh').directory) { if (file('src/jmh').directory) {
apply plugin: 'me.champeau.gradle.jmh' apply plugin: 'me.champeau.gradle.jmh'
@ -605,7 +616,17 @@ task checkSpdxHeader(type: CheckSpdxHeader) {
rootPath = "${projectDir}" rootPath = "${projectDir}"
spdxHeader = "* SPDX-License-Identifier: Apache-2.0" spdxHeader = "* SPDX-License-Identifier: Apache-2.0"
filesRegex = "(.*.java)|(.*.groovy)" filesRegex = "(.*.java)|(.*.groovy)"
excludeRegex = "(.*generalstate/GeneralStateRegressionReferenceTest.*)|(.*generalstate/GeneralStateReferenceTest.*)|(.*blockchain/BlockchainReferenceTest.*)|(.*.gradle/.*)|(.*.idea/.*)" excludeRegex = [
"(.*/generalstate/GeneralStateRegressionReferenceTest.*)",
"(.*/generalstate/GeneralStateReferenceTest.*)",
"(.*/blockchain/BlockchainReferenceTest.*)",
"(.*/.gradle/.*)",
"(.*/.idea/.*)",
"(.*/out/.*)",
"(.*/build/.*)",
"(.*/src/main/generated/.*)",
].join("|")
} }
task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) { task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) {

@ -42,4 +42,3 @@ dependencies {
} }
configurations { testArtifacts } configurations { testArtifacts }
artifacts { testSupportArtifacts testSupportJar }

@ -54,5 +54,4 @@ task testJar (type: Jar) {
artifacts { artifacts {
testArtifacts testJar testArtifacts testJar
testSupportArtifacts testSupportJar
} }

@ -0,0 +1,62 @@
/*
* 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
*
*/
apply plugin: 'java-library'
apply plugin: 'application'
apply plugin: 'idea'
jar {
baseName 'besu-evmtool'
manifest {
attributes(
'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
}
}
dependencies {
implementation project(':besu')
implementation project(':config')
implementation project(':crypto')
implementation project(':consensus:clique')
implementation project(':consensus:ibft')
implementation project(':ethereum:core')
implementation project(':metrics:core')
implementation project(':services:kvstore')
implementation project(':util')
implementation 'com.google.dagger:dagger'
implementation 'com.google.guava:guava'
implementation 'info.picocli:picocli'
implementation 'io.vertx:vertx-core'
implementation 'org.apache.logging.log4j:log4j-api'
implementation 'org.apache.logging.log4j:log4j-core'
annotationProcessor 'com.google.dagger:dagger-compiler'
}
mainClassName = 'org.hyperledger.besu.evmtool.EvmTool'
startScripts {
applicationName = 'evm'
doLast {
unixScript.text = unixScript.text.replace('BESU_HOME', '\$APP_HOME')
windowsScript.text = windowsScript.text.replace('BESU_HOME', '%~dp0..')
}
}

@ -0,0 +1,73 @@
/*
* 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.evmtool;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.BlockchainStorage;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.MutableWorldView;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@SuppressWarnings("WeakerAccess")
@Module(includes = {GenesisFileModule.class, DataStoreModule.class})
public class BlockchainModule {
@Singleton
@Provides
Blockchain provideBlockchain(
@Named("GenesisBlock") final Block genesisBlock,
final BlockchainStorage blockchainStorage,
final MetricsSystem metricsSystem) {
return DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem);
}
@Provides
MutableWorldView getMutableWorldView(
final WorldStateStorage worldStateStorage,
final WorldStatePreimageStorage worldStatePreimageStorage) {
return new DefaultMutableWorldState(worldStateStorage, worldStatePreimageStorage);
}
@Provides
WorldStateStorage provideWorldStateStorage(final KeyValueStorage keyValueStorage) {
return new WorldStateKeyValueStorage(keyValueStorage);
}
@Provides
WorldStatePreimageStorage provideWorldStatePreimageStorage(
final KeyValueStorage keyValueStorage) {
return new WorldStatePreimageKeyValueStorage(keyValueStorage);
}
@Provides
WorldUpdater provideWorldUpdater(final MutableWorldView mutableWorldView) {
return mutableWorldView.updater();
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2018 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.evmtool;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.consensus.clique.CliqueProtocolSchedule;
import org.hyperledger.besu.consensus.ibft.IbftBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import javax.inject.Named;
class CliqueGenesisFileModule extends GenesisFileModule {
CliqueGenesisFileModule(final String genesisConfig) {
super(genesisConfig);
}
@Override
ProtocolSchedule<?> provideProtocolSchedule(
final GenesisConfigOptions configOptions,
@Named("RevertReasonEnabled") final boolean revertReasonEnabled) {
// dagger can handle this magic one day
return CliqueProtocolSchedule.create(configOptions, null, revertReasonEnabled);
}
@Override
BlockHeaderFunctions blockHashFunction() {
return IbftBlockHeaderFunctions.forOnChainBlock();
}
}

@ -0,0 +1,41 @@
/*
* 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.evmtool;
import org.hyperledger.besu.ethereum.chain.BlockchainStorage;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import dagger.Module;
import dagger.Provides;
@SuppressWarnings("WeakerAccess")
@Module(includes = GenesisFileModule.class)
public class DataStoreModule {
@Provides
@SuppressWarnings("CloseableProvides")
KeyValueStorage provideKeyValueStorage() {
throw new RuntimeException("Abstract");
}
@Provides
static BlockchainStorage provideBlockchainStorage(
final KeyValueStorage keyValueStorage, final BlockHeaderFunctions blockHashFunction) {
return new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHashFunction);
}
}

@ -0,0 +1,35 @@
/*
* 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.evmtool;
import static picocli.CommandLine.defaultExceptionHandler;
import picocli.CommandLine;
public final class EvmTool {
private static final int SUCCESS_EXIT_CODE = 0;
private static final int ERROR_EXIT_CODE = 1;
public static void main(final String... args) {
final EvmToolCommand evmToolCommand = new EvmToolCommand();
evmToolCommand.parse(
new CommandLine.RunLast().andExit(SUCCESS_EXIT_CODE),
defaultExceptionHandler().andExit(ERROR_EXIT_CODE),
args);
}
}

@ -0,0 +1,285 @@
/*
* 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.evmtool;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.LogsBloomFilter;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.Code;
import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.ehalt.ExceptionalHaltException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.List;
import com.google.common.base.Stopwatch;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(
description = "This command evaluates EVM transactions.",
abbreviateSynopsis = true,
name = "evm",
mixinStandardHelpOptions = true,
sortOptions = false,
header = "Usage:",
synopsisHeading = "%n",
descriptionHeading = "%nDescription:%n%n",
optionListHeading = "%nOptions:%n",
footerHeading = "%n",
footer = "Hyperledger Besu is licensed under the Apache License 2.0")
public class EvmToolCommand implements Runnable {
private static final Logger LOG = LogManager.getLogger();
@Option(
names = {"--code"},
paramLabel = "<code>",
description = "code to be executed")
private final Bytes codeHexString = Bytes.EMPTY;
@Option(
names = {"--gas"},
paramLabel = "<int>")
private final Gas gas = Gas.of(10_000_000_000L);
@Option(
names = {"--price"},
paramLabel = "<int>")
private final Wei gasPriceGWei = Wei.ZERO;
@Option(
names = {"--sender"},
paramLabel = "<address>",
description = "address of ORIGIN")
private final Address sender = Address.fromHexString("0x00");
@Option(
names = {"--receiver"},
paramLabel = "<address>",
description = "address of ADDRESS")
private final Address receiver = Address.fromHexString("0x00");
@Option(
names = {"--input"},
paramLabel = "<code>",
description = "CALLDATA")
private final Bytes callData = Bytes.EMPTY;
@Option(
names = {"--value"},
paramLabel = "<int>")
private final Wei ethValue = Wei.ZERO;
@Option(
names = {"--json"},
description = "output json output for each opcode")
private final Boolean showJsonResults = false;
@Option(
names = {"--nomemory"},
description = "disable showing the full memory output for each op")
private final Boolean showMemory = true;
@Option(
names = {"--prestate", "--genesis"},
description = "a chain specification, the same one that the client normally would use")
private final File genesisFile = null;
@Option(
names = {"--chain"},
description = "Name of a well know chain")
private final NetworkName network = null;
@Option(
names = {"--repeat"},
description = "Number of times to repeat before gathering timing")
private final Integer repeat = 0;
private final EvmToolCommandOptionsModule daggerOptions = new EvmToolCommandOptionsModule();
void parse(
final CommandLine.AbstractParseResultHandler<List<Object>> resultHandler,
final CommandLine.DefaultExceptionHandler<List<Object>> exceptionHandler,
final String[] args) {
final CommandLine commandLine = new CommandLine(this);
commandLine.addMixin("Dagger Options", daggerOptions);
// add sub commands here
commandLine.registerConverter(Address.class, Address::fromHexString);
commandLine.registerConverter(Bytes.class, Bytes::fromHexString);
commandLine.registerConverter(Gas.class, (arg) -> Gas.of(Long.parseUnsignedLong(arg)));
commandLine.registerConverter(Wei.class, (arg) -> Wei.of(Long.parseUnsignedLong(arg)));
commandLine.parseWithHandlers(resultHandler, exceptionHandler, args);
}
@Override
public void run() {
try {
final EvmToolComponent component =
DaggerEvmToolComponent.builder()
.dataStoreModule(new InMemoryDataStoreModule())
.genesisFileModule(
network == null
? genesisFile == null
? GenesisFileModule.createGenesisModule(NetworkName.DEV)
: GenesisFileModule.createGenesisModule(genesisFile)
: GenesisFileModule.createGenesisModule(network))
.evmToolCommandOptionsModule(daggerOptions)
.metricsSystemModule(new PrometheusMetricsSystemModule())
.build();
final BlockHeader blockHeader =
BlockHeaderBuilder.create()
.parentHash(Hash.EMPTY)
.coinbase(Address.ZERO)
.difficulty(Difficulty.ONE)
.number(1)
.gasLimit(5000)
.timestamp(Instant.now().toEpochMilli())
.ommersHash(Hash.EMPTY_LIST_HASH)
.stateRoot(Hash.EMPTY_TRIE_HASH)
.transactionsRoot(Hash.EMPTY)
.receiptsRoot(Hash.EMPTY)
.logsBloom(LogsBloomFilter.empty())
.gasUsed(0)
.extraData(Bytes.EMPTY)
.mixHash(Hash.EMPTY)
.nonce(0)
.blockHeaderFunctions(new MainnetBlockHeaderFunctions())
.buildBlockHeader();
Configurator.setAllLevels("", repeat == 0 ? Level.INFO : Level.OFF);
int repeat = this.repeat;
do {
final boolean lastLoop = repeat == 0;
final MessageFrame messageFrame =
MessageFrame.builder()
.type(MessageFrame.Type.MESSAGE_CALL)
.messageFrameStack(new ArrayDeque<>())
.blockchain(component.getBlockchain())
.worldState(component.getWorldUpdater())
.initialGas(gas)
.contract(Address.ZERO)
.address(receiver)
.originator(sender)
.gasPrice(gasPriceGWei)
.inputData(callData)
.sender(Address.ZERO)
.value(ethValue)
.apparentValue(ethValue)
.code(new Code(codeHexString))
.blockHeader(blockHeader)
.depth(0)
.completer(c -> {})
.miningBeneficiary(blockHeader.getCoinbase())
.blockHashLookup(new BlockHashLookup(blockHeader, component.getBlockchain()))
.contractAccountVersion(Account.DEFAULT_VERSION)
.build();
messageFrame.setState(MessageFrame.State.CODE_EXECUTING);
final EVM evm = component.getEvmAtBlock().apply(0);
final Stopwatch stopwatch = Stopwatch.createStarted();
evm.runToHalt(
messageFrame,
(frame, currentGasCost, executeOperation) -> {
if (showJsonResults && lastLoop) {
System.out.println(createEvmTraceOperation(messageFrame));
}
executeOperation.execute();
});
stopwatch.stop();
if (lastLoop) {
System.out.println(
new JsonObject()
.put(
"gasUser",
gas.minus(messageFrame.getRemainingGas()).asUInt256().toShortHexString())
.put("timens", stopwatch.elapsed().toNanos())
.put("time", stopwatch.elapsed().toNanos() / 1000));
}
} while (repeat-- > 0);
} catch (final IOException | ExceptionalHaltException e) {
LOG.fatal(e);
}
}
private JsonObject createEvmTraceOperation(final MessageFrame messageFrame) {
final JsonArray stack = new JsonArray();
for (int i = 0; i < messageFrame.stackSize(); i++) {
stack.add(messageFrame.getStackItem(i).toShortHexString());
}
final String error =
messageFrame.getExceptionalHaltReasons().stream()
.findFirst()
.map(ExceptionalHaltReason::getDescription)
.orElse(
messageFrame
.getRevertReason()
.map(bytes -> new String(bytes.toArrayUnsafe(), StandardCharsets.UTF_8))
.orElse(""));
final JsonObject results = new JsonObject();
results.put("pc", messageFrame.getPC());
results.put("op", messageFrame.getCurrentOperation().getOpcode());
results.put("gas", messageFrame.getRemainingGas().asUInt256().toShortHexString());
results.put(
"gasCost",
messageFrame.getCurrentOperation().cost(messageFrame).asUInt256().toShortHexString());
if (!showMemory) {
results.put(
"memory",
messageFrame.readMemory(UInt256.ZERO, messageFrame.memoryWordSize()).toHexString());
}
results.put("memSize", messageFrame.memoryByteSize());
results.put("depth", messageFrame.getMessageStackDepth() + 1);
results.put("stack", stack);
results.put("error", error);
results.put("opName", messageFrame.getCurrentOperation().getName());
return results;
}
}

@ -0,0 +1,42 @@
/*
* 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.evmtool;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
import picocli.CommandLine.Option;
@SuppressWarnings("WeakerAccess")
@Module
public class EvmToolCommandOptionsModule {
@Option(
names = {"--revert-reason-enabled"},
paramLabel = "<Boolean>",
description = "Should revert reasons be persisted. (default: ${FALLBACK-VALUE})",
arity = "0..1",
fallbackValue = "true")
final Boolean revertReasonEnabled = true;
@Provides
@Named("RevertReasonEnabled")
boolean isRevertReasonEnabled() {
return revertReasonEnabled;
}
}

@ -0,0 +1,44 @@
/*
* 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.evmtool;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.vm.EVM;
import java.util.function.Function;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(
modules = {
ProtocolModule.class,
GenesisFileModule.class,
DataStoreModule.class,
BlockchainModule.class,
EvmToolCommandOptionsModule.class,
MetricsSystemModule.class,
})
public interface EvmToolComponent {
Function<Integer, EVM> getEvmAtBlock();
WorldUpdater getWorldUpdater();
Blockchain getBlockchain();
}

@ -0,0 +1,114 @@
/*
* 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.evmtool;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.cli.config.NetworkName;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.ethereum.chain.GenesisState;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import io.vertx.core.json.JsonObject;
@Module
public class GenesisFileModule {
private final String genesisConfig;
protected GenesisFileModule(final File genesisFile) throws IOException {
this.genesisConfig = Files.readString(genesisFile.toPath(), Charset.defaultCharset());
}
protected GenesisFileModule(final String genesisConfig) {
this.genesisConfig = genesisConfig;
}
@Singleton
@Provides
GenesisConfigFile providesGenesisConfigFile() {
return GenesisConfigFile.fromConfig(genesisConfig);
}
@Singleton
@Provides
GenesisConfigOptions provideGenesisConfigOptions(final GenesisConfigFile genesisConfigFile) {
return genesisConfigFile.getConfigOptions();
}
@Singleton
@Provides
ProtocolSchedule<?> provideProtocolSchedule(
final GenesisConfigOptions configOptions,
@Named("RevertReasonEnabled") final boolean revertReasonEnabled) {
throw new RuntimeException("Abstract");
}
@Singleton
@Provides
GenesisState provideGenesisState(
final GenesisConfigFile genesisConfigFile, final ProtocolSchedule<?> protocolSchedule) {
return GenesisState.fromConfig(genesisConfigFile, protocolSchedule);
}
@Singleton
@Provides
BlockHeaderFunctions blockHashFunction() {
throw new RuntimeException("Abstract");
}
@Singleton
@Provides
@Named("GenesisBlock")
Block provideGenesisBlock(final GenesisState genesisState) {
return genesisState.getBlock();
}
static GenesisFileModule createGenesisModule(final NetworkName networkName) {
return createGenesisModule(EthNetworkConfig.jsonConfig(networkName));
}
static GenesisFileModule createGenesisModule(final File genesisFile) throws IOException {
return createGenesisModule(Files.readString(genesisFile.toPath(), Charset.defaultCharset()));
}
private static GenesisFileModule createGenesisModule(final String genesisConfig) {
// duplicating work from JsonGenesisConfigOptions, but in a refactoring this goes away.
final JsonObject genesis = new JsonObject(genesisConfig);
final JsonObject config = genesis.getJsonObject("config");
if (config.containsKey("ethash")) {
return new MainnetGenesisFileModule(genesisConfig);
} else if (config.containsKey("ibft")) {
return new IBFTGenesisFileModule(genesisConfig);
} else if (config.containsKey("clique")) {
return new CliqueGenesisFileModule(genesisConfig);
} else {
// default is mainnet
return new MainnetGenesisFileModule(genesisConfig);
}
}
}

@ -0,0 +1,43 @@
/*
* 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.evmtool;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.consensus.ibft.IbftBlockHeaderFunctions;
import org.hyperledger.besu.consensus.ibft.IbftProtocolSchedule;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import javax.inject.Named;
class IBFTGenesisFileModule extends GenesisFileModule {
IBFTGenesisFileModule(final String genesisConfig) {
super(genesisConfig);
}
@Override
ProtocolSchedule<?> provideProtocolSchedule(
final GenesisConfigOptions configOptions,
@Named("RevertReasonEnabled") final boolean revertReasonEnabled) {
return IbftProtocolSchedule.create(configOptions);
}
@Override
BlockHeaderFunctions blockHashFunction() {
return IbftBlockHeaderFunctions.forOnChainBlock();
}
}

@ -0,0 +1,27 @@
/*
* 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.evmtool;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
class InMemoryDataStoreModule extends DataStoreModule {
@Override
KeyValueStorage provideKeyValueStorage() {
return new InMemoryKeyValueStorage();
}
}

@ -0,0 +1,43 @@
/*
* 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.evmtool;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import javax.inject.Named;
class MainnetGenesisFileModule extends GenesisFileModule {
MainnetGenesisFileModule(final String genesisConfig) {
super(genesisConfig);
}
@Override
ProtocolSchedule<?> provideProtocolSchedule(
final GenesisConfigOptions configOptions,
@Named("RevertReasonEnabled") final boolean revertReasonEnabled) {
return MainnetProtocolSchedule.fromConfig(configOptions);
}
@Override
BlockHeaderFunctions blockHashFunction() {
return new MainnetBlockHeaderFunctions();
}
}

@ -0,0 +1,32 @@
/*
* 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.evmtool;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import dagger.Module;
import dagger.Provides;
@SuppressWarnings("WeakerAccess")
@Module
public class MetricsSystemModule {
@Provides
MetricsSystem getMetricsSystem() {
throw new RuntimeException("Abstract");
}
}

@ -0,0 +1,29 @@
/*
* 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.evmtool;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.metrics.prometheus.PrometheusMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem;
public class PrometheusMetricsSystemModule extends MetricsSystemModule {
@Override
public MetricsSystem getMetricsSystem() {
return PrometheusMetricsSystem.init(MetricsConfiguration.builder().build());
}
}

@ -0,0 +1,34 @@
/*
* 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.evmtool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.vm.EVM;
import java.util.function.Function;
import dagger.Module;
import dagger.Provides;
@SuppressWarnings("WeakerAccess")
@Module(includes = GenesisFileModule.class)
public class ProtocolModule {
@Provides
Function<Integer, EVM> provideEvmAtBlock(final ProtocolSchedule<?> protocolSchedule) {
return blockNum -> protocolSchedule.getByBlockNumber(blockNum).getEvm();
}
}

@ -17,10 +17,14 @@ dependencyManagement {
dependencies { dependencies {
dependency 'com.fasterxml.jackson.core:jackson-databind:2.10.1' dependency 'com.fasterxml.jackson.core:jackson-databind:2.10.1'
dependency 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.1' dependency 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.1'
dependency 'com.github.tomakehurst:wiremock-jre8:2.25.1' dependency 'com.github.tomakehurst:wiremock-jre8:2.25.1'
dependency 'com.google.auto.service:auto-service:1.0-rc6' dependency 'com.google.auto.service:auto-service:1.0-rc6'
dependency 'com.google.dagger:dagger:2.27'
dependency 'com.google.dagger:dagger-compiler:2.27'
dependency 'com.google.errorprone:error_prone_annotation:2.3.3' dependency 'com.google.errorprone:error_prone_annotation:2.3.3'
dependency 'com.google.errorprone:error_prone_check_api:2.3.3' dependency 'com.google.errorprone:error_prone_check_api:2.3.3'
dependency 'com.google.errorprone:error_prone_core:2.3.3' dependency 'com.google.errorprone:error_prone_core:2.3.3'

@ -32,7 +32,6 @@ dependencies {
} }
configurations { testArtifacts } configurations { testArtifacts }
artifacts { testSupportArtifacts testSupportJar }
class FileStateChecker extends DefaultTask { class FileStateChecker extends DefaultTask {

@ -16,6 +16,7 @@
rootProject.name='besu' rootProject.name='besu'
include 'acceptance-tests:dsl' include 'acceptance-tests:dsl'
include 'acceptance-tests:tests' include 'acceptance-tests:tests'
include 'besu'
include 'config' include 'config'
include 'consensus:clique' include 'consensus:clique'
include 'consensus:common' include 'consensus:common'
@ -24,27 +25,27 @@ include 'consensus:ibftlegacy'
include 'crypto' include 'crypto'
include 'enclave' include 'enclave'
include 'errorprone-checks' include 'errorprone-checks'
include 'ethereum:api'
include 'ethereum:blockcreation' include 'ethereum:blockcreation'
include 'ethereum:core' include 'ethereum:core'
include 'ethereum:eth' include 'ethereum:eth'
include 'ethereum:api' include 'ethereum:evmtool'
include 'ethereum:mock-p2p' include 'ethereum:mock-p2p'
include 'ethereum:p2p' include 'ethereum:p2p'
include 'ethereum:permissioning' include 'ethereum:permissioning'
include 'ethereum:referencetests' include 'ethereum:referencetests'
include 'ethereum:retesteth' include 'ethereum:retesteth'
include 'ethereum:rlp' include 'ethereum:rlp'
include 'ethereum:trie'
include 'ethereum:stratum' include 'ethereum:stratum'
include 'ethereum:trie'
include 'metrics:core' include 'metrics:core'
include 'metrics:rocksdb' include 'metrics:rocksdb'
include 'nat' include 'nat'
include 'besu'
include 'plugin-api' include 'plugin-api'
include 'plugins:rocksdb' include 'plugins:rocksdb'
include 'privacy-contracts'
include 'services:kvstore' include 'services:kvstore'
include 'services:pipeline' include 'services:pipeline'
include 'services:tasks' include 'services:tasks'
include 'testutil' include 'testutil'
include 'util' include 'util'
include 'privacy-contracts'

Loading…
Cancel
Save