mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
Go quorum privacy configuration (#1718)
* add goquorum privacy configuration Signed-off-by: Stefan Pingel <stefan.pingel@consensys.net>
This commit is contained in:
@@ -84,6 +84,7 @@ import org.hyperledger.besu.crypto.KeyPairUtil;
|
||||
import org.hyperledger.besu.crypto.NodeKey;
|
||||
import org.hyperledger.besu.crypto.SECP256K1;
|
||||
import org.hyperledger.besu.enclave.EnclaveFactory;
|
||||
import org.hyperledger.besu.enclave.GoQuorumEnclave;
|
||||
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
|
||||
@@ -97,6 +98,7 @@ import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.GasLimitCalculator;
|
||||
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
||||
import org.hyperledger.besu.ethereum.core.Address;
|
||||
import org.hyperledger.besu.ethereum.core.GoQuorumPrivacyParameters;
|
||||
import org.hyperledger.besu.ethereum.core.Hash;
|
||||
import org.hyperledger.besu.ethereum.core.MiningParameters;
|
||||
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
|
||||
@@ -163,6 +165,7 @@ import java.net.UnknownHostException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -181,6 +184,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.io.Resources;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.VertxOptions;
|
||||
@@ -1406,7 +1410,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
try {
|
||||
final GenesisConfigFile genesisConfigFile = GenesisConfigFile.fromConfig(genesisConfig());
|
||||
genesisConfigOptions = genesisConfigFile.getConfigOptions(genesisConfigOverrides);
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
throw new IllegalStateException("Unable to read genesis file for GoQuorum options", e);
|
||||
}
|
||||
return genesisConfigOptions;
|
||||
@@ -1502,10 +1506,53 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
.ifPresent(p -> ensureAllNodesAreInAllowlist(staticNodes, p));
|
||||
metricsConfiguration = metricsConfiguration();
|
||||
|
||||
if (isGoQuorumCompatibilityMode) {
|
||||
configureGoQuorumPrivacy();
|
||||
}
|
||||
|
||||
logger.info("Security Module: {}", securityModuleName);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void configureGoQuorumPrivacy() {
|
||||
|
||||
GoQuorumPrivacyParameters.isEnabled = true;
|
||||
|
||||
GoQuorumPrivacyParameters.goQuorumEnclave = createGoQuorumEnclave();
|
||||
|
||||
GoQuorumPrivacyParameters.enclaveKey = readEnclaveKey();
|
||||
}
|
||||
|
||||
private GoQuorumEnclave createGoQuorumEnclave() {
|
||||
final EnclaveFactory enclaveFactory = new EnclaveFactory(Vertx.vertx());
|
||||
if (privacyKeyStoreFile != null) {
|
||||
return enclaveFactory.createGoQuorumEnclave(
|
||||
privacyUrl, privacyKeyStoreFile, privacyKeyStorePasswordFile, privacyTlsKnownEnclaveFile);
|
||||
} else {
|
||||
return enclaveFactory.createGoQuorumEnclave(privacyUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private String readEnclaveKey() {
|
||||
final String key;
|
||||
try {
|
||||
key = Files.asCharSource(privacyPublicKeyFile, UTF_8).read();
|
||||
} catch (final Exception e) {
|
||||
throw new ParameterException(
|
||||
this.commandLine,
|
||||
"--privacy-public-key-file must be set when --goquorum-compatibility-enabled is set to true.",
|
||||
e);
|
||||
}
|
||||
if (key.length() != 44) {
|
||||
throw new IllegalArgumentException(
|
||||
"Contents of enclave public key file needs to be 44 characters long to decode to a valid 32 byte public key.");
|
||||
}
|
||||
// throws exception if invalid base 64
|
||||
Base64.getDecoder().decode(key);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
private NetworkName getNetwork() {
|
||||
// noinspection ConstantConditions network is not always null but injected by
|
||||
// PicoCLI if used
|
||||
@@ -1913,7 +1960,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
final OptionalLong qip714BlockNumber = genesisConfigOptions.getQip714BlockNumber();
|
||||
return Optional.of(
|
||||
QuorumPermissioningConfiguration.enabled(qip714BlockNumber.orElse(QIP714_DEFAULT_BLOCK)));
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
throw new IllegalStateException("Error reading GoQuorum permissioning options", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,7 +868,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dataDirOptionMustBeUsed() throws Exception {
|
||||
public void dataDirOptionMustBeUsed() {
|
||||
final Path path = Paths.get(".");
|
||||
|
||||
parseCommand("--data-path", path.toString());
|
||||
@@ -913,7 +913,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
|
||||
verify(mockControllerBuilder).build();
|
||||
|
||||
EthNetworkConfig config = networkArg.getValue();
|
||||
final EthNetworkConfig config = networkArg.getValue();
|
||||
assertThat(config.getBootNodes()).isEmpty();
|
||||
assertThat(config.getDnsDiscoveryUrl()).isNull();
|
||||
assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(3141592));
|
||||
@@ -929,14 +929,14 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
|
||||
verify(mockControllerBuilder).build();
|
||||
|
||||
EthNetworkConfig config = networkArg.getValue();
|
||||
final EthNetworkConfig config = networkArg.getValue();
|
||||
assertThat(config.getBootNodes()).isEqualTo(MAINNET_BOOTSTRAP_NODES);
|
||||
assertThat(config.getDnsDiscoveryUrl()).isEqualTo(MAINNET_DISCOVERY_URL);
|
||||
assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenesisPathGoerliEthConfig() throws Exception {
|
||||
public void testGenesisPathGoerliEthConfig() {
|
||||
final ArgumentCaptor<EthNetworkConfig> networkArg =
|
||||
ArgumentCaptor.forClass(EthNetworkConfig.class);
|
||||
|
||||
@@ -945,14 +945,14 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
|
||||
verify(mockControllerBuilder).build();
|
||||
|
||||
EthNetworkConfig config = networkArg.getValue();
|
||||
final EthNetworkConfig config = networkArg.getValue();
|
||||
assertThat(config.getBootNodes()).isEqualTo(GOERLI_BOOTSTRAP_NODES);
|
||||
assertThat(config.getDnsDiscoveryUrl()).isEqualTo(GOERLI_DISCOVERY_URL);
|
||||
assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenesisPathRinkebyEthConfig() throws Exception {
|
||||
public void testGenesisPathRinkebyEthConfig() {
|
||||
final ArgumentCaptor<EthNetworkConfig> networkArg =
|
||||
ArgumentCaptor.forClass(EthNetworkConfig.class);
|
||||
|
||||
@@ -961,7 +961,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
|
||||
verify(mockControllerBuilder).build();
|
||||
|
||||
EthNetworkConfig config = networkArg.getValue();
|
||||
final EthNetworkConfig config = networkArg.getValue();
|
||||
assertThat(config.getBootNodes()).isEqualTo(RINKEBY_BOOTSTRAP_NODES);
|
||||
assertThat(config.getDnsDiscoveryUrl()).isEqualTo(RINKEBY_DISCOVERY_URL);
|
||||
assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(4));
|
||||
@@ -1517,7 +1517,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
|
||||
@Test
|
||||
public void dnsEnabledOptionIsParsedCorrectly() {
|
||||
TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true");
|
||||
final TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true");
|
||||
|
||||
assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isTrue();
|
||||
assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isFalse();
|
||||
@@ -1525,7 +1525,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
|
||||
@Test
|
||||
public void dnsUpdateEnabledOptionIsParsedCorrectly() {
|
||||
TestBesuCommand besuCommand =
|
||||
final TestBesuCommand besuCommand =
|
||||
parseCommand("--Xdns-enabled", "true", "--Xdns-update-enabled", "true");
|
||||
|
||||
assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isTrue();
|
||||
@@ -3987,10 +3987,44 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
"--genesis-file",
|
||||
genesisFile.toString(),
|
||||
"--min-gas-price",
|
||||
"0");
|
||||
"0",
|
||||
"--privacy-public-key-file",
|
||||
ENCLAVE_PUBLIC_KEY_PATH);
|
||||
assertThat(commandErrorOutput.toString()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quorumInteropEnabledFailsIfEnclaveKeyFileDoesNotExist() throws IOException {
|
||||
final Path genesisFile =
|
||||
createFakeGenesisFile(VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID);
|
||||
parseCommand(
|
||||
"--goquorum-compatibility-enabled",
|
||||
"--genesis-file",
|
||||
genesisFile.toString(),
|
||||
"--min-gas-price",
|
||||
"0",
|
||||
"--privacy-public-key-file",
|
||||
"ThisFileDoesNotExist");
|
||||
assertThat(commandErrorOutput.toString())
|
||||
.contains(
|
||||
"--privacy-public-key-file must be set when --goquorum-compatibility-enabled is set to true.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quorumInteropEnabledFailsIfEnclaveKeyFileIsNotSet() throws IOException {
|
||||
final Path genesisFile =
|
||||
createFakeGenesisFile(VALID_GENESIS_QUORUM_INTEROP_ENABLED_WITH_CHAINID);
|
||||
parseCommand(
|
||||
"--goquorum-compatibility-enabled",
|
||||
"--genesis-file",
|
||||
genesisFile.toString(),
|
||||
"--min-gas-price",
|
||||
"0");
|
||||
assertThat(commandErrorOutput.toString())
|
||||
.contains(
|
||||
"--privacy-public-key-file must be set when --goquorum-compatibility-enabled is set to true.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quorumInteropEnabledFailsWithMainnetDefaultNetwork() throws IOException {
|
||||
final Path genesisFile = createFakeGenesisFile(INVALID_GENESIS_QUORUM_INTEROP_ENABLED_MAINNET);
|
||||
|
||||
@@ -48,6 +48,22 @@ public class EnclaveFactory {
|
||||
return new Enclave(vertxTransmitter);
|
||||
}
|
||||
|
||||
public Enclave createVertxEnclave(
|
||||
final URI enclaveUri,
|
||||
final Path privacyKeyStoreFile,
|
||||
final Path privacyKeyStorePasswordFile,
|
||||
final Path privacyAllowlistFile) {
|
||||
|
||||
final HttpClientOptions clientOptions =
|
||||
createTlsClientOptions(
|
||||
enclaveUri, privacyKeyStoreFile, privacyKeyStorePasswordFile, privacyAllowlistFile);
|
||||
|
||||
final RequestTransmitter vertxTransmitter =
|
||||
new VertxRequestTransmitter(vertx.createHttpClient(clientOptions));
|
||||
|
||||
return new Enclave(vertxTransmitter);
|
||||
}
|
||||
|
||||
public GoQuorumEnclave createGoQuorumEnclave(final URI enclaveUri) {
|
||||
final HttpClientOptions clientOptions = createNonTlsClientOptions(enclaveUri);
|
||||
|
||||
@@ -115,22 +131,6 @@ public class EnclaveFactory {
|
||||
return clientOptions;
|
||||
}
|
||||
|
||||
public Enclave createVertxEnclave(
|
||||
final URI enclaveUri,
|
||||
final Path privacyKeyStoreFile,
|
||||
final Path privacyKeyStorePasswordFile,
|
||||
final Path privacyAllowlistFile) {
|
||||
|
||||
final HttpClientOptions clientOptions =
|
||||
createTlsClientOptions(
|
||||
enclaveUri, privacyKeyStoreFile, privacyKeyStorePasswordFile, privacyAllowlistFile);
|
||||
|
||||
final RequestTransmitter vertxTransmitter =
|
||||
new VertxRequestTransmitter(vertx.createHttpClient(clientOptions));
|
||||
|
||||
return new Enclave(vertxTransmitter);
|
||||
}
|
||||
|
||||
private static PfxOptions convertFrom(final Path keystoreFile, final Path keystorePasswordFile)
|
||||
throws IOException {
|
||||
final String password = readSecretFromFile(keystorePasswordFile);
|
||||
|
||||
@@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods;
|
||||
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.MultiTenancyUserUtil.enclavePublicKey;
|
||||
|
||||
import org.hyperledger.besu.ethereum.core.GoQuorumPrivacyParameters;
|
||||
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -28,9 +29,12 @@ public interface EnclavePublicKeyProvider {
|
||||
String getEnclaveKey(Optional<User> user);
|
||||
|
||||
static EnclavePublicKeyProvider build(final PrivacyParameters privacyParameters) {
|
||||
return privacyParameters.isMultiTenancyEnabled()
|
||||
? multiTenancyEnclavePublicKeyProvider()
|
||||
: defaultEnclavePublicKeyProvider(privacyParameters);
|
||||
if (GoQuorumPrivacyParameters.isEnabled) {
|
||||
return goQuorumEnclavePublicKeyProvider();
|
||||
} else if (privacyParameters.isMultiTenancyEnabled()) {
|
||||
return multiTenancyEnclavePublicKeyProvider();
|
||||
}
|
||||
return defaultEnclavePublicKeyProvider(privacyParameters);
|
||||
}
|
||||
|
||||
private static EnclavePublicKeyProvider multiTenancyEnclavePublicKeyProvider() {
|
||||
@@ -44,4 +48,8 @@ public interface EnclavePublicKeyProvider {
|
||||
final PrivacyParameters privacyParameters) {
|
||||
return user -> privacyParameters.getEnclavePublicKey();
|
||||
}
|
||||
|
||||
private static EnclavePublicKeyProvider goQuorumEnclavePublicKeyProvider() {
|
||||
return user -> GoQuorumPrivacyParameters.enclaveKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.ethereum.core;
|
||||
|
||||
import org.hyperledger.besu.enclave.GoQuorumEnclave;
|
||||
|
||||
public class GoQuorumPrivacyParameters {
|
||||
|
||||
public static boolean isEnabled = false;
|
||||
|
||||
public static GoQuorumEnclave goQuorumEnclave;
|
||||
|
||||
public static String enclaveKey;
|
||||
}
|
||||
Reference in New Issue
Block a user