Skip to content

Commit

Permalink
[Privacy] Allow users to provide a private genesis (hyperledger#2509)
Browse files Browse the repository at this point in the history
* Refactor: PrivacyBlockProcessor to clarify intent

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Wire up privacy genesis options into PrivacyParameters

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Refactor private state genesis into it's own class

- pass through in privacyParameters

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Refactor: inject PrivateStateGenesis into PrivacyPrecompiles

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Private Genesis initialisation

- set code, balance and storage from private-genesis.json

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Check on-chain with private genesis in acceptance tests

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Remove unused EthGetCodeCall

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Use a plugin based aproach for privacy genesis

- if the plugin is registered it will be used to apply private genesis
state
- if onchain flexible privacy groups is enable that will be applied
after

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* PrivateGenesisAcceptanceTest::createPrivacyGroup can be private

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* PrivateStateGenesis add debug logs

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Warn if genesis account allocation is in reserved precompile range

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Add sender into unsignedPrivateMarkerTransaction for plugin to make descision

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Remove locking solution as may not be needed

- if this is required we should first evaluate actual use cases
and test scenarios

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Rename PrivateStateGenesis -> PrivateStateGenesisAllocator

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Tidy up naming for getPrivateStateGenesisAllocator

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>

* Privacy Plugin javadocs

Signed-off-by: Antony Denyer <git@antonydenyer.co.uk>
  • Loading branch information
antonydenyer authored Aug 10, 2021
1 parent 047b680 commit 19c3451
Show file tree
Hide file tree
Showing 42 changed files with 1,224 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,43 @@ public PrivacyNode createIbft2NodePrivacyEnabled(
containerNetwork);
}

public PrivacyNode createIbft2NodePrivacyEnabledWithGenesis(
final String name,
final PrivacyAccount privacyAccount,
final boolean minerEnabled,
final EnclaveType enclaveType,
final Optional<Network> containerNetwork,
final boolean isOnchainPrivacyGroupEnabled,
final boolean isMultitenancyEnabled,
final boolean isPrivacyPluginEnabled,
final String unrestrictedPrefix)
throws IOException {
return create(
new PrivacyNodeConfiguration(
isOnchainPrivacyGroupEnabled,
isMultitenancyEnabled,
isPrivacyPluginEnabled,
new BesuNodeConfigurationBuilder()
.name(name)
.miningEnabled()
.jsonRpcConfiguration(node.createJsonRpcWithIbft2EnabledConfig(minerEnabled))
.webSocketConfiguration(node.createWebSocketEnabledConfig())
.devMode(false)
.genesisConfigProvider(genesis::createPrivacyIbft2GenesisConfig)
.keyFilePath(privacyAccount.getPrivateKeyPath())
.enablePrivateTransactions()
.plugins(Collections.singletonList("testPlugins"))
.extraCLIOptions(
List.of(
"--plugin-privacy-service-encryption-prefix=" + unrestrictedPrefix,
"--plugin-privacy-service-genesis-enabled=true"))
.build(),
new EnclaveKeyConfiguration(
privacyAccount.getEnclaveKeyPaths(), privacyAccount.getEnclavePrivateKeyPaths())),
enclaveType,
containerNetwork);
}

public PrivacyNode createQbftNodePrivacyEnabled(
final String name,
final PrivacyAccount privacyAccount,
Expand Down Expand Up @@ -231,6 +268,8 @@ public PrivacyNode createOnChainPrivacyGroupEnabledMinerNode(
.jsonRpcEnabled()
.webSocketEnabled()
.enablePrivateTransactions()
.plugins(Collections.singletonList("testPlugins"))
.extraCLIOptions(List.of("--plugin-privacy-service-genesis-enabled=true"))
.keyFilePath(privacyAccount.getPrivateKeyPath())
.build(),
new EnclaveKeyConfiguration(
Expand All @@ -256,6 +295,8 @@ public PrivacyNode createOnChainPrivacyGroupEnabledNode(
.jsonRpcEnabled()
.keyFilePath(privacyAccount.getPrivateKeyPath())
.enablePrivateTransactions()
.plugins(Collections.singletonList("testPlugins"))
.extraCLIOptions(List.of("--plugin-privacy-service-genesis-enabled=true"))
.webSocketEnabled()
.build(),
new EnclaveKeyConfiguration(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
public class PrivacyAcceptanceTestBase {
@ClassRule public static final TemporaryFolder privacy = new TemporaryFolder();

protected static final long POW_CHAIN_ID = 1337;

protected final PrivacyTransactions privacyTransactions;
protected final PrivateContractVerifier privateContractVerifier;
protected final PrivateTransactionVerifier privateTransactionVerifier;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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.tests.acceptance.dsl.privacy.contract;

import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;

import java.lang.reflect.Method;
import java.math.BigInteger;

import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.tx.Contract;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.BesuPrivacyGasProvider;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.utils.Base64String;

public class LoadPrivateSmartContractTransactionWithPrivacyGroupId<T extends Contract>
implements Transaction<T> {

private static final BesuPrivacyGasProvider GAS_PROVIDER =
new BesuPrivacyGasProvider(BigInteger.valueOf(1000));
private static final Object METHOD_IS_STATIC = null;

private final Class<T> clazz;
private final Credentials senderCredentials;
private final Base64String privateFrom;
private final Base64String privacyGroupId;
private final String contractAddress;

public LoadPrivateSmartContractTransactionWithPrivacyGroupId(
final String contractAddress,
final Class<T> clazz,
final String transactionSigningKey,
final String privateFrom,
final String privacyGroupId) {

this.contractAddress = contractAddress;
this.clazz = clazz;
this.senderCredentials = Credentials.create(transactionSigningKey);
this.privateFrom = Base64String.wrap(privateFrom);
this.privacyGroupId = Base64String.wrap(privacyGroupId);
}

@SuppressWarnings("unchecked")
@Override
public T execute(final NodeRequests node) {
final PrivateTransactionManager privateTransactionManager =
new PrivateTransactionManager.Builder(
node.privacy().getBesuClient(), senderCredentials, privateFrom)
.setPrivacyGroupId(privacyGroupId)
.build();

try {
final Method method =
clazz.getMethod(
"load",
String.class,
Web3j.class,
TransactionManager.class,
ContractGasProvider.class);

return (T)
method.invoke(
METHOD_IS_STATIC,
contractAddress,
node.privacy().getBesuClient(),
privateTransactionManager,
GAS_PROVIDER);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public <T extends Contract> LoadPrivateSmartContractTransaction<T> loadSmartCont
contractAddress, clazz, transactionSigningKey, privateFrom, Arrays.asList(privateFor));
}

private <T extends Contract> LoadPrivateSmartContractTransaction<T> loadSmartContract(
public <T extends Contract> LoadPrivateSmartContractTransaction<T> loadSmartContract(
final String contractAddress,
final Class<T> clazz,
final String transactionSigningKey,
Expand All @@ -146,6 +146,17 @@ private <T extends Contract> LoadPrivateSmartContractTransaction<T> loadSmartCon
contractAddress, clazz, transactionSigningKey, privateFrom, privateFor);
}

public <T extends Contract>
LoadPrivateSmartContractTransactionWithPrivacyGroupId<T> loadSmartContractWithPrivacyGroupId(
final String contractAddress,
final Class<T> clazz,
final String transactionSigningKey,
final String privateFrom,
final String privacyGroupId) {
return new LoadPrivateSmartContractTransactionWithPrivacyGroupId<>(
contractAddress, clazz, transactionSigningKey, privateFrom, privacyGroupId);
}

public CallOnChainPermissioningPrivateSmartContractFunction callOnChainPermissioningSmartContract(
final String contractAddress,
final String encodedFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,17 @@
*/
package org.hyperledger.besu.plugins;

import static org.hyperledger.besu.ethereum.privacy.PrivateTransaction.readFrom;
import static org.hyperledger.besu.ethereum.privacy.PrivateTransaction.serialize;

import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.data.PrivateTransaction;
import org.hyperledger.besu.plugin.data.Transaction;
import org.hyperledger.besu.plugin.services.PicoCLIOptions;
import org.hyperledger.besu.plugin.services.PrivacyPluginService;
import org.hyperledger.besu.plugin.services.privacy.PrivacyPluginPayloadProvider;

import java.util.Optional;
import org.hyperledger.besu.plugins.privacy.TestPrivacyGroupGenesisProvider;
import org.hyperledger.besu.plugins.privacy.TestPrivacyPluginPayloadProvider;
import org.hyperledger.besu.plugins.privacy.TestSigningPrivateMarkerTransactionFactory;

import com.google.auto.service.AutoService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import picocli.CommandLine.Option;

@AutoService(BesuPlugin.class)
Expand All @@ -41,46 +34,38 @@ public class TestPrivacyServicePlugin implements BesuPlugin {
PrivacyPluginService pluginService;
BesuContext context;

TestPrivacyPluginPayloadProvider payloadProvider = new TestPrivacyPluginPayloadProvider();
TestPrivacyGroupGenesisProvider privacyGroupGenesisProvider =
new TestPrivacyGroupGenesisProvider();
TestSigningPrivateMarkerTransactionFactory privateMarkerTransactionFactory =
new TestSigningPrivateMarkerTransactionFactory();

@Override
public void register(final BesuContext context) {
this.context = context;

context.getService(PicoCLIOptions.class).get().addPicoCLIOptions("privacy-service", this);
pluginService = context.getService(PrivacyPluginService.class).get();

pluginService.setPayloadProvider(
new PrivacyPluginPayloadProvider() {
@Override
public Bytes generateMarkerPayload(
final PrivateTransaction privateTransaction, final String privacyUserId) {

return Bytes.wrap(Bytes.fromHexString(prefix), serialize(privateTransaction).encoded());
}

@Override
public Optional<PrivateTransaction> getPrivateTransactionFromPayload(
final Transaction transaction) {

final Bytes prefixBytes = Bytes.fromHexString(prefix);
if (transaction.getPayload().slice(0, prefixBytes.size()).equals(prefixBytes)) {
LOG.info("processing payload for" + prefix);
final BytesValueRLPInput bytesValueRLPInput =
new BytesValueRLPInput(
transaction.getPayload().slice(prefixBytes.size()).copy(), false);
return Optional.of(readFrom(bytesValueRLPInput));
} else {
LOG.info("Can not process payload for" + prefix);
return Optional.empty();
}
}
});
pluginService.setPayloadProvider(payloadProvider);
pluginService.setPrivacyGroupGenesisProvider(privacyGroupGenesisProvider);

LOG.info("Registering Plugins with options " + this);
}

@Override
public void start() {
LOG.info("Start Plugins with options " + this);

payloadProvider.setPluginPayloadPrefix(prefix);

if (genesisEnabled) {
privacyGroupGenesisProvider.setGenesisEnabled();
}

if (signingEnabled) {
pluginService.setPrivateMarkerTransactionFactory(
new TestSigningPrivateMarkerTransactionFactory(signingKey));
pluginService.setPrivateMarkerTransactionFactory(privateMarkerTransactionFactory);
privateMarkerTransactionFactory.setSigningKeyEnbaled(signingKey);
}
}

Expand All @@ -90,9 +75,28 @@ public void stop() {}
@Option(names = "--plugin-privacy-service-encryption-prefix")
String prefix;

@Option(names = "--plugin-privacy-service-genesis-enabled")
boolean genesisEnabled = false;

@Option(names = "--plugin-privacy-service-signing-enabled")
boolean signingEnabled = false;

@Option(names = "--plugin-privacy-service-signing-key")
String signingKey;

@Override
public String toString() {
return "TestPrivacyServicePlugin{"
+ "prefix='"
+ prefix
+ '\''
+ ", signingEnabled="
+ signingEnabled
+ ", genesisEnabled="
+ genesisEnabled
+ ", signingKey='"
+ signingKey
+ '\''
+ '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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.plugins.privacy;

import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.plugin.data.Address;
import org.hyperledger.besu.plugin.data.PrivacyGenesis;
import org.hyperledger.besu.plugin.data.PrivacyGenesisAccount;
import org.hyperledger.besu.plugin.data.Quantity;
import org.hyperledger.besu.plugin.services.privacy.PrivacyGroupGenesisProvider;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;

public class TestPrivacyGroupGenesisProvider implements PrivacyGroupGenesisProvider {
private boolean genesisEnabled = false;

public void setGenesisEnabled() {
this.genesisEnabled = true;
}

@Override
public PrivacyGenesis getPrivacyGenesis(final Bytes privacyGroupId, final long blockNumber) {
if (!genesisEnabled) return Collections::emptyList;

return () ->
List.of(
new PrivacyGenesisAccount() {
@Override
public Address getAddress() {
return org.hyperledger.besu.ethereum.core.Address.fromHexString(
"0x1000000000000000000000000000000000000001");
}

@Override
public Map<UInt256, UInt256> getStorage() {
return Collections.emptyMap();
}

@Override
public int getVersion() {
return 0;
}

@Override
public Long getNonce() {
return 0L;
}

@Override
public Quantity getBalance() {
return Wei.of(1000);
}

// The code in the genesis file needs to be the deployed contract code, not the code
// to deploy
// the contract
// you can generate it using the solc --bin-runtime flag
// cd ./acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/
// docker run -v $PWD:/sources ethereum/solc:0.5.0 -o /sources/output --bin-runtime
// /sources/EventEmitter.sol --overwrite

@Override
public Bytes getCode() {
return Bytes.fromHexString(
"0x608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633fa4f2451461005c5780636057361d1461008757806367e404ce146100c2575b600080fd5b34801561006857600080fd5b50610071610119565b6040518082815260200191505060405180910390f35b34801561009357600080fd5b506100c0600480360360208110156100aa57600080fd5b8101908080359060200190929190505050610123565b005b3480156100ce57600080fd5b506100d76101d9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600254905090565b7fc9db20adedc6cf2b5d25252b101ab03e124902a73fcb12b753f3d1aaa2d8f9f53382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a18060028190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690509056fea165627a7a72305820e74360c3d08936cb1747ad641729261ff5e83b6fc0d303d136e171f15f07d7740029");
}
});
}
}
Loading

0 comments on commit 19c3451

Please sign in to comment.