diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 549275bbb6..f95c943068 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -909,7 +909,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { @Option( names = {"--target-gas-limit"}, description = - "Sets target gas limit per block. If set each blocks gas limit will approach this setting over time if the current gas limit is different.") + "Sets target gas limit per block. If set each block's gas limit will approach this setting over time if the current gas limit is different.") private final Long targetGasLimit = null; @Option( @@ -1314,13 +1314,13 @@ public class BesuCommand implements DefaultCommandValues, Runnable { if (isMiningEnabled && coinbase == null) { throw new ParameterException( this.commandLine, - "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled)" + "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) " + "or specify the beneficiary of mining (via --miner-coinbase
)"); } if (!isMiningEnabled && iStratumMiningEnabled) { throw new ParameterException( this.commandLine, - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled)" + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) " + "or specify mining is enabled (--miner-enabled)"); } } @@ -1882,6 +1882,16 @@ public class BesuCommand implements DefaultCommandValues, Runnable { throw new ParameterException( commandLine, "Please specify Enclave public key file path to enable privacy"); } + + if (Wei.ZERO.compareTo(minTransactionGasPrice) < 0) { + // if gas is required, cannot use random keys to sign private tx + // ie --privacy-marker-transaction-signing-key-file must be set + if (privacyMarkerTransactionSigningKeyPath == null) { + throw new ParameterException( + commandLine, + "Not a free gas network. --privacy-marker-transaction-signing-key-file must be specified and must be a funded account. Private transactions cannot be signed by random (non-funded) accounts in paid gas networks"); + } + } privacyParametersBuilder.setPrivacyAddress(privacyPrecompiledAddress); privacyParametersBuilder.setPrivateKeyPath(privacyMarkerTransactionSigningKeyPath); privacyParametersBuilder.setStorageProvider( diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index f256747cd5..71017afd61 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1540,9 +1540,14 @@ public class BesuCommandTest extends CommandTestAbstract { when(storageService.getByName("rocksdb-privacy")) .thenReturn(Optional.of(rocksDBSPrivacyStorageFactory)); final URL configFile = this.getClass().getResource("/orion_publickey.pub"); + final String coinbaseStr = String.format("%040x", 1); parseCommand( "--privacy-enabled", + "--miner-enabled", + "--miner-coinbase=" + coinbaseStr, + "--min-gas-price", + "0", "--privacy-url", ENCLAVE_URI, "--privacy-public-key-file", @@ -2622,7 +2627,7 @@ public class BesuCommandTest extends CommandTestAbstract { assertThat(commandOutput.toString()).isEmpty(); assertThat(commandErrorOutput.toString()) .startsWith( - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled)or specify mining is enabled (--miner-enabled)"); + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)"); } @Test @@ -2912,7 +2917,9 @@ public class BesuCommandTest extends CommandTestAbstract { "--privacy-url", ENCLAVE_URI, "--privacy-public-key-file", - configFile.getPath()); + configFile.getPath(), + "--min-gas-price", + "0"); final ArgumentCaptor enclaveArg = ArgumentCaptor.forClass(PrivacyParameters.class); @@ -2982,7 +2989,9 @@ public class BesuCommandTest extends CommandTestAbstract { "--rpc-http-authentication-enabled", "--privacy-multi-tenancy-enabled", "--rpc-http-authentication-jwt-public-key-file", - "/non/existent/file"); + "/non/existent/file", + "--min-gas-price", + "0"); final ArgumentCaptor privacyParametersArgumentCaptor = ArgumentCaptor.forClass(PrivacyParameters.class); @@ -3023,7 +3032,12 @@ public class BesuCommandTest extends CommandTestAbstract { @Test public void onChainPrivacyGroupEnabledFlagDefaultValueIsFalse() { - parseCommand("--privacy-enabled", "--privacy-public-key-file", ENCLAVE_PUBLIC_KEY_PATH); + parseCommand( + "--privacy-enabled", + "--privacy-public-key-file", + ENCLAVE_PUBLIC_KEY_PATH, + "--min-gas-price", + "0"); final ArgumentCaptor privacyParametersArgumentCaptor = ArgumentCaptor.forClass(PrivacyParameters.class); @@ -3044,7 +3058,9 @@ public class BesuCommandTest extends CommandTestAbstract { "--privacy-enabled", "--privacy-public-key-file", ENCLAVE_PUBLIC_KEY_PATH, - "--privacy-onchain-groups-enabled"); + "--privacy-onchain-groups-enabled", + "--min-gas-price", + "0"); final ArgumentCaptor privacyParametersArgumentCaptor = ArgumentCaptor.forClass(PrivacyParameters.class); @@ -3073,6 +3089,15 @@ public class BesuCommandTest extends CommandTestAbstract { .startsWith("Privacy multi-tenancy and onchain privacy groups cannot be used together"); } + @Test + public void privacyMarkerTransactionSigningKeyFileRequiredIfMinGasPriceNonZero() { + parseCommand("--privacy-enabled", "--privacy-public-key-file", ENCLAVE_PUBLIC_KEY_PATH); + + assertThat(commandErrorOutput.toString()) + .startsWith( + "Not a free gas network. --privacy-marker-transaction-signing-key-file must be specified"); + } + private Path createFakeGenesisFile(final JsonObject jsonGenesis) throws IOException { final Path genesisFile = Files.createTempFile("genesisFile", ""); Files.write(genesisFile, encodeJsonGenesis(jsonGenesis).getBytes(UTF_8));