From 78c458b321903815d2cbc085890bb2fe97da629f Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 19 Aug 2020 13:11:02 +1000 Subject: [PATCH] On chain group management api changes (#1288) - On-chain group management changes: additional API to check whether someone is allowed to update the contract, and remove enclave key as a parameter to contract APIs - Add check for group membership to onchain and offchain precompiled contracts Signed-off-by: Stefan Pingel --- CHANGELOG.md | 8 + .../acceptance/dsl/account/Accounts.java | 15 +- .../AddToOnChainPrivacyGroupTransaction.java | 13 +- .../FindOnChainPrivacyGroupTransaction.java | 2 +- .../LockOnChainPrivacyGroupTransaction.java | 8 +- .../transaction/PrivacyTransactions.java | 20 +- ...oveFromOnChainPrivacyGroupTransaction.java | 13 +- .../privacy/PrivacyRequestFactory.java | 80 ++--- .../besu/tests/acceptance/RunHelpTest.java | 2 +- .../Ibft2PrivacyClusterAcceptanceTest.java | 6 +- .../privacy/OnChainPrivacyAcceptanceTest.java | 82 +++-- .../privacy/PrivacyGroupAcceptanceTest.java | 77 +++++ .../privacy/contracts/PrivacyGroupTest.java | 117 ++++--- .../privacy/contracts/PrivacyProxyTest.java | 89 +++-- .../hyperledger/besu/PrivacyReorgTest.java | 10 + .../methods/eea/EeaSendRawTransaction.java | 7 +- .../priv/PrivDistributeRawTransaction.java | 7 +- .../eea/EeaSendRawTransactionTest.java | 14 +- .../MainnetPrecompiledContractRegistries.java | 3 +- .../OnChainPrivacyPrecompiledContract.java | 134 +++++++- .../privacy/PrivacyPrecompiledContract.java | 31 +- .../privacy/DefaultPrivacyController.java | 91 ++--- .../MultiTenancyPrivacyController.java | 16 +- .../ethereum/privacy/PrivacyController.java | 3 +- .../privacy/PrivateTransactionSimulator.java | 3 +- .../privacy/group/OnChainGroupManagement.java | 10 +- .../core/PrivateTransactionDataFixture.java | 6 + .../core/PrivateTransactionTestFixture.java | 7 + ...OnChainPrivacyPrecompiledContractTest.java | 314 ++++++++++++++++++ .../PrivacyPrecompiledContractTest.java | 51 ++- ...OnChainPrivacyGroupManagementContract.java | 42 +-- ...nChainPrivacyGroupManagementInterface.java | 26 +- .../OnChainPrivacyGroupManagementProxy.java | 128 +++++-- ...tOnChainPrivacyGroupManagementContract.sol | 70 ++-- ...OnChainPrivacyGroupManagementInterface.sol | 11 +- .../OnChainPrivacyGroupManagementProxy.sol | 43 ++- 36 files changed, 1165 insertions(+), 394 deletions(-) create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a775e1783b..145962c284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,14 @@ - [Permissioning issues on Kubernetes](KNOWN_ISSUES.md#Kubernetes-permissioning-uses-Service-IPs-rather-than-pod-IPs-which-can-fail) - [Restarts caused by insufficient memory can cause inconsistent private state](KNOWN_ISSUES.md#Restart-caused-by-insufficient-memory-can-cause-inconsistent-private-state) +### Breaking Changes + +When upgrading to 1.5.3, ensure you've taken into account the following breaking changes. + +#### Onchain Privacy Group Management + +This early access feature was changed in a way that makes onchain privacy groups created with previous versions no longer usable. + ## 1.5.2 ### Additions and Improvements diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Accounts.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Accounts.java index 3eb7d59971..ad3df909c6 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Accounts.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/account/Accounts.java @@ -21,6 +21,8 @@ public class Accounts { public static final String GENESIS_ACCOUNT_ONE_PRIVATE_KEY = "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"; + public static final String GENESIS_ACCOUNT_TWO_PRIVATE_KEY = + "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3"; private final EthTransactions eth; private final Account richBenefactorOne; @@ -31,20 +33,17 @@ public class Accounts { richBenefactorOne = Account.fromPrivateKey(eth, "Rich Benefactor One", GENESIS_ACCOUNT_ONE_PRIVATE_KEY); richBenefactorTwo = - Account.fromPrivateKey( - eth, - "Rich Benefactor Two", - "c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3"); - } - - public Account getSecondaryBenefactor() { - return richBenefactorTwo; + Account.fromPrivateKey(eth, "Rich Benefactor Two", GENESIS_ACCOUNT_TWO_PRIVATE_KEY); } public Account getPrimaryBenefactor() { return richBenefactorOne; } + public Account getSecondaryBenefactor() { + return richBenefactorTwo; + } + public Account createAccount(final String accountName) { return Account.create(eth, accountName); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/AddToOnChainPrivacyGroupTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/AddToOnChainPrivacyGroupTransaction.java index dbcbcf6b21..b802d23193 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/AddToOnChainPrivacyGroupTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/AddToOnChainPrivacyGroupTransaction.java @@ -23,18 +23,23 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -import org.web3j.protocol.exceptions.TransactionException; +import org.web3j.crypto.Credentials; import org.web3j.utils.Base64String; public class AddToOnChainPrivacyGroupTransaction implements Transaction { private final Base64String privacyGroupId; private final PrivacyNode adder; private final List addresses; + private final Credentials signer; public AddToOnChainPrivacyGroupTransaction( - final String privacyGroupId, final PrivacyNode adder, final PrivacyNode... nodes) { + final String privacyGroupId, + final PrivacyNode adder, + final Credentials signer, + final PrivacyNode... nodes) { this.privacyGroupId = Base64String.wrap(privacyGroupId); this.adder = adder; + this.signer = signer; this.addresses = Arrays.stream(nodes) .map(n -> n.getOrion().getDefaultPublicKey()) @@ -44,8 +49,8 @@ public class AddToOnChainPrivacyGroupTransaction implements Transaction @Override public String execute(final NodeRequests node) { try { - return node.privacy().privxAddToPrivacyGroup(privacyGroupId, adder, addresses); - } catch (final IOException | TransactionException e) { + return node.privacy().privxAddToPrivacyGroup(privacyGroupId, adder, signer, addresses); + } catch (final IOException e) { throw new RuntimeException(e); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/FindOnChainPrivacyGroupTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/FindOnChainPrivacyGroupTransaction.java index 9100c58695..ecb3ee73b0 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/FindOnChainPrivacyGroupTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/FindOnChainPrivacyGroupTransaction.java @@ -36,7 +36,7 @@ public class FindOnChainPrivacyGroupTransaction public List execute(final NodeRequests node) { try { return node.privacy().privxFindOnChainPrivacyGroup(nodes).send().getGroups(); - } catch (IOException e) { + } catch (final IOException e) { throw new RuntimeException(e); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/LockOnChainPrivacyGroupTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/LockOnChainPrivacyGroupTransaction.java index 162242b04a..f6e4e3b476 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/LockOnChainPrivacyGroupTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/LockOnChainPrivacyGroupTransaction.java @@ -20,22 +20,26 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; import java.io.IOException; +import org.web3j.crypto.Credentials; import org.web3j.protocol.exceptions.TransactionException; import org.web3j.utils.Base64String; public class LockOnChainPrivacyGroupTransaction implements Transaction { private final Base64String privacyGroupId; private final PrivacyNode locker; + private final Credentials signer; - public LockOnChainPrivacyGroupTransaction(final String privacyGroupId, final PrivacyNode locker) { + public LockOnChainPrivacyGroupTransaction( + final String privacyGroupId, final PrivacyNode locker, final Credentials signer) { this.privacyGroupId = Base64String.wrap(privacyGroupId); this.locker = locker; + this.signer = signer; } @Override public String execute(final NodeRequests node) { try { - return node.privacy().privxLockPrivacyGroup(locker, privacyGroupId); + return node.privacy().privxLockPrivacyGroup(locker, privacyGroupId, signer); } catch (final IOException | TransactionException e) { throw new RuntimeException(e); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/PrivacyTransactions.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/PrivacyTransactions.java index ae3e8aaaf2..dab456e253 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/PrivacyTransactions.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/PrivacyTransactions.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.filter.Priv import java.util.List; +import org.web3j.crypto.Credentials; import org.web3j.tx.Contract; public class PrivacyTransactions { @@ -49,13 +50,16 @@ public class PrivacyTransactions { } public AddToOnChainPrivacyGroupTransaction addToPrivacyGroup( - final String privacyGroupId, final PrivacyNode adder, final PrivacyNode... nodes) { - return new AddToOnChainPrivacyGroupTransaction(privacyGroupId, adder, nodes); + final String privacyGroupId, + final PrivacyNode adder, + final Credentials signer, + final PrivacyNode... nodes) { + return new AddToOnChainPrivacyGroupTransaction(privacyGroupId, adder, signer, nodes); } public LockOnChainPrivacyGroupTransaction privxLockPrivacyGroupAndCheck( - final String privacyGroupId, final PrivacyNode locker) { - return new LockOnChainPrivacyGroupTransaction(privacyGroupId, locker); + final String privacyGroupId, final PrivacyNode locker, final Credentials signer) { + return new LockOnChainPrivacyGroupTransaction(privacyGroupId, locker, signer); } public FindPrivacyGroupTransaction findPrivacyGroup(final List nodes) { @@ -87,8 +91,12 @@ public class PrivacyTransactions { } public RemoveFromOnChainPrivacyGroupTransaction removeFromPrivacyGroup( - final String privacyGroupId, final PrivacyNode remover, final PrivacyNode nodeToRemove) { - return new RemoveFromOnChainPrivacyGroupTransaction(privacyGroupId, remover, nodeToRemove); + final String privacyGroupId, + final PrivacyNode remover, + final Credentials signer, + final PrivacyNode nodeToRemove) { + return new RemoveFromOnChainPrivacyGroupTransaction( + privacyGroupId, remover, signer, nodeToRemove); } public EeaSendRawTransactionTransaction sendRawTransaction(final String transaction) { diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/RemoveFromOnChainPrivacyGroupTransaction.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/RemoveFromOnChainPrivacyGroupTransaction.java index 7dd8ef14e0..dc521a6641 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/RemoveFromOnChainPrivacyGroupTransaction.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/transaction/RemoveFromOnChainPrivacyGroupTransaction.java @@ -20,26 +20,31 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction; import java.io.IOException; -import org.web3j.protocol.exceptions.TransactionException; +import org.web3j.crypto.Credentials; import org.web3j.utils.Base64String; public class RemoveFromOnChainPrivacyGroupTransaction implements Transaction { private final Base64String privacyGroupId; private final PrivacyNode remover; private final String toRemove; + private final Credentials signer; public RemoveFromOnChainPrivacyGroupTransaction( - final String privacyGroupId, final PrivacyNode remover, final PrivacyNode toRemove) { + final String privacyGroupId, + final PrivacyNode remover, + final Credentials signer, + final PrivacyNode toRemove) { this.privacyGroupId = Base64String.wrap(privacyGroupId); this.remover = remover; + this.signer = signer; this.toRemove = toRemove.getOrion().getDefaultPublicKey(); } @Override public String execute(final NodeRequests node) { try { - return node.privacy().privxRemoveFromPrivacyGroup(privacyGroupId, remover, toRemove); - } catch (IOException | TransactionException e) { + return node.privacy().privxRemoveFromPrivacyGroup(privacyGroupId, remover, signer, toRemove); + } catch (final IOException e) { throw new RuntimeException(e); } } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivacyRequestFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivacyRequestFactory.java index 5ce9961646..88c076ffaf 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivacyRequestFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/privacy/PrivacyRequestFactory.java @@ -49,6 +49,7 @@ import org.web3j.protocol.core.Response; import org.web3j.protocol.core.methods.response.EthCall; import org.web3j.protocol.core.methods.response.EthFilter; import org.web3j.protocol.core.methods.response.EthLog; +import org.web3j.protocol.core.methods.response.EthSendTransaction; import org.web3j.protocol.core.methods.response.EthUninstallFilter; import org.web3j.protocol.eea.crypto.PrivateTransactionEncoder; import org.web3j.protocol.eea.crypto.RawPrivateTransaction; @@ -127,18 +128,20 @@ public class PrivacyRequestFactory { } public String privxAddToPrivacyGroup( - final Base64String privacyGroupId, final PrivacyNode adder, final List addresses) - throws IOException, TransactionException { + final Base64String privacyGroupId, + final PrivacyNode adder, + final Credentials signer, + final List addresses) + throws IOException { final BigInteger nonce = besuClient - .privGetTransactionCount(adder.getAddress().toHexString(), privacyGroupId) + .privGetTransactionCount(signer.getAddress(), privacyGroupId) .send() .getTransactionCount(); final Bytes payload = encodeAddToGroupFunctionCall( - Bytes.fromBase64String(adder.getEnclaveKey()), addresses.stream().map(Bytes::fromBase64String).collect(Collectors.toList())); final RawPrivateTransaction privateTransaction = @@ -154,26 +157,25 @@ public class PrivacyRequestFactory { return besuClient .eeaSendRawTransaction( - Numeric.toHexString( - PrivateTransactionEncoder.signMessage( - privateTransaction, Credentials.create(adder.getTransactionSigningKey())))) + Numeric.toHexString(PrivateTransactionEncoder.signMessage(privateTransaction, signer))) .send() .getTransactionHash(); } public String privxRemoveFromPrivacyGroup( - final Base64String privacyGroupId, final PrivacyNode remover, final String toRemove) - throws IOException, TransactionException { + final Base64String privacyGroupId, + final PrivacyNode remover, + final Credentials signer, + final String toRemove) + throws IOException { final BigInteger nonce = besuClient - .privGetTransactionCount(remover.getAddress().toHexString(), privacyGroupId) + .privGetTransactionCount(signer.getAddress(), privacyGroupId) .send() .getTransactionCount(); - final Bytes payload = - encodeRemoveFromGroupFunctionCall( - Bytes.fromBase64String(remover.getEnclaveKey()), Bytes.fromBase64String(toRemove)); + final Bytes payload = encodeRemoveFromGroupFunctionCall(Bytes.fromBase64String(toRemove)); final RawPrivateTransaction privateTransaction = RawPrivateTransaction.createTransaction( @@ -188,23 +190,21 @@ public class PrivacyRequestFactory { return besuClient .eeaSendRawTransaction( - Numeric.toHexString( - PrivateTransactionEncoder.signMessage( - privateTransaction, Credentials.create(remover.getTransactionSigningKey())))) + Numeric.toHexString(PrivateTransactionEncoder.signMessage(privateTransaction, signer))) .send() .getTransactionHash(); } - private Bytes encodeRemoveFromGroupFunctionCall(final Bytes remover, final Bytes toRemove) { - return Bytes.concatenate( - OnChainGroupManagement.REMOVE_PARTICIPANT_METHOD_SIGNATURE, remover, toRemove); + private Bytes encodeRemoveFromGroupFunctionCall(final Bytes toRemove) { + return Bytes.concatenate(OnChainGroupManagement.REMOVE_PARTICIPANT_METHOD_SIGNATURE, toRemove); } - public String privxLockPrivacyGroup(final PrivacyNode locker, final Base64String privacyGroupId) + public String privxLockPrivacyGroup( + final PrivacyNode locker, final Base64String privacyGroupId, final Credentials signer) throws IOException, TransactionException { final BigInteger nonce = besuClient - .privGetTransactionCount(locker.getAddress().toHexString(), privacyGroupId) + .privGetTransactionCount(signer.getAddress(), privacyGroupId) .send() .getTransactionCount(); @@ -223,8 +223,7 @@ public class PrivacyRequestFactory { besuClient .eeaSendRawTransaction( Numeric.toHexString( - PrivateTransactionEncoder.signMessage( - privateTransaction, Credentials.create(locker.getTransactionSigningKey())))) + PrivateTransactionEncoder.signMessage(privateTransaction, signer))) .send() .getTransactionHash(); @@ -244,22 +243,13 @@ public class PrivacyRequestFactory { secureRandom.nextBytes(bytes); final Bytes privacyGroupId = Bytes.wrap(bytes); - final BigInteger nonce = - besuClient - .privGetTransactionCount( - creator.getAddress().toHexString(), - Base64String.wrap(privacyGroupId.toArrayUnsafe())) - .send() - .getTransactionCount(); - final Bytes payload = encodeAddToGroupFunctionCall( - Bytes.fromBase64String(creator.getEnclaveKey()), addresses.stream().map(Bytes::fromBase64String).collect(Collectors.toList())); final RawPrivateTransaction privateTransaction = RawPrivateTransaction.createTransaction( - nonce, + BigInteger.ZERO, BigInteger.valueOf(1000), BigInteger.valueOf(3000000), Address.ONCHAIN_PRIVACY_PROXY.toHexString(), @@ -268,15 +258,12 @@ public class PrivacyRequestFactory { Base64String.wrap(privacyGroupId.toArrayUnsafe()), org.web3j.utils.Restriction.RESTRICTED); - final String transactionHash = - besuClient - .eeaSendRawTransaction( - Numeric.toHexString( - PrivateTransactionEncoder.signMessage( - privateTransaction, - Credentials.create(creator.getTransactionSigningKey())))) - .send() - .getTransactionHash(); + final Request ethSendTransactionRequest = + besuClient.eeaSendRawTransaction( + Numeric.toHexString( + PrivateTransactionEncoder.signMessage( + privateTransaction, Credentials.create(creator.getTransactionSigningKey())))); + final String transactionHash = ethSendTransactionRequest.send().getTransactionHash(); return new PrivxCreatePrivacyGroupResponse(privacyGroupId.toBase64String(), transactionHash); } @@ -531,16 +518,13 @@ public class PrivacyRequestFactory { } } - private Bytes encodeAddToGroupFunctionCall( - final Bytes privateFrom, final List participants) { + private Bytes encodeAddToGroupFunctionCall(final List participants) { return Bytes.concatenate( - OnChainGroupManagement.ADD_TO_GROUP_METHOD_SIGNATURE, - privateFrom, - encodeList(participants)); + OnChainGroupManagement.ADD_PARTICIPANTS_METHOD_SIGNATURE, encodeList(participants)); } private Bytes encodeList(final List participants) { - final Bytes dynamicParameterOffset = encodeLong(64); + final Bytes dynamicParameterOffset = encodeLong(32); final Bytes length = encodeLong(participants.size()); return Bytes.concatenate( dynamicParameterOffset, diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/RunHelpTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/RunHelpTest.java index 7898a104f9..49bf159b1d 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/RunHelpTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/RunHelpTest.java @@ -26,7 +26,7 @@ public class RunHelpTest extends AcceptanceTestBase { @Test public void testShowsHelpAndExits() throws IOException { - BesuNode node = besu.runCommand("--help"); + final BesuNode node = besu.runCommand("--help"); cluster.runNodeStart(node); WaitUtils.waitFor(5000, () -> node.verify(exitedSuccessfully)); } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/Ibft2PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/Ibft2PrivacyClusterAcceptanceTest.java index 6d5f5f08a3..f2d22fc6c2 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/Ibft2PrivacyClusterAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/Ibft2PrivacyClusterAcceptanceTest.java @@ -144,16 +144,16 @@ public class Ibft2PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase bob.getEnclaveKey())); // alice gets receipt from charlie's interaction - final PrivateTransactionReceipt firstExpectedReceipt = + final PrivateTransactionReceipt aliceReceipt = alice.execute(privacyTransactions.getPrivateTransactionReceipt(firstTransactionHash)); // verify bob and charlie have access to the same receipt bob.verify( privateTransactionVerifier.validPrivateTransactionReceipt( - firstTransactionHash, firstExpectedReceipt)); + firstTransactionHash, aliceReceipt)); charlie.verify( privateTransactionVerifier.validPrivateTransactionReceipt( - firstTransactionHash, firstExpectedReceipt)); + firstTransactionHash, aliceReceipt)); // alice deploys second contract final String secondDeployedAddress = "0xebf56429e6500e84442467292183d4d621359838"; diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTest.java index dd2cc7b643..66fbe982d5 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/OnChainPrivacyAcceptanceTest.java @@ -39,6 +39,7 @@ import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; import org.junit.Before; import org.junit.Test; +import org.web3j.crypto.Credentials; import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.protocol.core.methods.response.EthCall; import org.web3j.protocol.core.methods.response.Log; @@ -78,8 +79,8 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { @Test public void nodeCanCreatePrivacyGroup() { - final String privacyGroupId = createOnChainPrivacyGroup(alice, bob); - checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob); + final String privacyGroupId = createOnChainPrivacyGroup(alice); + checkOnChainPrivacyGroupExists(privacyGroupId, alice); } @Test @@ -100,8 +101,9 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(commitmentHash)); - lockPrivacyGroup(privacyGroupId, alice); - addMembersToPrivacyGroup(privacyGroupId, alice, charlie); + final Credentials aliceCredentials = Credentials.create(alice.getTransactionSigningKey()); + lockPrivacyGroup(privacyGroupId, alice, aliceCredentials); + addMembersToPrivacyGroup(privacyGroupId, alice, aliceCredentials, charlie); checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob, charlie); charlie.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(commitmentHash)); @@ -111,7 +113,9 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { public void removedMemberCannotSendTransactionToGroup() { final String privacyGroupId = createOnChainPrivacyGroup(alice, bob); - final String removeHash = removeFromPrivacyGroup(privacyGroupId, alice, bob); + final String removeHash = + removeFromPrivacyGroup( + privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob); bob.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(removeHash)); @@ -126,8 +130,9 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { checkOnChainPrivacyGroupExists(privacyGroupId, alice); - lockPrivacyGroup(privacyGroupId, alice); - addMembersToPrivacyGroup(privacyGroupId, alice, bob); + lockPrivacyGroup(privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey())); + addMembersToPrivacyGroup( + privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob); checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob); @@ -142,7 +147,8 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { eventEmitter, valueSetWhileBobWasMember); - removeFromPrivacyGroup(privacyGroupId, alice, bob); + removeFromPrivacyGroup( + privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob); checkOnChainPrivacyGroupExists(privacyGroupId, alice); @@ -159,8 +165,9 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { eventEmitter, valueSetWhileBobWasMember); // bob did not get the last transaction - lockPrivacyGroup(privacyGroupId, alice); - addMembersToPrivacyGroup(privacyGroupId, alice, bob); + lockPrivacyGroup(privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey())); + addMembersToPrivacyGroup( + privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob); checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob); @@ -187,11 +194,11 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { final List nodes, final String privacyGroupId, final EventEmitter eventEmitter, - final int valueSetWhileBobWasMember) { + final int value) { final PrivateTransactionReceipt receiptWhileBobMember = - setEventEmitterValue(nodes, privacyGroupId, eventEmitter, valueSetWhileBobWasMember); + setEventEmitterValue(nodes, privacyGroupId, eventEmitter, value); - checkEmitterValue(nodes, privacyGroupId, eventEmitter, valueSetWhileBobWasMember); + checkEmitterValue(nodes, privacyGroupId, eventEmitter, value); return receiptWhileBobMember; } @@ -222,7 +229,7 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { final List nodes, final String privacyGroupId, final EventEmitter eventEmitter, - final int valueWhileBobMember) { + final int expectedValue) { for (final PrivacyNode node : nodes) { final EthCall response = node.execute( @@ -230,14 +237,14 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall())); assertThat(new BigInteger(response.getValue().substring(2), 16)) - .isEqualByComparingTo(BigInteger.valueOf(valueWhileBobMember)); + .isEqualByComparingTo(BigInteger.valueOf(expectedValue)); } } @Test public void bobCanAddCharlieAfterBeingAddedByAlice() { final String privacyGroupId = createOnChainPrivacyGroup(alice); - + checkOnChainPrivacyGroupExists(privacyGroupId, alice); final EventEmitter eventEmitter = alice.execute( privateContractTransactions.createSmartContractWithPrivacyGroupId( @@ -252,14 +259,19 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { eventEmitter.getContractAddress(), alice.getAddress().toString()) .verify(eventEmitter); + final Credentials aliceCredentials = Credentials.create(alice.getTransactionSigningKey()); final String aliceLockHash = - alice.execute(privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, alice)); + alice.execute( + privacyTransactions.privxLockPrivacyGroupAndCheck( + privacyGroupId, alice, aliceCredentials)); - alice.execute(privacyTransactions.addToPrivacyGroup(privacyGroupId, alice, bob)); + alice.execute( + privacyTransactions.addToPrivacyGroup(privacyGroupId, alice, aliceCredentials, bob)); checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob); - bob.execute(privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, bob)); + bob.execute( + privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, bob, aliceCredentials)); alice.execute(minerTransactions.minerStop()); @@ -278,7 +290,8 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { alice.getEnclaveKey(), privacyGroupId)); - final String bobAddHash = addMembersToPrivacyGroup(privacyGroupId, bob, charlie); + final String bobAddHash = + addMembersToPrivacyGroup(privacyGroupId, bob, aliceCredentials, charlie); alice .getBesu() @@ -392,20 +405,20 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { privateTransactionVerifier.validPrivateTransactionReceipt( aliceStoreHash, expectedStoreReceipt)); - removeFromPrivacyGroup(privacyGroupId, bob, charlie); + removeFromPrivacyGroup(privacyGroupId, bob, aliceCredentials, charlie); checkOnChainPrivacyGroupExists(privacyGroupId, alice, bob); } @Test - public void addMembersToTwoGroupsInTheSameBlock() throws InterruptedException { + public void addMembersToTwoGroupsInTheSameBlock() { final String privacyGroupId1 = createOnChainPrivacyGroup(alice); final String privacyGroupId2 = createOnChainPrivacyGroup(bob); checkOnChainPrivacyGroupExists(privacyGroupId1, alice); checkOnChainPrivacyGroupExists(privacyGroupId2, bob); - lockPrivacyGroup(privacyGroupId1, alice); - lockPrivacyGroup(privacyGroupId2, bob); + lockPrivacyGroup(privacyGroupId1, alice, Credentials.create(alice.getTransactionSigningKey())); + lockPrivacyGroup(privacyGroupId2, bob, Credentials.create(bob.getTransactionSigningKey())); final BigInteger pendingTransactionFilterId = alice.execute(ethTransactions.newPendingTransactionsFilter()); @@ -413,8 +426,12 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { alice.execute(minerTransactions.minerStop()); alice.getBesu().verify(ethConditions.miningStatus(false)); - final String aliceAddHash = addMembersToPrivacyGroup(privacyGroupId1, alice, charlie); - final String bobAddHash = addMembersToPrivacyGroup(privacyGroupId2, bob, alice); + final String aliceAddHash = + addMembersToPrivacyGroup( + privacyGroupId1, alice, Credentials.create(alice.getTransactionSigningKey()), charlie); + final String bobAddHash = + addMembersToPrivacyGroup( + privacyGroupId2, bob, Credentials.create(bob.getTransactionSigningKey()), alice); alice .getBesu() @@ -457,6 +474,7 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { * @return the id of the privacy group */ private String createOnChainPrivacyGroup(final PrivacyNode... members) { + final PrivacyNode groupCreator = members[0]; final CreateOnChainPrivacyGroupTransaction createTx = @@ -485,18 +503,21 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { private String addMembersToPrivacyGroup( final String privacyGroupId, final PrivacyNode nodeAddingMember, + final Credentials signer, final PrivacyNode... newMembers) { return nodeAddingMember.execute( - privacyTransactions.addToPrivacyGroup(privacyGroupId, nodeAddingMember, newMembers)); + privacyTransactions.addToPrivacyGroup( + privacyGroupId, nodeAddingMember, signer, newMembers)); } private String removeFromPrivacyGroup( final String privacyGroupId, final PrivacyNode nodeRemovingMember, + final Credentials signer, final PrivacyNode memberBeingRemoved) { return nodeRemovingMember.execute( privacyTransactions.removeFromPrivacyGroup( - privacyGroupId, nodeRemovingMember, memberBeingRemoved)); + privacyGroupId, nodeRemovingMember, signer, memberBeingRemoved)); } private String calculateAddParticipantPMTHash( @@ -564,9 +585,10 @@ public class OnChainPrivacyAcceptanceTest extends PrivacyAcceptanceTestBase { * * @return the hash of the lock privacy group transaction */ - private String lockPrivacyGroup(final String privacyGroupId, final PrivacyNode member) { + private String lockPrivacyGroup( + final String privacyGroupId, final PrivacyNode member, final Credentials signer) { return member.execute( - privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, member)); + privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, member, signer)); } private ExpectValidOnChainPrivacyGroupCreated onChainPrivacyGroupExists( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyGroupAcceptanceTest.java index 15edc91c11..4afee1e305 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyGroupAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/PrivacyGroupAcceptanceTest.java @@ -18,10 +18,14 @@ import static org.assertj.core.api.Assertions.assertThat; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode; +import org.hyperledger.besu.tests.web3j.generated.EventEmitter; + +import java.math.BigInteger; import org.junit.Before; import org.junit.Test; import org.web3j.protocol.besu.response.privacy.PrivacyGroup; +import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt; import org.web3j.utils.Base64String; public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase { @@ -124,4 +128,77 @@ public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase { bob.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected)); } + + @Test + public void canInteractWithMultiplePrivacyGroups() { + final String privacyGroupIdABC = + alice.execute(privacyTransactions.createPrivacyGroup(null, null, alice, bob, charlie)); + + final EventEmitter firstEventEmitter = + alice.execute( + privateContractTransactions.createSmartContractWithPrivacyGroupId( + EventEmitter.class, + alice.getTransactionSigningKey(), + POW_CHAIN_ID, + alice.getEnclaveKey(), + privacyGroupIdABC)); + + // charlie interacts with contract + final String firstTransactionHash = + charlie.execute( + privateContractTransactions.callSmartContractWithPrivacyGroupId( + firstEventEmitter.getContractAddress(), + firstEventEmitter.store(BigInteger.ONE).encodeFunctionCall(), + charlie.getTransactionSigningKey(), + POW_CHAIN_ID, + charlie.getEnclaveKey(), + privacyGroupIdABC)); + + // alice gets receipt from charlie's interaction + final PrivateTransactionReceipt firstExpectedReceipt = + alice.execute(privacyTransactions.getPrivateTransactionReceipt(firstTransactionHash)); + + // verify bob and charlie have access to the same receipt + bob.verify( + privateTransactionVerifier.validPrivateTransactionReceipt( + firstTransactionHash, firstExpectedReceipt)); + charlie.verify( + privateTransactionVerifier.validPrivateTransactionReceipt( + firstTransactionHash, firstExpectedReceipt)); + + // alice deploys second contract + final String privacyGroupIdAB = + alice.execute(privacyTransactions.createPrivacyGroup(null, null, alice, bob)); + + final EventEmitter secondEventEmitter = + alice.execute( + privateContractTransactions.createSmartContractWithPrivacyGroupId( + EventEmitter.class, + alice.getTransactionSigningKey(), + POW_CHAIN_ID, + alice.getEnclaveKey(), + privacyGroupIdAB)); + + // bob interacts with contract + final String secondTransactionHash = + bob.execute( + privateContractTransactions.callSmartContractWithPrivacyGroupId( + secondEventEmitter.getContractAddress(), + secondEventEmitter.store(BigInteger.ONE).encodeFunctionCall(), + bob.getTransactionSigningKey(), + POW_CHAIN_ID, + bob.getEnclaveKey(), + privacyGroupIdAB)); + + // alice gets receipt from bob's interaction + final PrivateTransactionReceipt secondExpectedReceipt = + alice.execute(privacyTransactions.getPrivateTransactionReceipt(secondTransactionHash)); + + bob.verify( + privateTransactionVerifier.validPrivateTransactionReceipt( + secondTransactionHash, secondExpectedReceipt)); + + // charlie cannot see the receipt + charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(secondTransactionHash)); + } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyGroupTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyGroupTest.java index b2a346e2bd..53076db2ca 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyGroupTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyGroupTest.java @@ -20,11 +20,14 @@ import org.hyperledger.besu.privacy.contracts.generated.DefaultOnChainPrivacyGro import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; +import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.Before; import org.junit.Test; +import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.protocol.exceptions.TransactionException; import org.web3j.utils.Base64String; @@ -37,14 +40,13 @@ public class PrivacyGroupTest extends AcceptanceTestBase { Base64String.wrap("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="); private final Base64String thirdParticipant = Base64String.wrap("Jo2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="); - private DefaultOnChainPrivacyGroupManagementContract privacyGroup; + private DefaultOnChainPrivacyGroupManagementContract defaultPrivacyGroupManagementContract; - private static final String RAW_FIRST_PARTICIPANT = - "0x0b0235be035695b4cc4b0941e60551d7a19cf30603db5bfc23e5ac43a56f57f25f75486a"; + private static final String RAW_FIRST_PARTICIPANT = "0x5aa68ac0"; private static final String RAW_ADD_PARTICIPANT = - "0xf744b089035695b4cc4b0941e60551d7a19cf30603db5bfc23e5ac43a56f57f25f75486a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000012a8d9b56a0fe9cd94d60be4413bcb721d3a7be27ed8e28b3a6346df874ee141b"; + "0xb4926e25000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000012a8d9b56a0fe9cd94d60be4413bcb721d3a7be27ed8e28b3a6346df874ee141b"; private static final String RAW_REMOVE_PARTICIPANT = - "0x61544c91035695b4cc4b0941e60551d7a19cf30603db5bfc23e5ac43a56f57f25f75486a2a8d9b56a0fe9cd94d60be4413bcb721d3a7be27ed8e28b3a6346df874ee141b"; + "0xfd0177972a8d9b56a0fe9cd94d60be4413bcb721d3a7be27ed8e28b3a6346df874ee141b"; private static final String RAW_LOCK = "0xf83d08ba"; private static final String RAW_UNLOCK = "0xa69df4b5"; private static final String RAW_CAN_EXECUTE = "0x78b90337"; @@ -56,7 +58,7 @@ public class PrivacyGroupTest extends AcceptanceTestBase { public void setUp() throws Exception { minerNode = besu.createMinerNode("node"); cluster.start(minerNode); - privacyGroup = + defaultPrivacyGroupManagementContract = minerNode.execute( contractTransactions.createSmartContract( DefaultOnChainPrivacyGroupManagementContract.class)); @@ -65,36 +67,43 @@ public class PrivacyGroupTest extends AcceptanceTestBase { @Test public void rlp() throws Exception { final String contractAddress = "0x42699a7612a82f1d9c36148af9c77354759b210b"; - assertThat(privacyGroup.isValid()).isEqualTo(true); - contractVerifier.validTransactionReceipt(contractAddress).verify(privacyGroup); + assertThat(defaultPrivacyGroupManagementContract.isValid()).isEqualTo(true); + contractVerifier + .validTransactionReceipt(contractAddress) + .verify(defaultPrivacyGroupManagementContract); // 0x0b0235be assertThat(RAW_FIRST_PARTICIPANT) - .isEqualTo(privacyGroup.getParticipants(firstParticipant.raw()).encodeFunctionCall()); + .isEqualTo(defaultPrivacyGroupManagementContract.getParticipants().encodeFunctionCall()); // 0xf744b089 assertThat(RAW_ADD_PARTICIPANT) .isEqualTo( - privacyGroup - .addParticipants( - firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(secondParticipant.raw())) .encodeFunctionCall()); // 0xf744b089 assertThat(RAW_REMOVE_PARTICIPANT) .isEqualTo( - privacyGroup - .removeParticipant(firstParticipant.raw(), secondParticipant.raw()) + defaultPrivacyGroupManagementContract + .removeParticipant(secondParticipant.raw()) .encodeFunctionCall()); - assertThat(RAW_LOCK).isEqualTo(privacyGroup.lock().encodeFunctionCall()); - assertThat(RAW_UNLOCK).isEqualTo(privacyGroup.unlock().encodeFunctionCall()); - assertThat(RAW_CAN_EXECUTE).isEqualTo(privacyGroup.canExecute().encodeFunctionCall()); - assertThat(RAW_GET_VERSION).isEqualTo(privacyGroup.getVersion().encodeFunctionCall()); + assertThat(RAW_LOCK) + .isEqualTo(defaultPrivacyGroupManagementContract.lock().encodeFunctionCall()); + assertThat(RAW_UNLOCK) + .isEqualTo(defaultPrivacyGroupManagementContract.unlock().encodeFunctionCall()); + assertThat(RAW_CAN_EXECUTE) + .isEqualTo(defaultPrivacyGroupManagementContract.canExecute().encodeFunctionCall()); + assertThat(RAW_GET_VERSION) + .isEqualTo(defaultPrivacyGroupManagementContract.getVersion().encodeFunctionCall()); } @Test public void canInitiallyAddParticipants() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) - .send(); - final List participants = privacyGroup.getParticipants(firstParticipant.raw()).send(); + final RemoteFunctionCall transactionReceiptRemoteFunctionCall = + defaultPrivacyGroupManagementContract.addParticipants( + Arrays.asList(firstParticipant.raw(), secondParticipant.raw())); + transactionReceiptRemoteFunctionCall.send(); + final List participants = + defaultPrivacyGroupManagementContract.getParticipants().send(); assertThat(participants.size()).isEqualTo(2); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(secondParticipant.raw()).isEqualTo(participants.get(1)); @@ -102,51 +111,50 @@ public class PrivacyGroupTest extends AcceptanceTestBase { @Test public void canRemoveParticipant() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Arrays.asList(firstParticipant.raw(), secondParticipant.raw())) .send(); - final List participants = privacyGroup.getParticipants(firstParticipant.raw()).send(); + final List participants = + defaultPrivacyGroupManagementContract.getParticipants().send(); assertThat(participants.size()).isEqualTo(2); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(secondParticipant.raw()).isEqualTo(participants.get(1)); - privacyGroup.removeParticipant(firstParticipant.raw(), secondParticipant.raw()).send(); + defaultPrivacyGroupManagementContract.removeParticipant(secondParticipant.raw()).send(); final List participantsAfterRemove = - privacyGroup.getParticipants(firstParticipant.raw()).send(); + defaultPrivacyGroupManagementContract.getParticipants().send(); assertThat(participantsAfterRemove.size()).isEqualTo(1); assertThat(firstParticipant.raw()).isEqualTo(participantsAfterRemove.get(0)); } @Test(expected = TransactionException.class) public void cannotAddToContractWhenNotLocked() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(thirdParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(thirdParticipant.raw())) .send(); - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(secondParticipant.raw())) .send(); } @Test - public void ensureContractIsNotLockedAfterDeploy() throws Exception { - privacyGroup.unlock().send(); - assertThat(privacyGroup.canExecute().send()).isTrue(); + public void ensureContractIsLockedAfterDeploy() throws Exception { + assertThat(defaultPrivacyGroupManagementContract.canExecute().send()).isFalse(); } @Test public void ensurePrivacyGroupVersionIsAlwaysDifferent() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(secondParticipant.raw())) .send(); - final byte[] version1 = privacyGroup.getVersion().send(); - privacyGroup.lock().send(); - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(thirdParticipant.raw())) + final byte[] version1 = defaultPrivacyGroupManagementContract.getVersion().send(); + defaultPrivacyGroupManagementContract.lock().send(); + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(thirdParticipant.raw())) .send(); - final byte[] version2 = privacyGroup.getVersion().send(); - privacyGroup.lock().send(); - privacyGroup.removeParticipant(firstParticipant.raw(), secondParticipant.raw()).send(); - final byte[] version3 = privacyGroup.getVersion().send(); + final byte[] version2 = defaultPrivacyGroupManagementContract.getVersion().send(); + defaultPrivacyGroupManagementContract.removeParticipant(secondParticipant.raw()).send(); + final byte[] version3 = defaultPrivacyGroupManagementContract.getVersion().send(); assertThat(version1).isNotEqualTo(version2); assertThat(version1).isNotEqualTo(version3); @@ -155,15 +163,16 @@ public class PrivacyGroupTest extends AcceptanceTestBase { @Test public void canAddTwiceToContractWhenCallLock() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(thirdParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Arrays.asList(firstParticipant.raw(), thirdParticipant.raw())) .send(); - privacyGroup.lock().send(); - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + defaultPrivacyGroupManagementContract.lock().send(); + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(secondParticipant.raw())) .send(); - final List participants = privacyGroup.getParticipants(firstParticipant.raw()).send(); + final List participants = + defaultPrivacyGroupManagementContract.getParticipants().send(); assertThat(participants.size()).isEqualTo(3); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(thirdParticipant.raw()).isEqualTo(participants.get(1)); @@ -172,10 +181,10 @@ public class PrivacyGroupTest extends AcceptanceTestBase { @Test(expected = TransactionException.class) public void cannotLockTwice() throws Exception { - privacyGroup - .addParticipants(firstParticipant.raw(), Collections.singletonList(thirdParticipant.raw())) + defaultPrivacyGroupManagementContract + .addParticipants(Collections.singletonList(thirdParticipant.raw())) .send(); - privacyGroup.lock().send(); - privacyGroup.lock().send(); + defaultPrivacyGroupManagementContract.lock().send(); + defaultPrivacyGroupManagementContract.lock().send(); } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyProxyTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyProxyTest.java index 4a3bd43eab..402d3ca80a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyProxyTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/web3j/privacy/contracts/PrivacyProxyTest.java @@ -15,18 +15,26 @@ package org.hyperledger.besu.tests.web3j.privacy.contracts; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.hyperledger.besu.privacy.contracts.generated.DefaultOnChainPrivacyGroupManagementContract; import org.hyperledger.besu.privacy.contracts.generated.OnChainPrivacyGroupManagementProxy; import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts; import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; +import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.web3j.crypto.Credentials; +import org.web3j.protocol.Web3j; +import org.web3j.protocol.exceptions.TransactionException; +import org.web3j.protocol.http.HttpService; +import org.web3j.tx.gas.DefaultGasProvider; import org.web3j.utils.Base64String; @SuppressWarnings("unchecked") @@ -40,25 +48,26 @@ public class PrivacyProxyTest extends AcceptanceTestBase { Base64String.wrap("Jo2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="); private OnChainPrivacyGroupManagementProxy onChainPrivacyGroupManagementProxy; - private static final String RAW_FIRST_PARTICIPANT = - "0x0b0235bef772b2ee55f016431cefe724a05814324bb96e9afdb73e338665a693d4653678"; + private static final String RAW_GET_PARTICIPANTS = "0x5aa68ac0"; private static final String RAW_ADD_PARTICIPANT = - "0xf744b089f772b2ee55f016431cefe724a05814324bb96e9afdb73e338665a693d465367800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000"; + "0xb4926e2500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"; private BesuNode minerNode; + private DefaultOnChainPrivacyGroupManagementContract defaultOnChainPrivacyGroupManagementContract; @Before public void setUp() throws Exception { minerNode = besu.createMinerNode("node"); cluster.start(minerNode); - DefaultOnChainPrivacyGroupManagementContract privacyGroup = + defaultOnChainPrivacyGroupManagementContract = minerNode.execute( contractTransactions.createSmartContract( DefaultOnChainPrivacyGroupManagementContract.class)); onChainPrivacyGroupManagementProxy = minerNode.execute( contractTransactions.createSmartContract( - OnChainPrivacyGroupManagementProxy.class, privacyGroup.getContractAddress())); + OnChainPrivacyGroupManagementProxy.class, + defaultOnChainPrivacyGroupManagementContract.getContractAddress())); } @Test @@ -67,47 +76,39 @@ public class PrivacyProxyTest extends AcceptanceTestBase { contractVerifier .validTransactionReceipt(onChainPrivacyGroupManagementProxy.getContractAddress()) .verify(onChainPrivacyGroupManagementProxy); - // 0x0b0235be - assertThat(RAW_FIRST_PARTICIPANT) - .isEqualTo( - onChainPrivacyGroupManagementProxy - .getParticipants(firstParticipant.raw()) - .encodeFunctionCall()); - // 0xf744b089 + assertThat(RAW_GET_PARTICIPANTS) + .isEqualTo(onChainPrivacyGroupManagementProxy.getParticipants().encodeFunctionCall()); assertThat(RAW_ADD_PARTICIPANT) .isEqualTo( onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.emptyList()) + .addParticipants(Collections.emptyList()) .encodeFunctionCall()); } @Ignore("return 0x which causes web3j to throw exception instead of return empty list") @Test public void deploysWithNoParticipant() throws Exception { - final List participants = - onChainPrivacyGroupManagementProxy.getParticipants(firstParticipant.raw()).send(); + final List participants = onChainPrivacyGroupManagementProxy.getParticipants().send(); assertThat(participants.size()).isEqualTo(0); } @Test public void canAddParticipants() throws Exception { onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + .addParticipants(Arrays.asList(firstParticipant.raw(), secondParticipant.raw())) .send(); - final List participants = - onChainPrivacyGroupManagementProxy.getParticipants(firstParticipant.raw()).send(); + final List participants = onChainPrivacyGroupManagementProxy.getParticipants().send(); assertThat(participants.size()).isEqualTo(2); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(secondParticipant.raw()).isEqualTo(participants.get(1)); } @Test - public void canUpgrade() throws Exception { + public void nonOwnerCannotUpgrade() throws Exception { onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + .addParticipants(Arrays.asList(firstParticipant.raw(), secondParticipant.raw())) .send(); - final List participants = - onChainPrivacyGroupManagementProxy.getParticipants(firstParticipant.raw()).send(); + final List participants = onChainPrivacyGroupManagementProxy.getParticipants().send(); assertThat(participants.size()).isEqualTo(2); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(secondParticipant.raw()).isEqualTo(participants.get(1)); @@ -117,12 +118,43 @@ public class PrivacyProxyTest extends AcceptanceTestBase { contractTransactions.createSmartContract( DefaultOnChainPrivacyGroupManagementContract.class)); - onChainPrivacyGroupManagementProxy.upgradeTo(upgradedContract.getContractAddress()).send(); + final HttpService httpService = + new HttpService( + "http://" + minerNode.getHostName() + ":" + minerNode.getJsonRpcSocketPort().get()); + final Web3j web3j = Web3j.build(httpService); + + // load the proxy contract, use it with another signer + final OnChainPrivacyGroupManagementProxy proxyContractAccount2 = + OnChainPrivacyGroupManagementProxy.load( + onChainPrivacyGroupManagementProxy.getContractAddress(), + web3j, + Credentials.create(Accounts.GENESIS_ACCOUNT_TWO_PRIVATE_KEY), + new DefaultGasProvider()); + // contract is the proxy contract and uses genesis account 2. It should not be able to upgrade + // the contract, because it is not the owner of "upgradedContract" + assertThatThrownBy( + () -> proxyContractAccount2.upgradeTo(upgradedContract.getContractAddress()).send()) + .isInstanceOf(TransactionException.class); + } + + @Test + public void ownerCanUpgrade() throws Exception { onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + .addParticipants(Arrays.asList(firstParticipant.raw(), secondParticipant.raw())) .send(); + final List participants = onChainPrivacyGroupManagementProxy.getParticipants().send(); + assertThat(participants.size()).isEqualTo(2); + assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); + assertThat(secondParticipant.raw()).isEqualTo(participants.get(1)); + + final DefaultOnChainPrivacyGroupManagementContract upgradedContract = + minerNode.execute( + contractTransactions.createSmartContract( + DefaultOnChainPrivacyGroupManagementContract.class)); + + onChainPrivacyGroupManagementProxy.upgradeTo(upgradedContract.getContractAddress()).send(); final List participantsAfterUpgrade = - onChainPrivacyGroupManagementProxy.getParticipants(firstParticipant.raw()).send(); + onChainPrivacyGroupManagementProxy.getParticipants().send(); assertThat(participantsAfterUpgrade.size()).isEqualTo(2); assertThat(firstParticipant.raw()).isEqualTo(participantsAfterUpgrade.get(0)); assertThat(secondParticipant.raw()).isEqualTo(participantsAfterUpgrade.get(1)); @@ -131,14 +163,13 @@ public class PrivacyProxyTest extends AcceptanceTestBase { @Test public void canAddTwiceToContractWhenCallLock() throws Exception { onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.singletonList(thirdParticipant.raw())) + .addParticipants(Arrays.asList(firstParticipant.raw(), thirdParticipant.raw())) .send(); onChainPrivacyGroupManagementProxy.lock().send(); onChainPrivacyGroupManagementProxy - .addParticipants(firstParticipant.raw(), Collections.singletonList(secondParticipant.raw())) + .addParticipants(Collections.singletonList(secondParticipant.raw())) .send(); - final List participants = - onChainPrivacyGroupManagementProxy.getParticipants(firstParticipant.raw()).send(); + final List participants = onChainPrivacyGroupManagementProxy.getParticipants().send(); assertThat(participants.size()).isEqualTo(3); assertThat(firstParticipant.raw()).isEqualTo(participants.get(0)); assertThat(thirdParticipant.raw()).isEqualTo(participants.get(1)); diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java index cd748cd8fa..20132b2740 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java @@ -16,6 +16,9 @@ package org.hyperledger.besu; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver.EMPTY_ROOT_HASH; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.controller.BesuController; @@ -24,6 +27,7 @@ import org.hyperledger.besu.crypto.NodeKeyUtils; import org.hyperledger.besu.crypto.SECP256K1; import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.EnclaveFactory; +import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.enclave.types.SendResponse; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; @@ -42,6 +46,7 @@ import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; +import org.hyperledger.besu.ethereum.privacy.DefaultPrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.privacy.Restriction; @@ -69,6 +74,7 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import io.vertx.core.Vertx; @@ -130,6 +136,7 @@ public class PrivacyReorgTest { private OrionTestHarness enclave; private PrivateStateRootResolver privateStateRootResolver; private PrivacyParameters privacyParameters; + private DefaultPrivacyController privacyController; @Before public void setUp() throws IOException { @@ -153,6 +160,9 @@ public class PrivacyReorgTest { .setEnclaveFactory(new EnclaveFactory(Vertx.vertx())) .build(); privacyParameters.setEnclavePublicKey(ENCLAVE_PUBLIC_KEY.toBase64String()); + privacyController = mock(DefaultPrivacyController.class); + when(privacyController.retrieveOffChainPrivacyGroup(any(), any())) + .thenReturn(Optional.of(new PrivacyGroup())); privateStateRootResolver = new PrivateStateRootResolver(privacyParameters.getPrivateStateStorage()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java index 3e525410db..ee8233c1c1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransaction.java @@ -93,10 +93,9 @@ public class EeaSendRawTransaction implements JsonRpcMethod { return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_ID_NOT_AVAILABLE); } maybePrivacyGroup = - privacyController.retrieveOnChainPrivacyGroup( - maybePrivacyGroupId.get(), enclavePublicKey); - if (maybePrivacyGroup.isEmpty() - && !privacyController.isGroupAdditionTransaction(privateTransaction)) { + privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers( + maybePrivacyGroupId.get(), enclavePublicKey, privateTransaction); + if (maybePrivacyGroup.isEmpty()) { return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST); } } else { // !onchainPirvacyGroupEnabled diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java index 8c54449683..a12814d6ac 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivDistributeRawTransaction.java @@ -88,10 +88,9 @@ public class PrivDistributeRawTransaction implements JsonRpcMethod { return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_ID_NOT_AVAILABLE); } maybePrivacyGroup = - privacyController.retrieveOnChainPrivacyGroup( - maybePrivacyGroupId.get(), enclavePublicKey); - if (maybePrivacyGroup.isEmpty() - && !privacyController.isGroupAdditionTransaction(privateTransaction)) { + privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers( + maybePrivacyGroupId.get(), enclavePublicKey, privateTransaction); + if (maybePrivacyGroup.isEmpty()) { return new JsonRpcErrorResponse(id, JsonRpcError.ONCHAIN_PRIVACY_GROUP_DOES_NOT_EXIST); } } else { // !onchainPirvacyGroupEnabled diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java index f574dcf453..6a4169dae2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/EeaSendRawTransactionTest.java @@ -50,7 +50,7 @@ import org.hyperledger.besu.ethereum.privacy.Restriction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import java.math.BigInteger; -import java.util.Collections; +import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -255,10 +255,12 @@ public class EeaSendRawTransactionTest { when(privacyController.validatePrivateTransaction( any(PrivateTransaction.class), any(String.class))) .thenReturn(ValidationResult.valid()); - when(privacyController.retrieveOnChainPrivacyGroup(any(Bytes.class), any(String.class))) - .thenReturn( - Optional.of( - new PrivacyGroup("", PrivacyGroup.Type.ONCHAIN, "", "", Collections.emptyList()))); + final Optional optionalPrivacyGroup = + Optional.of( + new PrivacyGroup( + "", PrivacyGroup.Type.ONCHAIN, "", "", Arrays.asList(ENCLAVE_PUBLIC_KEY))); + when(privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers(any(), any(), any())) + .thenReturn(optionalPrivacyGroup); when(privacyController.buildAndSendAddPayload( any(PrivateTransaction.class), any(Bytes32.class), any(String.class))) .thenReturn(Optional.of(ENCLAVE_PUBLIC_KEY)); @@ -321,7 +323,7 @@ public class EeaSendRawTransactionTest { new EeaSendRawTransaction( transactionPool, privacyController, enclavePublicKeyProvider, true); - when(privacyController.retrieveOnChainPrivacyGroup(any(Bytes.class), any(String.class))) + when(privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers(any(), any(), any())) .thenReturn(Optional.empty()); final JsonRpcRequestContext request = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistries.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistries.java index 7be4b342ba..b492b225e3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistries.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetPrecompiledContractRegistries.java @@ -183,7 +183,8 @@ public abstract class MainnetPrecompiledContractRegistries { accountVersion, new PrivacyPrecompiledContract( precompiledContractConfiguration.getGasCalculator(), - precompiledContractConfiguration.getPrivacyParameters())); + precompiledContractConfiguration.getPrivacyParameters(), + "Privacy")); } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java index f4fbc32bb6..5f10d25667 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContract.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet.precompiles.privacy; import static org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver.EMPTY_ROOT_HASH; import org.hyperledger.besu.crypto.SECP256K1; +import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.EnclaveClientException; import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -31,6 +32,7 @@ import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.WorldUpdater; import org.hyperledger.besu.ethereum.debug.TraceOptions; +import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.Restriction; @@ -38,11 +40,17 @@ import org.hyperledger.besu.ethereum.privacy.VersionedPrivateTransaction; import org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement; import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.vm.GasCalculator; import org.hyperledger.besu.ethereum.vm.MessageFrame; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; +import java.util.List; import java.util.Optional; import org.apache.logging.log4j.LogManager; @@ -61,12 +69,21 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac public OnChainPrivacyPrecompiledContract( final GasCalculator gasCalculator, final PrivacyParameters privacyParameters) { + super(gasCalculator, privacyParameters, "OnChainPrivacy"); + } + + public OnChainPrivacyPrecompiledContract( + final GasCalculator gasCalculator, + final Enclave enclave, + final WorldStateArchive worldStateArchive, + final PrivateStateStorage privateStateStorage, + final PrivateStateRootResolver privateStateRootResolver) { super( gasCalculator, - privacyParameters.getEnclave(), - privacyParameters.getPrivateWorldStateArchive(), - privacyParameters.getPrivateStateStorage(), - privacyParameters.getPrivateStateRootResolver(), + enclave, + worldStateArchive, + privateStateStorage, + privateStateRootResolver, "OnChainPrivacy"); } @@ -97,13 +114,11 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac final PrivateTransaction privateTransaction = versionedPrivateTransaction.getPrivateTransaction(); - if (!privateFromMatchesSenderKey( - privateTransaction.getPrivateFrom(), receiveResponse.getSenderKey())) { + final Bytes privateFrom = privateTransaction.getPrivateFrom(); + if (!privateFromMatchesSenderKey(privateFrom, receiveResponse.getSenderKey())) { return Bytes.EMPTY; } - final Bytes32 version = versionedPrivateTransaction.getVersion(); - final Optional maybeGroupId = privateTransaction.getPrivacyGroupId(); if (maybeGroupId.isEmpty()) { return Bytes.EMPTY; @@ -124,22 +139,23 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater(); + final WorldUpdater publicWorldState = messageFrame.getWorldState(); + final Blockchain blockchain = messageFrame.getBlockchain(); + maybeInjectDefaultManagementAndProxy( lastRootHash, disposablePrivateState, privateWorldStateUpdater); - final Blockchain blockchain = messageFrame.getBlockchain(); - final WorldUpdater publicWorldState = messageFrame.getWorldState(); - if (!canExecute( messageFrame, currentBlockHeader, privateTransaction, - version, + versionedPrivateTransaction.getVersion(), publicWorldState, privacyGroupId, blockchain, disposablePrivateState, - privateWorldStateUpdater)) { + privateWorldStateUpdater, + privateFrom)) { return Bytes.EMPTY; } @@ -164,7 +180,6 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac persistPrivateState( pmtHash, currentBlockHash, - privateTransaction, privacyGroupId, disposablePrivateState, privateWorldStateUpdater, @@ -183,13 +198,14 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac final Bytes32 privacyGroupId, final Blockchain blockchain, final MutableWorldState disposablePrivateState, - final WorldUpdater privateWorldStateUpdater) { + final WorldUpdater privateWorldStateUpdater, + final Bytes privateFrom) { final boolean isAddingParticipant = privateTransaction .getPayload() .toHexString() - .startsWith(OnChainGroupManagement.ADD_TO_GROUP_METHOD_SIGNATURE.toHexString()); + .startsWith(OnChainGroupManagement.ADD_PARTICIPANTS_METHOD_SIGNATURE.toHexString()); final boolean isPrivacyGroupLocked = isContractLocked( @@ -226,11 +242,97 @@ public class OnChainPrivacyPrecompiledContract extends PrivacyPrecompiledContrac blockchain, disposablePrivateState, privateWorldStateUpdater)) { + LOG.debug( + "Privacy group version mismatch while trying to execute transaction with commitment {}", + messageFrame.getTransactionHash()); + return false; + } + + if (!isMemberOfPrivacyGroup( + isAddingParticipant, + privateTransaction, + privateFrom, + privacyGroupId, + messageFrame, + currentBlockHeader, + publicWorldState, + blockchain, + disposablePrivateState, + privateWorldStateUpdater)) { + LOG.debug( + "PrivateTransaction with hash {} cannot execute in privacy group {} because privateFrom {} is not a member.", + messageFrame.getTransactionHash(), + privacyGroupId.toBase64String(), + privateFrom.toBase64String()); return false; } + return true; } + private boolean isMemberOfPrivacyGroup( + final boolean isAddingParticipant, + final PrivateTransaction privateTransaction, + final Bytes privateFrom, + final Bytes32 privacyGroupId, + final MessageFrame messageFrame, + final ProcessableBlockHeader currentBlockHeader, + final WorldUpdater publicWorldState, + final Blockchain blockchain, + final MutableWorldState disposablePrivateState, + final WorldUpdater privateWorldStateUpdater) { + final PrivateTransactionProcessor.Result result = + simulateTransaction( + messageFrame, + currentBlockHeader, + publicWorldState, + privacyGroupId, + blockchain, + disposablePrivateState, + privateWorldStateUpdater, + OnChainGroupManagement.GET_PARTICIPANTS_METHOD_SIGNATURE); + final List list = getMembersFromResult(result); + List participantsFromParameter = Collections.emptyList(); + if (list.isEmpty() && isAddingParticipant) { + // creating a new group, so we are checking whether the privateFrom is one of the members of + // the new group + participantsFromParameter = getParticipantsFromParameter(privateTransaction.getPayload()); + } + return list.contains(privateFrom) + || participantsFromParameter.contains(privateFrom.toBase64String()); + } + + List getMembersFromResult(final PrivateTransactionProcessor.Result result) { + List list = Collections.emptyList(); + if (result != null && result.isSuccessful()) { + final RLPInput rlpInput = RLP.input(result.getOutput()); + if (rlpInput.nextSize() > 0) { + list = decodeList(rlpInput.raw()); + } + } + return list; + } + + // TODO: this method is copied from DefaultPrivacyController. Fix the duplication in a separate GI + private List getParticipantsFromParameter(final Bytes input) { + final List participants = new ArrayList<>(); + final Bytes mungedParticipants = input.slice(4 + 32 + 32); + for (int i = 0; i <= mungedParticipants.size() - 32; i += 32) { + participants.add(mungedParticipants.slice(i, 32).toBase64String()); + } + return participants; + } + + private List decodeList(final Bytes rlpEncodedList) { + final ArrayList decodedElements = new ArrayList<>(); + // first 32 bytes is dynamic list offset + final UInt256 lengthOfList = UInt256.fromBytes(rlpEncodedList.slice(32, 32)); // length of list + for (int i = 0; i < lengthOfList.toLong(); ++i) { + decodedElements.add(Bytes.wrap(rlpEncodedList.slice(64 + (32 * i), 32))); // participant + } + return decodedElements; + } + protected boolean isContractLocked( final MessageFrame messageFrame, final ProcessableBlockHeader currentBlockHeader, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java index 18bb1c5037..ce93ca44f9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java @@ -60,14 +60,16 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract { private static final Logger LOG = LogManager.getLogger(); public PrivacyPrecompiledContract( - final GasCalculator gasCalculator, final PrivacyParameters privacyParameters) { + final GasCalculator gasCalculator, + final PrivacyParameters privacyParameters, + final String name) { this( gasCalculator, privacyParameters.getEnclave(), privacyParameters.getPrivateWorldStateArchive(), privacyParameters.getPrivateStateStorage(), privacyParameters.getPrivateStateRootResolver(), - "Privacy"); + name); } @VisibleForTesting @@ -134,14 +136,33 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract { final PrivateTransaction privateTransaction = PrivateTransaction.readFrom(bytesValueRLPInput.readAsRlp()); - if (!privateFromMatchesSenderKey( - privateTransaction.getPrivateFrom(), receiveResponse.getSenderKey())) { + final Bytes privateFrom = privateTransaction.getPrivateFrom(); + if (!privateFromMatchesSenderKey(privateFrom, receiveResponse.getSenderKey())) { return Bytes.EMPTY; } final Bytes32 privacyGroupId = Bytes32.wrap(Bytes.fromBase64String(receiveResponse.getPrivacyGroupId())); + try { + if (privateTransaction.getPrivateFor().isEmpty() + && !enclave + .retrievePrivacyGroup(privacyGroupId.toBase64String()) + .getMembers() + .contains(privateFrom.toBase64String())) { + return Bytes.EMPTY; + } + } catch (final EnclaveClientException e) { + // This exception is thrown when the privacy group can not be found + return Bytes.EMPTY; + } catch (final EnclaveServerException e) { + LOG.error("Enclave is responding with an error, perhaps it has a misconfiguration?", e); + throw e; + } catch (final EnclaveIOException e) { + LOG.error("Can not communicate with enclave, is it up?", e); + throw e; + } + LOG.debug("Processing private transaction {} in privacy group {}", pmtHash, privacyGroupId); final Hash currentBlockHash = ((BlockHeader) messageFrame.getBlockHeader()).getHash(); @@ -175,7 +196,6 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract { persistPrivateState( pmtHash, currentBlockHash, - privateTransaction, privacyGroupId, disposablePrivateState, privateWorldStateUpdater, @@ -188,7 +208,6 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract { void persistPrivateState( final Hash commitmentHash, final Hash currentBlockHash, - final PrivateTransaction privateTransaction, final Bytes32 privacyGroupId, final MutableWorldState disposablePrivateState, final WorldUpdater privateWorldStateUpdater, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/DefaultPrivacyController.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/DefaultPrivacyController.java index b684a75c05..9edc8591b2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/DefaultPrivacyController.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/DefaultPrivacyController.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.privacy; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.ADD_TO_GROUP_METHOD_SIGNATURE; +import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.ADD_PARTICIPANTS_METHOD_SIGNATURE; import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.GET_PARTICIPANTS_METHOD_SIGNATURE; import static org.hyperledger.besu.ethereum.privacy.group.OnChainGroupManagement.GET_VERSION_METHOD_SIGNATURE; @@ -272,8 +272,7 @@ public class DefaultPrivacyController implements PrivacyController { .keySet() .forEach( c -> { - final Optional maybePrivacyGroup = - retrieveOnChainPrivacyGroup(c, enclavePublicKey); + final Optional maybePrivacyGroup = retrieveOnChainPrivacyGroup(c); if (maybePrivacyGroup.isPresent() && maybePrivacyGroup.get().getMembers().containsAll(addresses)) { privacyGroups.add(maybePrivacyGroup.get()); @@ -282,15 +281,11 @@ public class DefaultPrivacyController implements PrivacyController { return privacyGroups; } - @Override - public Optional retrieveOnChainPrivacyGroup( - final Bytes privacyGroupId, final String enclavePublicKey) { + public Optional retrieveOnChainPrivacyGroup(final Bytes privacyGroupId) { // get the privateFor list from the management contract final Optional privateTransactionSimulatorResultOptional = privateTransactionSimulator.process( - privacyGroupId.toBase64String(), - buildCallParams( - Bytes.fromBase64String(enclavePublicKey), GET_PARTICIPANTS_METHOD_SIGNATURE)); + privacyGroupId.toBase64String(), buildCallParams(GET_PARTICIPANTS_METHOD_SIGNATURE)); if (privateTransactionSimulatorResultOptional.isPresent() && privateTransactionSimulatorResultOptional.get().isSuccessful()) { @@ -307,8 +302,45 @@ public class DefaultPrivacyController implements PrivacyController { } else { return Optional.empty(); } + } else { + return Optional.empty(); + } + } + + @Override + public Optional retrieveOnChainPrivacyGroupWithToBeAddedMembers( + final Bytes privacyGroupId, + final String enclavePublicKey, + final PrivateTransaction privateTransaction) { + // get the privateFor list from the management contract + final Optional privateTransactionSimulatorResultOptional = + privateTransactionSimulator.process( + privacyGroupId.toBase64String(), buildCallParams(GET_PARTICIPANTS_METHOD_SIGNATURE)); + + final List members = new ArrayList<>(); + if (privateTransactionSimulatorResultOptional.isPresent() + && privateTransactionSimulatorResultOptional.get().isSuccessful()) { + final RLPInput rlpInput = + RLP.input(privateTransactionSimulatorResultOptional.get().getOutput()); + if (rlpInput.nextSize() > 0) { + members.addAll(decodeList(rlpInput.raw())); + if (!members.contains(enclavePublicKey)) { + return Optional.empty(); + } + } + } + if (isGroupAdditionTransaction(privateTransaction)) { + final List participantsFromParameter = + getParticipantsFromParameter(privateTransaction.getPayload()); + members.addAll(participantsFromParameter); + } + if (members.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of( + new PrivacyGroup( + privacyGroupId.toBase64String(), PrivacyGroup.Type.ONCHAIN, "", "", members)); } - return Optional.empty(); } private List decodeList(final Bytes rlpEncodedList) { @@ -324,21 +356,16 @@ public class DefaultPrivacyController implements PrivacyController { private List getParticipantsFromParameter(final Bytes input) { final List participants = new ArrayList<>(); - final Bytes mungedParticipants = input.slice(4 + 32 + 32 + 32); + final Bytes mungedParticipants = input.slice(4 + 32 + 32); for (int i = 0; i <= mungedParticipants.size() - 32; i += 32) { participants.add(mungedParticipants.slice(i, 32).toBase64String()); } return participants; } - private CallParameter buildCallParams(final Bytes enclavePublicKey, final Bytes methodCall) { + private CallParameter buildCallParams(final Bytes methodCall) { return new CallParameter( - Address.ZERO, - Address.ONCHAIN_PRIVACY_PROXY, - 3000000, - Wei.of(1000), - Wei.ZERO, - Bytes.concatenate(methodCall, enclavePublicKey)); + Address.ZERO, Address.ONCHAIN_PRIVACY_PROXY, 3000000, Wei.of(1000), Wei.ZERO, methodCall); } private List buildTransactionMetadataList( @@ -411,7 +438,7 @@ public class DefaultPrivacyController implements PrivacyController { && privateTransaction .getPayload() .toHexString() - .startsWith(ADD_TO_GROUP_METHOD_SIGNATURE.toHexString()); + .startsWith(ADD_PARTICIPANTS_METHOD_SIGNATURE.toHexString()); } @Override @@ -448,23 +475,21 @@ public class DefaultPrivacyController implements PrivacyController { final Optional maybePrivacyGroup) { final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); - if (maybePrivacyGroup.isPresent() || isGroupAdditionTransaction(privateTransaction)) { - if (isGroupAdditionTransaction(privateTransaction) - || maybePrivacyGroup.get().getType() == PrivacyGroup.Type.ONCHAIN) { + if (maybePrivacyGroup.isPresent()) { + final PrivacyGroup privacyGroup = maybePrivacyGroup.get(); + if (privacyGroup.getType() == PrivacyGroup.Type.ONCHAIN) { // onchain privacy group final Optional result = privateTransactionSimulator.process( privateTransaction.getPrivacyGroupId().get().toBase64String(), - buildCallParams( - Bytes.fromBase64String(enclavePublicKey), GET_VERSION_METHOD_SIGNATURE)); + buildCallParams(GET_VERSION_METHOD_SIGNATURE)); new VersionedPrivateTransaction(privateTransaction, result).writeTo(rlpOutput); - final List onChainPrivateFor = - resolveOnChainPrivateFor(privateTransaction, maybePrivacyGroup); + final List onChainPrivateFor = privacyGroup.getMembers(); return enclave.send( rlpOutput.encoded().toBase64String(), privateTransaction.getPrivateFrom().toBase64String(), onChainPrivateFor); - } else if (maybePrivacyGroup.get().getType() == PrivacyGroup.Type.PANTHEON) { + } else if (privacyGroup.getType() == PrivacyGroup.Type.PANTHEON) { // offchain privacy group privateTransaction.writeTo(rlpOutput); return enclave.send( @@ -499,18 +524,6 @@ public class DefaultPrivacyController implements PrivacyController { return privateFor; } - private List resolveOnChainPrivateFor( - final PrivateTransaction privateTransaction, final Optional privacyGroup) { - final ArrayList privateFor = new ArrayList<>(); - if (isGroupAdditionTransaction(privateTransaction)) { - privateFor.addAll(getParticipantsFromParameter(privateTransaction.getPayload())); - } - if (privacyGroup.isPresent()) { - privateFor.addAll(privacyGroup.get().getMembers()); - } - return privateFor; - } - @Override public void verifyPrivacyGroupContainsEnclavePublicKey( final String privacyGroupId, final String enclavePublicKey) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyController.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyController.java index baa259a47f..2cc7dc8d93 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyController.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyController.java @@ -230,15 +230,15 @@ public class MultiTenancyPrivacyController implements PrivacyController { } @Override - public Optional retrieveOnChainPrivacyGroup( - final Bytes privacyGroupId, final String enclavePublicKey) { + public Optional retrieveOnChainPrivacyGroupWithToBeAddedMembers( + final Bytes privacyGroupId, + final String enclavePublicKey, + final PrivateTransaction privateTransaction) { final Optional maybePrivacyGroup = - privacyController.retrieveOnChainPrivacyGroup(privacyGroupId, enclavePublicKey); - if (maybePrivacyGroup.isPresent() - && !maybePrivacyGroup.get().getMembers().contains(enclavePublicKey)) { - throw new MultiTenancyValidationException( - "Privacy group must contain the enclave public key"); - } + privacyController.retrieveOnChainPrivacyGroupWithToBeAddedMembers( + privacyGroupId, enclavePublicKey, privateTransaction); + // The check that the enclavePublicKey is a member (if the group already exists) is done in the + // DefaultPrivacyController. return maybePrivacyGroup; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java index 252765079f..10c5d6f855 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivacyController.java @@ -83,7 +83,8 @@ public interface PrivacyController { final Hash blockHash, final String enclavePublicKey); - Optional retrieveOnChainPrivacyGroup(Bytes privacyGroupId, String enclavePublicKey); + Optional retrieveOnChainPrivacyGroupWithToBeAddedMembers( + Bytes privacyGroupId, String enclavePublicKey, final PrivateTransaction privateTransaction); List retrieveAddBlob(String addDataKey); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java index aa2b084d23..735772e928 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionSimulator.java @@ -48,8 +48,7 @@ public class PrivateTransactionSimulator { private static final SECP256K1.Signature FAKE_SIGNATURE = SECP256K1.Signature.create(SECP256K1.HALF_CURVE_ORDER, SECP256K1.HALF_CURVE_ORDER, (byte) 0); - private static final Address DEFAULT_FROM = - Address.fromHexString("0x0000000000000000000000000000000000000000"); + private static final Address DEFAULT_FROM = Address.ZERO; private final Blockchain blockchain; private final WorldStateArchive worldStateArchive; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/group/OnChainGroupManagement.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/group/OnChainGroupManagement.java index 8b21f51e23..c095481e18 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/group/OnChainGroupManagement.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/group/OnChainGroupManagement.java @@ -19,16 +19,16 @@ import org.apache.tuweni.bytes.Bytes; public class OnChainGroupManagement { public static final Bytes PROXY_RUNTIME_BYTECODE = Bytes.fromHexString( - "608060405234801561001057600080fd5b50600436106100935760003560e01c806361544c911161006657806361544c91146101c757806378b9033714610217578063a69df4b514610239578063f744b08914610243578063f83d08ba1461031d57610093565b80630b0235be146100985780630d8e6e2c1461011b5780633659cfe6146101395780635c60da1b1461017d575b600080fd5b6100c4600480360360208110156100ae57600080fd5b8101908080359060200190929190505050610327565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156101075780820151818401526020810190506100ec565b505050509050019250505060405180910390f35b61012361047d565b6040518082815260200191505060405180910390f35b61017b6004803603602081101561014f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061052b565b005b610185610591565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101fd600480360360408110156101dd57600080fd5b8101908080359060200190929190803590602001909291905050506105b6565b604051808215151515815260200191505060405180910390f35b61021f61067c565b604051808215151515815260200191505060405180910390f35b61024161072a565b005b6103036004803603604081101561025957600080fd5b81019080803590602001909291908035906020019064010000000081111561028057600080fd5b82018360208201111561029257600080fd5b803590602001918460208302840111640100000000831117156102b457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192905050506107b3565b604051808215151515815260200191505060405180910390f35b6103256108ba565b005b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630b0235be846040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156103a057600080fd5b505afa1580156103b4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156103de57600080fd5b81019080805160405193929190846401000000008211156103fe57600080fd5b8382019150602082018581111561041457600080fd5b825186602082028301116401000000008211171561043157600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561046857808201518184015260208101905061044d565b50505050905001604052505050915050919050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630d8e6e2c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104ea57600080fd5b505afa1580156104fe573d6000803e3d6000fd5b505050506040513d602081101561051457600080fd5b810190808051906020019092919050505091505090565b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561058557600080fd5b61058e81610943565b50565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166361544c9185856040518363ffffffff1660e01b81526004018083815260200182815260200192505050602060405180830381600087803b15801561063857600080fd5b505af115801561064c573d6000803e3d6000fd5b505050506040513d602081101561066257600080fd5b810190808051906020019092919050505091505092915050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b1580156106e957600080fd5b505afa1580156106fd573d6000803e3d6000fd5b505050506040513d602081101561071357600080fd5b810190808051906020019092919050505091505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561079857600080fd5b505af11580156107ac573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f744b08985856040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610850578082015181840152602081019050610835565b505050509050019350505050602060405180830381600087803b15801561087657600080fd5b505af115801561088a573d6000803e3d6000fd5b505050506040513d60208110156108a057600080fd5b810190808051906020019092919050505091505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561092857600080fd5b505af115801561093c573d6000803e3d6000fd5b5050505050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a7231582086789349219ec4e3fca6895060836bcb51dbdead2090453fc01b0a49c021d4ef64736f6c63430005110032"); + "608060405234801561001057600080fd5b506004361061009e5760003560e01c80639738968c116100665780639738968c146101d0578063a69df4b5146101f2578063b4926e25146101fc578063f83d08ba146102cc578063fd017797146102d65761009e565b80630d8e6e2c146100a35780633659cfe6146100c15780635aa68ac0146101055780635c60da1b1461016457806378b90337146101ae575b600080fd5b6100ab61031c565b6040518082815260200191505060405180910390f35b610103600480360360208110156100d757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103ca565b005b61010d61085e565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610150578082015181840152602081019050610135565b505050509050019250505060405180910390f35b61016c6109a7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101b66109cc565b604051808215151515815260200191505060405180910390f35b6101d8610a7a565b604051808215151515815260200191505060405180910390f35b6101fa610b2a565b005b6102b26004803603602081101561021257600080fd5b810190808035906020019064010000000081111561022f57600080fd5b82018360208201111561024157600080fd5b8035906020019184602083028401116401000000008311171561026357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610bb3565b604051808215151515815260200191505060405180910390f35b6102d4610cb1565b005b610302600480360360208110156102ec57600080fd5b8101908080359060200190929190505050610d3a565b604051808215151515815260200191505060405180910390f35b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630d8e6e2c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561038957600080fd5b505afa15801561039d573d6000803e3d6000fd5b505050506040513d60208110156103b357600080fd5b810190808051906020019092919050505091505090565b3073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b15801561041057600080fd5b505afa158015610424573d6000803e3d6000fd5b505050506040513d602081101561043a57600080fd5b81019080805190602001909291905050506104bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f54686520636f6e7472616374206973206c6f636b65642e00000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610563576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526054815260200180610e7f6054913960600191505060405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16639738968c6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506040513d60208110156105d557600080fd5b810190808051906020019092919050505061063b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180610ed3602f913960400191505060405180910390fd5b60603073ffffffffffffffffffffffffffffffffffffffff16635aa68ac06040518163ffffffff1660e01b815260040160006040518083038186803b15801561068357600080fd5b505afa158015610697573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156106c157600080fd5b81019080805160405193929190846401000000008211156106e157600080fd5b838201915060208201858111156106f757600080fd5b825186602082028301116401000000008211171561071457600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561074b578082015181840152602081019050610730565b50505050905001604052505050905061076382610e3b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663b4926e25836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b838110156107f85780820151818401526020810190506107dd565b5050505090500192505050602060405180830381600087803b15801561081d57600080fd5b505af1158015610831573d6000803e3d6000fd5b505050506040513d602081101561084757600080fd5b810190808051906020019092919050505050505050565b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16635aa68ac06040518163ffffffff1660e01b815260040160006040518083038186803b1580156108cc57600080fd5b505afa1580156108e0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250602081101561090a57600080fd5b810190808051604051939291908464010000000082111561092a57600080fd5b8382019150602082018581111561094057600080fd5b825186602082028301116401000000008211171561095d57600080fd5b8083526020830192505050908051906020019060200280838360005b83811015610994578082015181840152602081019050610979565b5050505090500160405250505091505090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3957600080fd5b505afa158015610a4d573d6000803e3d6000fd5b505050506040513d6020811015610a6357600080fd5b810190808051906020019092919050505091505090565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16639738968c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ae957600080fd5b505af1158015610afd573d6000803e3d6000fd5b505050506040513d6020811015610b1357600080fd5b810190808051906020019092919050505091505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b9857600080fd5b505af1158015610bac573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663b4926e25846040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c49578082015181840152602081019050610c2e565b5050505090500192505050602060405180830381600087803b158015610c6e57600080fd5b505af1158015610c82573d6000803e3d6000fd5b505050506040513d6020811015610c9857600080fd5b8101908080519060200190929190505050915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d1f57600080fd5b505af1158015610d33573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1663fd017797856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015610db657600080fd5b505af1158015610dca573d6000803e3d6000fd5b505050506040513d6020811015610de057600080fd5b810190808051906020019092919050505090508015610e31577fef2df0cc0f44b5a36a7de9951ef49ba4d861649244ff89bcf7ffaa1ac7291e89846040518082815260200191505060405180910390a15b8092505050919050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fe54686520636f6e747261637420746f207570677261646520746f2068617320746f20626520646966666572656e742066726f6d207468652063757272656e74206d616e6167656d656e7420636f6e74726163742e4e6f7420616c6c6f77656420746f207570677261646520746865206d616e6167656d656e7420636f6e74726163742ea265627a7a7231582044fbf149f437e2b9c779b900ec84bfdaa17ce91f98119ecf8e4a10a899c2ea6964736f6c63430005110032"); public static final Bytes DEFAULT_GROUP_MANAGEMENT_RUNTIME_BYTECODE = Bytes.fromHexString( - "608060405234801561001057600080fd5b506004361061007d5760003560e01c806378b903371161005b57806378b9033714610173578063a69df4b514610195578063f744b0891461019f578063f83d08ba146102795761007d565b80630b0235be146100825780630d8e6e2c1461010557806361544c9114610123575b600080fd5b6100ae6004803603602081101561009857600080fd5b8101908080359060200190929190505050610283565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100f15780820151818401526020810190506100d6565b505050509050019250505060405180910390f35b61010d6102ef565b6040518082815260200191505060405180910390f35b6101596004803603604081101561013957600080fd5b8101908080359060200190929190803590602001909291905050506102f9565b604051808215151515815260200191505060405180910390f35b61017b61032d565b604051808215151515815260200191505060405180910390f35b61019d610343565b005b61025f600480360360408110156101b557600080fd5b8101908080359060200190929190803590602001906401000000008111156101dc57600080fd5b8201836020820111156101ee57600080fd5b8035906020019184602083028401116401000000008311171561021057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610378565b604051808215151515815260200191505060405180910390f35b6102816103f9565b005b606061028e8261042d565b61029757600080fd5b60028054806020026020016040519081016040528092919081815260200182805480156102e357602002820191906000526020600020905b8154815260200190600101908083116102cf575b50505050509050919050565b6000600154905090565b60006103048361042d565b61030d57600080fd5b60006103188361044d565b9050610322610530565b508091505092915050565b60008060009054906101000a900460ff16905090565b6000809054906101000a900460ff161561035c57600080fd5b60016000806101000a81548160ff021916908315150217905550565b60008060009054906101000a900460ff161561039357600080fd5b600060028054905014156103ac576103aa836105d0565b505b6103b58361042d565b6103be57600080fd5b60006103ca8484610642565b905060016000806101000a81548160ff0219169083151502179055506103ee610530565b508091505092915050565b6000809054906101000a900460ff1661041157600080fd5b60008060006101000a81548160ff021916908315150217905550565b600080600360008481526020019081526020016000205414159050919050565b6000806003600084815260200190815260200160002054905060008111801561047b57506002805490508111155b156105255760028054905081146104e95760006002600160028054905003815481106104a357fe5b9060005260206000200154905080600260018403815481106104c157fe5b9060005260206000200181905550816003600083815260200190815260200160002081905550505b60016002818180549050039150816105019190610924565b5060006003600085815260200190815260200160002081905550600191505061052b565b60009150505b919050565b60006001430340416002604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140182805480156105aa57602002820191906000526020600020905b815481526020019060010190808311610596575b505093505050506040516020818303038152906040528051906020012060018190555090565b60008060036000848152602001908152602001600020541415610638576002829080600181540180825580915050906001820390600052602060002001600090919290919091505560036000848152602001908152602001600020819055506001905061063d565b600090505b919050565b6000806001905060008090505b83518110156109195783818151811061066457fe5b60200260200101518514156106f8577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf21360008583815181106106a257fe5b60200260200101516040518083151515158152602001828152602001806020018281038252602f815260200180610997602f9139604001935050505060405180910390a18180156106f1575060005b915061090c565b61071484828151811061070757fe5b602002602001015161042d565b156107bb577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf213600085838151811061074857fe5b60200260200101516040518083151515158152602001828152602001806020018281038252601b8152602001807f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250602001935050505060405180910390a18180156107b4575060005b915061090b565b60006107d98583815181106107cc57fe5b60200260200101516105d0565b905060608161081d576040518060400160405280601b81526020017f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250610837565b604051806060016040528060218152602001610976602191395b90507fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf2138287858151811061086757fe5b602002602001015183604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156108c05780820151818401526020810190506108a5565b50505050905090810190601f1680156108ed5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a18380156109065750815b935050505b5b808060010191505061064f565b508091505092915050565b81548183558181111561094b5781836000526020600020918201910161094a9190610950565b5b505050565b61097291905b8082111561096e576000816000905550600101610956565b5090565b9056fe4d656d626572206163636f756e74206164646564207375636365737366756c6c79416464696e67206f776e206163636f756e742061732061204d656d626572206973206e6f74207065726d6974746564a265627a7a723158202d88696da9f39c286f5e1cc5830df2599a4d57a91cdd982a4872494055ad40d464736f6c63430005110032"); + "608060405234801561001057600080fd5b50600436106100885760003560e01c8063a69df4b51161005b578063a69df4b51461014e578063b4926e2514610158578063f83d08ba14610228578063fd0177971461023257610088565b80630d8e6e2c1461008d5780635aa68ac0146100ab57806378b903371461010a5780639738968c1461012c575b600080fd5b610095610278565b6040518082815260200191505060405180910390f35b6100b3610282565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100f65780820151818401526020810190506100db565b505050509050019250505060405180910390f35b6101126102da565b604051808215151515815260200191505060405180910390f35b6101346102f0565b604051808215151515815260200191505060405180910390f35b610156610347565b005b61020e6004803603602081101561016e57600080fd5b810190808035906020019064010000000081111561018b57600080fd5b82018360208201111561019d57600080fd5b803590602001918460208302840111640100000000831117156101bf57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610440565b604051808215151515815260200191505060405180910390f35b6102306105ee565b005b61025e6004803603602081101561024857600080fd5b81019080803590602001909291905050506106e5565b604051808215151515815260200191505060405180910390f35b6000600154905090565b606060028054806020026020016040519081016040528092919081815260200182805480156102d057602002820191906000526020600020905b8154815260200190600101908083116102bc575b5050505050905090565b60008060149054906101000a900460ff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614905090565b600060149054906101000a900460ff161561036157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614610423576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550565b60008060149054906101000a900460ff161561045b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156104f257326000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146105b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60006105bf836107e0565b90506001600060146101000a81548160ff0219169083151502179055506105e4610a20565b5080915050919050565b600060149054906101000a900460ff1661060757600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60008060146101000a81548160ff021916908315150217905550565b60008060149054906101000a900460ff166106ff57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146107c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60006107cc83610ac0565b90506107d6610a20565b5080915050919050565b6000806001905060008090505b8351811015610a165761081284828151811061080557fe5b6020026020010151610ba3565b156108b9577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf213600085838151811061084657fe5b60200260200101516040518083151515158152602001828152602001806020018281038252601b8152602001807f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250602001935050505060405180910390a18180156108b2575060005b9150610a09565b60006108d78583815181106108ca57fe5b6020026020010151610bc3565b905060608161091b576040518060400160405280601b81526020017f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250610935565b604051806060016040528060218152602001610c87602191395b90507fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf2138287858151811061096557fe5b602002602001015183604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156109be5780820151818401526020810190506109a3565b50505050905090810190601f1680156109eb5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1838015610a045750815b935050505b80806001019150506107ed565b5080915050919050565b60006001430340416002604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018280548015610a9a57602002820191906000526020600020905b815481526020019060010190808311610a86575b505093505050506040516020818303038152906040528051906020012060018190555090565b60008060036000848152602001908152602001600020549050600081118015610aee57506002805490508111155b15610b98576002805490508114610b5c576000600260016002805490500381548110610b1657fe5b906000526020600020015490508060026001840381548110610b3457fe5b9060005260206000200181905550816003600083815260200190815260200160002081905550505b6001600281818054905003915081610b749190610c35565b50600060036000858152602001908152602001600020819055506001915050610b9e565b60009150505b919050565b600080600360008481526020019081526020016000205414159050919050565b60008060036000848152602001908152602001600020541415610c2b5760028290806001815401808255809150509060018203906000526020600020016000909192909190915055600360008481526020019081526020016000208190555060019050610c30565b600090505b919050565b815481835581811115610c5c57818360005260206000209182019101610c5b9190610c61565b5b505050565b610c8391905b80821115610c7f576000816000905550600101610c67565b5090565b9056fe4d656d626572206163636f756e74206164646564207375636365737366756c6c79a265627a7a72315820bbc0f4c94a3e671eba00f207e4a7b3d0778d3b676de47497061483cb5cb3b41d64736f6c63430005110032"); - public static final Bytes ADD_TO_GROUP_METHOD_SIGNATURE = Bytes.fromHexString("0xf744b089"); + public static final Bytes ADD_PARTICIPANTS_METHOD_SIGNATURE = Bytes.fromHexString("0xb4926e25"); public static final Bytes CAN_EXECUTE_METHOD_SIGNATURE = Bytes.fromHexString("0x78b90337"); - public static final Bytes GET_PARTICIPANTS_METHOD_SIGNATURE = Bytes.fromHexString("0x0b0235be"); + public static final Bytes GET_PARTICIPANTS_METHOD_SIGNATURE = Bytes.fromHexString("0x5aa68ac0"); public static final Bytes GET_VERSION_METHOD_SIGNATURE = Bytes.fromHexString("0x0d8e6e2c"); - public static final Bytes REMOVE_PARTICIPANT_METHOD_SIGNATURE = Bytes.fromHexString("0x61544c91"); public static final Bytes LOCK_GROUP_METHOD_SIGNATURE = Bytes.fromHexString("0xf83d08ba"); + public static final Bytes REMOVE_PARTICIPANT_METHOD_SIGNATURE = Bytes.fromHexString("0xfd017797"); } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java index e7178ee4ba..c8efc79331 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java @@ -116,6 +116,12 @@ public class PrivateTransactionDataFixture { .createTransaction(KEY_PAIR); } + public static VersionedPrivateTransaction versionedPrivateTransactionBesu() { + return new PrivateTransactionTestFixture() + .privacyGroupId(VALID_BASE64_ENCLAVE_KEY) + .createVersionedPrivateTransaction((KEY_PAIR)); + } + public static PrivateTransaction privateContractDeploymentTransactionBesu() { return new PrivateTransactionTestFixture() .payload(VALID_CONTRACT_DEPLOYMENT_PAYLOAD) diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionTestFixture.java index 885dbb06bf..56b5d74386 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionTestFixture.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.privacy.Restriction; +import org.hyperledger.besu.ethereum.privacy.VersionedPrivateTransaction; import java.math.BigInteger; import java.util.List; @@ -24,6 +25,7 @@ import java.util.Optional; import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; public class PrivateTransactionTestFixture { @@ -84,6 +86,11 @@ public class PrivateTransactionTestFixture { return builder.signAndBuild(keys); } + public VersionedPrivateTransaction createVersionedPrivateTransaction(final KeyPair keyPair) { + final PrivateTransaction transaction = createTransaction(keyPair); + return new VersionedPrivateTransaction(transaction, Bytes32.ZERO); + } + public PrivateTransactionTestFixture nonce(final long nonce) { this.nonce = nonce; return this; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java new file mode 100644 index 0000000000..91511e6199 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/OnChainPrivacyPrecompiledContractTest.java @@ -0,0 +1,314 @@ +/* + * 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.mainnet.precompiles.privacy; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.versionedPrivateTransactionBesu; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.enclave.Enclave; +import org.hyperledger.besu.enclave.EnclaveClientException; +import org.hyperledger.besu.enclave.EnclaveConfigurationException; +import org.hyperledger.besu.enclave.types.ReceiveResponse; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.Log; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; +import org.hyperledger.besu.ethereum.core.WorldUpdater; +import org.hyperledger.besu.ethereum.mainnet.SpuriousDragonGasCalculator; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidator; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver; +import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; +import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; +import org.hyperledger.besu.ethereum.privacy.VersionedPrivateTransaction; +import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; +import org.hyperledger.besu.ethereum.vm.BlockHashLookup; +import org.hyperledger.besu.ethereum.vm.MessageFrame; +import org.hyperledger.besu.ethereum.vm.OperationTracer; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Mockito; + +public class OnChainPrivacyPrecompiledContractTest { + + @Rule public final TemporaryFolder temp = new TemporaryFolder(); + + private final Bytes txEnclaveKey = Bytes.random(32); + private MessageFrame messageFrame; + private Blockchain blockchain; + private final String DEFAULT_OUTPUT = "0x01"; + final String PAYLOAD_TEST_PRIVACY_GROUP_ID = "8lDVI66RZHIrBsolz6Kn88Rd+WsJ4hUjb4hsh29xW/o="; + private final WorldStateArchive worldStateArchive = mock(WorldStateArchive.class); + final PrivateStateStorage privateStateStorage = mock(PrivateStateStorage.class); + final PrivateStateRootResolver privateStateRootResolver = + new PrivateStateRootResolver(privateStateStorage); + + private PrivateTransactionProcessor mockPrivateTxProcessor( + final PrivateTransactionProcessor.Result result) { + final PrivateTransactionProcessor mockPrivateTransactionProcessor = + mock(PrivateTransactionProcessor.class); + when(mockPrivateTransactionProcessor.processTransaction( + nullable(Blockchain.class), + nullable(WorldUpdater.class), + nullable(WorldUpdater.class), + nullable(ProcessableBlockHeader.class), + nullable((Hash.class)), + nullable(PrivateTransaction.class), + nullable(Address.class), + nullable(OperationTracer.class), + nullable(BlockHashLookup.class), + nullable(Bytes.class))) + .thenReturn(result); + + return mockPrivateTransactionProcessor; + } + + @Before + public void setUp() { + final MutableWorldState mutableWorldState = mock(MutableWorldState.class); + when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class)); + when(worldStateArchive.getMutable()).thenReturn(mutableWorldState); + when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState)); + + final PrivateStateStorage.Updater storageUpdater = mock(PrivateStateStorage.Updater.class); + when(privateStateStorage.getPrivacyGroupHeadBlockMap(any())) + .thenReturn(Optional.of(PrivacyGroupHeadBlockMap.EMPTY)); + when(privateStateStorage.getPrivateBlockMetadata(any(), any())).thenReturn(Optional.empty()); + when(storageUpdater.putPrivateBlockMetadata( + nullable(Bytes32.class), nullable(Bytes32.class), any())) + .thenReturn(storageUpdater); + when(storageUpdater.putPrivacyGroupHeadBlockMap(nullable(Bytes32.class), any())) + .thenReturn(storageUpdater); + when(storageUpdater.putTransactionReceipt( + nullable(Bytes32.class), nullable(Bytes32.class), any())) + .thenReturn(storageUpdater); + when(privateStateStorage.updater()).thenReturn(storageUpdater); + + messageFrame = mock(MessageFrame.class); + blockchain = mock(Blockchain.class); + final BlockDataGenerator blockGenerator = new BlockDataGenerator(); + final Block genesis = blockGenerator.genesisBlock(); + final Block block = + blockGenerator.block( + new BlockDataGenerator.BlockOptions().setParentHash(genesis.getHeader().getHash())); + when(blockchain.getGenesisBlock()).thenReturn(genesis); + when(blockchain.getBlockByHash(block.getHash())).thenReturn(Optional.of(block)); + when(blockchain.getBlockByHash(genesis.getHash())).thenReturn(Optional.of(genesis)); + when(messageFrame.getBlockchain()).thenReturn(blockchain); + when(messageFrame.getBlockHeader()).thenReturn(block.getHeader()); + } + + @Test + public void testPayloadFoundInEnclave() { + final Enclave enclave = mock(Enclave.class); + final OnChainPrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + final List logs = new ArrayList<>(); + contract.setPrivateTransactionProcessor( + mockPrivateTxProcessor( + PrivateTransactionProcessor.Result.successful( + logs, 0, 0, Bytes.fromHexString(DEFAULT_OUTPUT), null))); + + final VersionedPrivateTransaction versionedPrivateTransaction = + versionedPrivateTransactionBesu(); + final byte[] payload = convertVersionedPrivateTransactionToBytes(versionedPrivateTransaction); + final String privateFrom = + versionedPrivateTransaction.getPrivateTransaction().getPrivateFrom().toBase64String(); + + final ReceiveResponse response = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom); + when(enclave.receive(any())).thenReturn(response); + + final OnChainPrivacyPrecompiledContract contractSpy = spy(contract); + Mockito.doNothing().when(contractSpy).maybeInjectDefaultManagementAndProxy(any(), any(), any()); + Mockito.doReturn(true) + .when(contractSpy) + .canExecute(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()); + + final Bytes actual = contractSpy.compute(txEnclaveKey, messageFrame); + + assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT)); + } + + @Test + public void testPayloadNotFoundInEnclave() { + final Enclave enclave = mock(Enclave.class); + final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + + when(enclave.receive(any(String.class))).thenThrow(EnclaveClientException.class); + + final Bytes expected = contract.compute(txEnclaveKey, messageFrame); + assertThat(expected).isEqualTo(Bytes.EMPTY); + } + + @Test(expected = RuntimeException.class) + public void testEnclaveDown() { + final Enclave enclave = mock(Enclave.class); + final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + + when(enclave.receive(any(String.class))).thenThrow(new RuntimeException()); + + contract.compute(txEnclaveKey, messageFrame); + } + + @Test + public void testEnclaveBelowRequiredVersion() { + final Enclave enclave = mock(Enclave.class); + final OnChainPrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + final VersionedPrivateTransaction versionedPrivateTransaction = + versionedPrivateTransactionBesu(); + final byte[] payload = convertVersionedPrivateTransactionToBytes(versionedPrivateTransaction); + + final ReceiveResponse responseWithoutSenderKey = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, null); + when(enclave.receive(eq(txEnclaveKey.toBase64String()))).thenReturn(responseWithoutSenderKey); + + assertThatThrownBy(() -> contract.compute(txEnclaveKey, messageFrame)) + .isInstanceOf(EnclaveConfigurationException.class) + .hasMessage("Incompatible Orion version. Orion version must be 1.6.0 or greater."); + } + + @Test + public void testPayloadNotMatchingPrivateFrom() { + final Enclave enclave = mock(Enclave.class); + final OnChainPrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + final VersionedPrivateTransaction versionedPrivateTransaction = + versionedPrivateTransactionBesu(); + final byte[] payload = convertVersionedPrivateTransactionToBytes(versionedPrivateTransaction); + + final String wrongSenderKey = Bytes.random(32).toBase64String(); + final ReceiveResponse responseWithWrongSenderKey = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, wrongSenderKey); + when(enclave.receive(eq(txEnclaveKey.toBase64String()))).thenReturn(responseWithWrongSenderKey); + + final Bytes expected = contract.compute(txEnclaveKey, messageFrame); + assertThat(expected).isEqualTo(Bytes.EMPTY); + } + + @Test + public void testPrivateFromNotMemberOfGroup() { + final Enclave enclave = mock(Enclave.class); + final OnChainPrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + final OnChainPrivacyPrecompiledContract contractSpy = spy(contract); + Mockito.doNothing().when(contractSpy).maybeInjectDefaultManagementAndProxy(any(), any(), any()); + Mockito.doReturn(false) + .when(contractSpy) + .isContractLocked(any(), any(), any(), any(), any(), any(), any()); + Mockito.doReturn(true) + .when(contractSpy) + .onChainPrivacyGroupVersionMatches(any(), any(), any(), any(), any(), any(), any(), any()); + final PrivateTransactionProcessor.Result mockResult = + mock(PrivateTransactionProcessor.Result.class); + Mockito.doReturn(mockResult) + .when(contractSpy) + .simulateTransaction(any(), any(), any(), any(), any(), any(), any(), any()); + Mockito.doReturn(Arrays.asList(Bytes.ofUnsignedInt(1L))) + .when(contractSpy) + .getMembersFromResult(any()); + + final VersionedPrivateTransaction privateTransaction = versionedPrivateTransactionBesu(); + final byte[] payload = convertVersionedPrivateTransactionToBytes(privateTransaction); + final String privateFrom = + privateTransaction.getPrivateTransaction().getPrivateFrom().toBase64String(); + + final ReceiveResponse response = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom); + when(enclave.receive(any(String.class))).thenReturn(response); + + final Bytes actual = contractSpy.compute(txEnclaveKey, messageFrame); + + assertThat(actual).isEqualTo(Bytes.EMPTY); + } + + @Test + public void testInvalidPrivateTransaction() { + final Enclave enclave = mock(Enclave.class); + + final OnChainPrivacyPrecompiledContract contract = + new OnChainPrivacyPrecompiledContract( + new SpuriousDragonGasCalculator(), + enclave, + worldStateArchive, + privateStateStorage, + privateStateRootResolver); + + contract.setPrivateTransactionProcessor( + mockPrivateTxProcessor( + PrivateTransactionProcessor.Result.invalid( + ValidationResult.invalid( + TransactionValidator.TransactionInvalidReason.INCORRECT_NONCE)))); + + final OnChainPrivacyPrecompiledContract contractSpy = spy(contract); + Mockito.doNothing().when(contractSpy).maybeInjectDefaultManagementAndProxy(any(), any(), any()); + Mockito.doReturn(true) + .when(contractSpy) + .canExecute(any(), any(), any(), any(), any(), any(), any(), any(), any(), any()); + + final VersionedPrivateTransaction privateTransaction = versionedPrivateTransactionBesu(); + final byte[] payload = convertVersionedPrivateTransactionToBytes(privateTransaction); + final String privateFrom = + privateTransaction.getPrivateTransaction().getPrivateFrom().toBase64String(); + + final ReceiveResponse response = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom); + + when(enclave.receive(any(String.class))).thenReturn(response); + + final Bytes actual = contractSpy.compute(txEnclaveKey, messageFrame); + + assertThat(actual).isEqualTo(Bytes.EMPTY); + } + + private byte[] convertVersionedPrivateTransactionToBytes( + final VersionedPrivateTransaction privateTransaction) { + final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput(); + privateTransaction.writeTo(bytesValueRLPOutput); + + return bytesValueRLPOutput.encoded().toBase64String().getBytes(UTF_8); + } + + private OnChainPrivacyPrecompiledContract buildPrivacyPrecompiledContract(final Enclave enclave) { + return new OnChainPrivacyPrecompiledContract( + new SpuriousDragonGasCalculator(), + enclave, + worldStateArchive, + privateStateStorage, + privateStateRootResolver); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java index 079d4735e6..a8a7bb574d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet.precompiles.privacy; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.VALID_BASE64_ENCLAVE_KEY; import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.privateTransactionBesu; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -28,6 +29,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.EnclaveClientException; import org.hyperledger.besu.enclave.EnclaveConfigurationException; +import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.enclave.types.ReceiveResponse; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; @@ -53,6 +55,7 @@ import org.hyperledger.besu.ethereum.vm.OperationTracer; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -136,6 +139,14 @@ public class PrivacyPrecompiledContractTest { @Test public void testPayloadFoundInEnclave() { final Enclave enclave = mock(Enclave.class); + when(enclave.retrievePrivacyGroup(PAYLOAD_TEST_PRIVACY_GROUP_ID)) + .thenReturn( + new PrivacyGroup( + PAYLOAD_TEST_PRIVACY_GROUP_ID, + PrivacyGroup.Type.PANTHEON, + "", + "", + Arrays.asList(VALID_BASE64_ENCLAVE_KEY.toBase64String()))); final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); final List logs = new ArrayList<>(); contract.setPrivateTransactionProcessor( @@ -144,7 +155,7 @@ public class PrivacyPrecompiledContractTest { logs, 0, 0, Bytes.fromHexString(DEFAULT_OUTPUT), null))); final PrivateTransaction privateTransaction = privateTransactionBesu(); - byte[] payload = convertPrivateTransactionToBytes(privateTransaction); + final byte[] payload = convertPrivateTransactionToBytes(privateTransaction); final String privateFrom = privateTransaction.getPrivateFrom().toBase64String(); final ReceiveResponse response = @@ -226,9 +237,47 @@ public class PrivacyPrecompiledContractTest { assertThat(expected).isEqualTo(Bytes.EMPTY); } + @Test + public void testPrivateFromNotMemberOfGroup() { + final Enclave enclave = mock(Enclave.class); + when(enclave.retrievePrivacyGroup(PAYLOAD_TEST_PRIVACY_GROUP_ID)) + .thenReturn( + new PrivacyGroup( + PAYLOAD_TEST_PRIVACY_GROUP_ID, + PrivacyGroup.Type.PANTHEON, + "", + "", + Arrays.asList(VALID_BASE64_ENCLAVE_KEY.toBase64String()))); + final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract(enclave); + contract.setPrivateTransactionProcessor( + mockPrivateTxProcessor( + PrivateTransactionProcessor.Result.successful( + new ArrayList<>(), 0, 0, Bytes.fromHexString(DEFAULT_OUTPUT), null))); + + final PrivateTransaction privateTransaction = privateTransactionBesu(); + final byte[] payload = convertPrivateTransactionToBytes(privateTransaction); + final String privateFrom = privateTransaction.getPrivateFrom().toBase64String(); + + final ReceiveResponse response = + new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom); + when(enclave.receive(any(String.class))).thenReturn(response); + + final Bytes actual = contract.compute(txEnclaveKey, messageFrame); + + assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT)); + } + @Test public void testInvalidPrivateTransaction() { final Enclave enclave = mock(Enclave.class); + when(enclave.retrievePrivacyGroup(PAYLOAD_TEST_PRIVACY_GROUP_ID)) + .thenReturn( + new PrivacyGroup( + PAYLOAD_TEST_PRIVACY_GROUP_ID, + PrivacyGroup.Type.PANTHEON, + "", + "", + Arrays.asList(VALID_BASE64_ENCLAVE_KEY.toBase64String()))); final PrivacyPrecompiledContract contract = new PrivacyPrecompiledContract( new SpuriousDragonGasCalculator(), diff --git a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/DefaultOnChainPrivacyGroupManagementContract.java b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/DefaultOnChainPrivacyGroupManagementContract.java index 802e237a61..3667daf4b3 100644 --- a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/DefaultOnChainPrivacyGroupManagementContract.java +++ b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/DefaultOnChainPrivacyGroupManagementContract.java @@ -53,17 +53,19 @@ import org.web3j.tx.gas.ContractGasProvider; * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the codegen module to update. * - *

Generated with web3j version 4.5.15. + *

Generated with web3j version 4.5.16. */ @SuppressWarnings("rawtypes") public class DefaultOnChainPrivacyGroupManagementContract extends Contract { public static final String BINARY = - "608060405234801561001057600080fd5b506109fa806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806378b903371161005b57806378b9033714610173578063a69df4b514610195578063f744b0891461019f578063f83d08ba146102795761007d565b80630b0235be146100825780630d8e6e2c1461010557806361544c9114610123575b600080fd5b6100ae6004803603602081101561009857600080fd5b8101908080359060200190929190505050610283565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100f15780820151818401526020810190506100d6565b505050509050019250505060405180910390f35b61010d6102ef565b6040518082815260200191505060405180910390f35b6101596004803603604081101561013957600080fd5b8101908080359060200190929190803590602001909291905050506102f9565b604051808215151515815260200191505060405180910390f35b61017b61032d565b604051808215151515815260200191505060405180910390f35b61019d610343565b005b61025f600480360360408110156101b557600080fd5b8101908080359060200190929190803590602001906401000000008111156101dc57600080fd5b8201836020820111156101ee57600080fd5b8035906020019184602083028401116401000000008311171561021057600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610378565b604051808215151515815260200191505060405180910390f35b6102816103f9565b005b606061028e8261042d565b61029757600080fd5b60028054806020026020016040519081016040528092919081815260200182805480156102e357602002820191906000526020600020905b8154815260200190600101908083116102cf575b50505050509050919050565b6000600154905090565b60006103048361042d565b61030d57600080fd5b60006103188361044d565b9050610322610530565b508091505092915050565b60008060009054906101000a900460ff16905090565b6000809054906101000a900460ff161561035c57600080fd5b60016000806101000a81548160ff021916908315150217905550565b60008060009054906101000a900460ff161561039357600080fd5b600060028054905014156103ac576103aa836105d0565b505b6103b58361042d565b6103be57600080fd5b60006103ca8484610642565b905060016000806101000a81548160ff0219169083151502179055506103ee610530565b508091505092915050565b6000809054906101000a900460ff1661041157600080fd5b60008060006101000a81548160ff021916908315150217905550565b600080600360008481526020019081526020016000205414159050919050565b6000806003600084815260200190815260200160002054905060008111801561047b57506002805490508111155b156105255760028054905081146104e95760006002600160028054905003815481106104a357fe5b9060005260206000200154905080600260018403815481106104c157fe5b9060005260206000200181905550816003600083815260200190815260200160002081905550505b60016002818180549050039150816105019190610924565b5060006003600085815260200190815260200160002081905550600191505061052b565b60009150505b919050565b60006001430340416002604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140182805480156105aa57602002820191906000526020600020905b815481526020019060010190808311610596575b505093505050506040516020818303038152906040528051906020012060018190555090565b60008060036000848152602001908152602001600020541415610638576002829080600181540180825580915050906001820390600052602060002001600090919290919091505560036000848152602001908152602001600020819055506001905061063d565b600090505b919050565b6000806001905060008090505b83518110156109195783818151811061066457fe5b60200260200101518514156106f8577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf21360008583815181106106a257fe5b60200260200101516040518083151515158152602001828152602001806020018281038252602f815260200180610997602f9139604001935050505060405180910390a18180156106f1575060005b915061090c565b61071484828151811061070757fe5b602002602001015161042d565b156107bb577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf213600085838151811061074857fe5b60200260200101516040518083151515158152602001828152602001806020018281038252601b8152602001807f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250602001935050505060405180910390a18180156107b4575060005b915061090b565b60006107d98583815181106107cc57fe5b60200260200101516105d0565b905060608161081d576040518060400160405280601b81526020017f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250610837565b604051806060016040528060218152602001610976602191395b90507fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf2138287858151811061086757fe5b602002602001015183604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156108c05780820151818401526020810190506108a5565b50505050905090810190601f1680156108ed5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a18380156109065750815b935050505b5b808060010191505061064f565b508091505092915050565b81548183558181111561094b5781836000526020600020918201910161094a9190610950565b5b505050565b61097291905b8082111561096e576000816000905550600101610956565b5090565b9056fe4d656d626572206163636f756e74206164646564207375636365737366756c6c79416464696e67206f776e206163636f756e742061732061204d656d626572206973206e6f74207065726d6974746564a265627a7a7231582072ad7e8bdc33e07430cb03b246b20c31c09189ccb0829a24e7a9c848aaa71c7e64736f6c63430005110032"; + "608060405234801561001057600080fd5b50610cdc806100206000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063a69df4b51161005b578063a69df4b51461014e578063b4926e2514610158578063f83d08ba14610228578063fd0177971461023257610088565b80630d8e6e2c1461008d5780635aa68ac0146100ab57806378b903371461010a5780639738968c1461012c575b600080fd5b610095610278565b6040518082815260200191505060405180910390f35b6100b3610282565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156100f65780820151818401526020810190506100db565b505050509050019250505060405180910390f35b6101126102da565b604051808215151515815260200191505060405180910390f35b6101346102f0565b604051808215151515815260200191505060405180910390f35b610156610347565b005b61020e6004803603602081101561016e57600080fd5b810190808035906020019064010000000081111561018b57600080fd5b82018360208201111561019d57600080fd5b803590602001918460208302840111640100000000831117156101bf57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610440565b604051808215151515815260200191505060405180910390f35b6102306105ee565b005b61025e6004803603602081101561024857600080fd5b81019080803590602001909291905050506106e5565b604051808215151515815260200191505060405180910390f35b6000600154905090565b606060028054806020026020016040519081016040528092919081815260200182805480156102d057602002820191906000526020600020905b8154815260200190600101908083116102bc575b5050505050905090565b60008060149054906101000a900460ff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614905090565b600060149054906101000a900460ff161561036157600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff1614610423576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff021916908315150217905550565b60008060149054906101000a900460ff161561045b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156104f257326000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146105b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60006105bf836107e0565b90506001600060146101000a81548160ff0219169083151502179055506105e4610a20565b5080915050919050565b600060149054906101000a900460ff1661060757600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146106c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60008060146101000a81548160ff021916908315150217905550565b60008060149054906101000a900460ff166106ff57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163273ffffffffffffffffffffffffffffffffffffffff16146107c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4f726967696e206e6f7420746865206f776e65722e000000000000000000000081525060200191505060405180910390fd5b60006107cc83610ac0565b90506107d6610a20565b5080915050919050565b6000806001905060008090505b8351811015610a165761081284828151811061080557fe5b6020026020010151610ba3565b156108b9577fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf213600085838151811061084657fe5b60200260200101516040518083151515158152602001828152602001806020018281038252601b8152602001807f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250602001935050505060405180910390a18180156108b2575060005b9150610a09565b60006108d78583815181106108ca57fe5b6020026020010151610bc3565b905060608161091b576040518060400160405280601b81526020017f4163636f756e7420697320616c72656164792061204d656d6265720000000000815250610935565b604051806060016040528060218152602001610c87602191395b90507fcc7365305ae5f16c463d1383713d699f43c5548bbda5537ee61373ceb9aaf2138287858151811061096557fe5b602002602001015183604051808415151515815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b838110156109be5780820151818401526020810190506109a3565b50505050905090810190601f1680156109eb5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a1838015610a045750815b935050505b80806001019150506107ed565b5080915050919050565b60006001430340416002604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018280548015610a9a57602002820191906000526020600020905b815481526020019060010190808311610a86575b505093505050506040516020818303038152906040528051906020012060018190555090565b60008060036000848152602001908152602001600020549050600081118015610aee57506002805490508111155b15610b98576002805490508114610b5c576000600260016002805490500381548110610b1657fe5b906000526020600020015490508060026001840381548110610b3457fe5b9060005260206000200181905550816003600083815260200190815260200160002081905550505b6001600281818054905003915081610b749190610c35565b50600060036000858152602001908152602001600020819055506001915050610b9e565b60009150505b919050565b600080600360008481526020019081526020016000205414159050919050565b60008060036000848152602001908152602001600020541415610c2b5760028290806001815401808255809150509060018203906000526020600020016000909192909190915055600360008481526020019081526020016000208190555060019050610c30565b600090505b919050565b815481835581811115610c5c57818360005260206000209182019101610c5b9190610c61565b5b505050565b610c8391905b80821115610c7f576000816000905550600101610c67565b5090565b9056fe4d656d626572206163636f756e74206164646564207375636365737366756c6c79a265627a7a723158203cf86d2cc3e5535fa971d254a61356128e1d65ba27e6a2ed9b8f71c27f3d5ae364736f6c63430005110032"; public static final String FUNC_ADDPARTICIPANTS = "addParticipants"; public static final String FUNC_CANEXECUTE = "canExecute"; + public static final String FUNC_CANUPGRADE = "canUpgrade"; + public static final String FUNC_GETPARTICIPANTS = "getParticipants"; public static final String FUNC_GETVERSION = "getVersion"; @@ -127,8 +129,8 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { for (Contract.EventValuesWithLog eventValues : valueList) { ParticipantAddedEventResponse typedResponse = new ParticipantAddedEventResponse(); typedResponse.log = eventValues.getLog(); - typedResponse.adminAdded = (Boolean) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.account = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); + typedResponse.success = (Boolean) eventValues.getNonIndexedValues().get(0).getValue(); + typedResponse.publicEnclaveKey = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); typedResponse.message = (String) eventValues.getNonIndexedValues().get(2).getValue(); responses.add(typedResponse); } @@ -146,9 +148,9 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { extractEventParametersWithLog(PARTICIPANTADDED_EVENT, log); ParticipantAddedEventResponse typedResponse = new ParticipantAddedEventResponse(); typedResponse.log = log; - typedResponse.adminAdded = + typedResponse.success = (Boolean) eventValues.getNonIndexedValues().get(0).getValue(); - typedResponse.account = + typedResponse.publicEnclaveKey = (byte[]) eventValues.getNonIndexedValues().get(1).getValue(); typedResponse.message = (String) eventValues.getNonIndexedValues().get(2).getValue(); @@ -164,17 +166,15 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { return participantAddedEventFlowable(filter); } - public RemoteFunctionCall addParticipants( - byte[] _enclaveKey, List _accounts) { + public RemoteFunctionCall addParticipants(List _publicEnclaveKeys) { final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function( FUNC_ADDPARTICIPANTS, Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(_enclaveKey), new org.web3j.abi.datatypes.DynamicArray( org.web3j.abi.datatypes.generated.Bytes32.class, org.web3j.abi.Utils.typeMap( - _accounts, org.web3j.abi.datatypes.generated.Bytes32.class))), + _publicEnclaveKeys, org.web3j.abi.datatypes.generated.Bytes32.class))), Collections.>emptyList()); return executeRemoteCallTransaction(function); } @@ -188,11 +188,18 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { return executeRemoteCallSingleValueReturn(function, Boolean.class); } - public RemoteFunctionCall getParticipants(byte[] _enclaveKey) { + public RemoteFunctionCall canUpgrade() { + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( + FUNC_CANUPGRADE, Arrays.asList(), Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall getParticipants() { final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function( FUNC_GETPARTICIPANTS, - Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(_enclaveKey)), + Arrays.asList(), Arrays.>asList(new TypeReference>() {})); return new RemoteFunctionCall( function, @@ -222,14 +229,11 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { return executeRemoteCallTransaction(function); } - public RemoteFunctionCall removeParticipant( - byte[] _enclaveKey, byte[] _account) { + public RemoteFunctionCall removeParticipant(byte[] _member) { final org.web3j.abi.datatypes.Function function = new org.web3j.abi.datatypes.Function( FUNC_REMOVEPARTICIPANT, - Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(_enclaveKey), - new org.web3j.abi.datatypes.generated.Bytes32(_account)), + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(_member)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } @@ -333,9 +337,9 @@ public class DefaultOnChainPrivacyGroupManagementContract extends Contract { } public static class ParticipantAddedEventResponse extends BaseEventResponse { - public Boolean adminAdded; + public Boolean success; - public byte[] account; + public byte[] publicEnclaveKey; public String message; } diff --git a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementInterface.java b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementInterface.java index 3253222510..b6bc25de52 100644 --- a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementInterface.java +++ b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementInterface.java @@ -44,7 +44,7 @@ import org.web3j.tx.gas.ContractGasProvider; * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the codegen module to update. * - *

Generated with web3j version 4.5.15. + *

Generated with web3j version 4.5.16. */ @SuppressWarnings("rawtypes") public class OnChainPrivacyGroupManagementInterface extends Contract { @@ -54,6 +54,8 @@ public class OnChainPrivacyGroupManagementInterface extends Contract { public static final String FUNC_CANEXECUTE = "canExecute"; + public static final String FUNC_CANUPGRADE = "canUpgrade"; + public static final String FUNC_GETPARTICIPANTS = "getParticipants"; public static final String FUNC_GETVERSION = "getVersion"; @@ -100,13 +102,11 @@ public class OnChainPrivacyGroupManagementInterface extends Contract { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public RemoteFunctionCall addParticipants( - byte[] enclaveKey, List participants) { + public RemoteFunctionCall addParticipants(List participants) { final Function function = new Function( FUNC_ADDPARTICIPANTS, Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey), new org.web3j.abi.datatypes.DynamicArray( org.web3j.abi.datatypes.generated.Bytes32.class, org.web3j.abi.Utils.typeMap( @@ -124,11 +124,18 @@ public class OnChainPrivacyGroupManagementInterface extends Contract { return executeRemoteCallSingleValueReturn(function, Boolean.class); } - public RemoteFunctionCall getParticipants(byte[] enclaveKey) { + public RemoteFunctionCall canUpgrade() { + final Function function = + new Function( + FUNC_CANUPGRADE, Arrays.asList(), Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall getParticipants() { final Function function = new Function( FUNC_GETPARTICIPANTS, - Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey)), + Arrays.asList(), Arrays.>asList(new TypeReference>() {})); return new RemoteFunctionCall( function, @@ -157,14 +164,11 @@ public class OnChainPrivacyGroupManagementInterface extends Contract { return executeRemoteCallTransaction(function); } - public RemoteFunctionCall removeParticipant( - byte[] enclaveKey, byte[] account) { + public RemoteFunctionCall removeParticipant(byte[] account) { final Function function = new Function( FUNC_REMOVEPARTICIPANT, - Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey), - new org.web3j.abi.datatypes.generated.Bytes32(account)), + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(account)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } diff --git a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementProxy.java b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementProxy.java index 112930ab60..f517bcfa20 100644 --- a/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementProxy.java +++ b/privacy-contracts/src/main/java/org/hyperledger/besu/privacy/contracts/generated/OnChainPrivacyGroupManagementProxy.java @@ -15,23 +15,31 @@ package org.hyperledger.besu.privacy.contracts.generated; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; +import io.reactivex.Flowable; +import io.reactivex.functions.Function; +import org.web3j.abi.EventEncoder; import org.web3j.abi.FunctionEncoder; import org.web3j.abi.TypeReference; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Bool; import org.web3j.abi.datatypes.DynamicArray; -import org.web3j.abi.datatypes.Function; +import org.web3j.abi.datatypes.Event; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.generated.Bytes32; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; +import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.RemoteCall; import org.web3j.protocol.core.RemoteFunctionCall; +import org.web3j.protocol.core.methods.request.EthFilter; +import org.web3j.protocol.core.methods.response.BaseEventResponse; +import org.web3j.protocol.core.methods.response.Log; import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.tx.Contract; import org.web3j.tx.TransactionManager; @@ -46,17 +54,19 @@ import org.web3j.tx.gas.ContractGasProvider; * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the codegen module to update. * - *

Generated with web3j version 4.5.15. + *

Generated with web3j version 4.5.16. */ @SuppressWarnings("rawtypes") public class OnChainPrivacyGroupManagementProxy extends Contract { public static final String BINARY = - "608060405234801561001057600080fd5b50604051610a4f380380610a4f8339818101604052602081101561003357600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506109bb806100946000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c806361544c911161006657806361544c91146101c757806378b9033714610217578063a69df4b514610239578063f744b08914610243578063f83d08ba1461031d57610093565b80630b0235be146100985780630d8e6e2c1461011b5780633659cfe6146101395780635c60da1b1461017d575b600080fd5b6100c4600480360360208110156100ae57600080fd5b8101908080359060200190929190505050610327565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b838110156101075780820151818401526020810190506100ec565b505050509050019250505060405180910390f35b61012361047d565b6040518082815260200191505060405180910390f35b61017b6004803603602081101561014f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061052b565b005b610185610591565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101fd600480360360408110156101dd57600080fd5b8101908080359060200190929190803590602001909291905050506105b6565b604051808215151515815260200191505060405180910390f35b61021f61067c565b604051808215151515815260200191505060405180910390f35b61024161072a565b005b6103036004803603604081101561025957600080fd5b81019080803590602001909291908035906020019064010000000081111561028057600080fd5b82018360208201111561029257600080fd5b803590602001918460208302840111640100000000831117156102b457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f8201169050808301925050505050505091929192905050506107b3565b604051808215151515815260200191505060405180910390f35b6103256108ba565b005b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630b0235be846040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156103a057600080fd5b505afa1580156103b4573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156103de57600080fd5b81019080805160405193929190846401000000008211156103fe57600080fd5b8382019150602082018581111561041457600080fd5b825186602082028301116401000000008211171561043157600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561046857808201518184015260208101905061044d565b50505050905001604052505050915050919050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630d8e6e2c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156104ea57600080fd5b505afa1580156104fe573d6000803e3d6000fd5b505050506040513d602081101561051457600080fd5b810190808051906020019092919050505091505090565b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561058557600080fd5b61058e81610943565b50565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166361544c9185856040518363ffffffff1660e01b81526004018083815260200182815260200192505050602060405180830381600087803b15801561063857600080fd5b505af115801561064c573d6000803e3d6000fd5b505050506040513d602081101561066257600080fd5b810190808051906020019092919050505091505092915050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b1580156106e957600080fd5b505afa1580156106fd573d6000803e3d6000fd5b505050506040513d602081101561071357600080fd5b810190808051906020019092919050505091505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561079857600080fd5b505af11580156107ac573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f744b08985856040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b83811015610850578082015181840152602081019050610835565b505050509050019350505050602060405180830381600087803b15801561087657600080fd5b505af115801561088a573d6000803e3d6000fd5b505050506040513d60208110156108a057600080fd5b810190808051906020019092919050505091505092915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561092857600080fd5b505af115801561093c573d6000803e3d6000fd5b5050505050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a723158207fea7928b00fedaff98beadf2cfe879463becd0c33005dc70cf51f4d8ff0cb8c64736f6c63430005110032"; + "608060405234801561001057600080fd5b50604051610fca380380610fca8339818101604052602081101561003357600080fd5b8101908080519060200190929190505050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050610f36806100946000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c80639738968c116100665780639738968c146101d0578063a69df4b5146101f2578063b4926e25146101fc578063f83d08ba146102cc578063fd017797146102d65761009e565b80630d8e6e2c146100a35780633659cfe6146100c15780635aa68ac0146101055780635c60da1b1461016457806378b90337146101ae575b600080fd5b6100ab61031c565b6040518082815260200191505060405180910390f35b610103600480360360208110156100d757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103ca565b005b61010d61085e565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b83811015610150578082015181840152602081019050610135565b505050509050019250505060405180910390f35b61016c6109a7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101b66109cc565b604051808215151515815260200191505060405180910390f35b6101d8610a7a565b604051808215151515815260200191505060405180910390f35b6101fa610b2a565b005b6102b26004803603602081101561021257600080fd5b810190808035906020019064010000000081111561022f57600080fd5b82018360208201111561024157600080fd5b8035906020019184602083028401116401000000008311171561026357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050509192919290505050610bb3565b604051808215151515815260200191505060405180910390f35b6102d4610cb1565b005b610302600480360360208110156102ec57600080fd5b8101908080359060200190929190505050610d3a565b604051808215151515815260200191505060405180910390f35b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16630d8e6e2c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561038957600080fd5b505afa15801561039d573d6000803e3d6000fd5b505050506040513d60208110156103b357600080fd5b810190808051906020019092919050505091505090565b3073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b15801561041057600080fd5b505afa158015610424573d6000803e3d6000fd5b505050506040513d602081101561043a57600080fd5b81019080805190602001909291905050506104bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260178152602001807f54686520636f6e7472616374206973206c6f636b65642e00000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610563576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526054815260200180610e7f6054913960600191505060405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff16639738968c6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506040513d60208110156105d557600080fd5b810190808051906020019092919050505061063b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602f815260200180610ed3602f913960400191505060405180910390fd5b60603073ffffffffffffffffffffffffffffffffffffffff16635aa68ac06040518163ffffffff1660e01b815260040160006040518083038186803b15801561068357600080fd5b505afa158015610697573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525060208110156106c157600080fd5b81019080805160405193929190846401000000008211156106e157600080fd5b838201915060208201858111156106f757600080fd5b825186602082028301116401000000008211171561071457600080fd5b8083526020830192505050908051906020019060200280838360005b8381101561074b578082015181840152602081019050610730565b50505050905001604052505050905061076382610e3b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663b4926e25836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b838110156107f85780820151818401526020810190506107dd565b5050505090500192505050602060405180830381600087803b15801561081d57600080fd5b505af1158015610831573d6000803e3d6000fd5b505050506040513d602081101561084757600080fd5b810190808051906020019092919050505050505050565b606060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16635aa68ac06040518163ffffffff1660e01b815260040160006040518083038186803b1580156108cc57600080fd5b505afa1580156108e0573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250602081101561090a57600080fd5b810190808051604051939291908464010000000082111561092a57600080fd5b8382019150602082018581111561094057600080fd5b825186602082028301116401000000008211171561095d57600080fd5b8083526020830192505050908051906020019060200280838360005b83811015610994578082015181840152602081019050610979565b5050505090500160405250505091505090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff166378b903376040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3957600080fd5b505afa158015610a4d573d6000803e3d6000fd5b505050506040513d6020811015610a6357600080fd5b810190808051906020019092919050505091505090565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff16639738968c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ae957600080fd5b505af1158015610afd573d6000803e3d6000fd5b505050506040513d6020811015610b1357600080fd5b810190808051906020019092919050505091505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663a69df4b56040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b9857600080fd5b505af1158015610bac573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663b4926e25846040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019060200280838360005b83811015610c49578082015181840152602081019050610c2e565b5050505090500192505050602060405180830381600087803b158015610c6e57600080fd5b505af1158015610c82573d6000803e3d6000fd5b505050506040513d6020811015610c9857600080fd5b8101908080519060200190929190505050915050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508073ffffffffffffffffffffffffffffffffffffffff1663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610d1f57600080fd5b505af1158015610d33573d6000803e3d6000fd5b5050505050565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1663fd017797856040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b158015610db657600080fd5b505af1158015610dca573d6000803e3d6000fd5b505050506040513d6020811015610de057600080fd5b810190808051906020019092919050505090508015610e31577fef2df0cc0f44b5a36a7de9951ef49ba4d861649244ff89bcf7ffaa1ac7291e89846040518082815260200191505060405180910390a15b8092505050919050565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fe54686520636f6e747261637420746f207570677261646520746f2068617320746f20626520646966666572656e742066726f6d207468652063757272656e74206d616e6167656d656e7420636f6e74726163742e4e6f7420616c6c6f77656420746f207570677261646520746865206d616e6167656d656e7420636f6e74726163742ea265627a7a72315820b44978dfc92abc75d19d42c6e9dc4112706674ac56975b77d7301394c9e92f0b64736f6c63430005110032"; public static final String FUNC_ADDPARTICIPANTS = "addParticipants"; public static final String FUNC_CANEXECUTE = "canExecute"; + public static final String FUNC_CANUPGRADE = "canUpgrade"; + public static final String FUNC_GETPARTICIPANTS = "getParticipants"; public static final String FUNC_GETVERSION = "getVersion"; @@ -71,6 +81,10 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { public static final String FUNC_UPGRADETO = "upgradeTo"; + public static final Event PARTICIPANTREMOVED_EVENT = + new Event( + "ParticipantRemoved", Arrays.>asList(new TypeReference() {}));; + @Deprecated protected OnChainPrivacyGroupManagementProxy( String contractAddress, @@ -107,35 +121,82 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } - public RemoteFunctionCall addParticipants( - byte[] enclaveKey, List participants) { - final Function function = - new Function( + public List getParticipantRemovedEvents( + TransactionReceipt transactionReceipt) { + List valueList = + extractEventParametersWithLog(PARTICIPANTREMOVED_EVENT, transactionReceipt); + ArrayList responses = + new ArrayList(valueList.size()); + for (Contract.EventValuesWithLog eventValues : valueList) { + ParticipantRemovedEventResponse typedResponse = new ParticipantRemovedEventResponse(); + typedResponse.log = eventValues.getLog(); + typedResponse.publicEnclaveKey = (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); + responses.add(typedResponse); + } + return responses; + } + + public Flowable participantRemovedEventFlowable( + EthFilter filter) { + return web3j + .ethLogFlowable(filter) + .map( + new Function() { + @Override + public ParticipantRemovedEventResponse apply(Log log) { + Contract.EventValuesWithLog eventValues = + extractEventParametersWithLog(PARTICIPANTREMOVED_EVENT, log); + ParticipantRemovedEventResponse typedResponse = + new ParticipantRemovedEventResponse(); + typedResponse.log = log; + typedResponse.publicEnclaveKey = + (byte[]) eventValues.getNonIndexedValues().get(0).getValue(); + return typedResponse; + } + }); + } + + public Flowable participantRemovedEventFlowable( + DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { + EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); + filter.addSingleTopic(EventEncoder.encode(PARTICIPANTREMOVED_EVENT)); + return participantRemovedEventFlowable(filter); + } + + public RemoteFunctionCall addParticipants(List _publicEnclaveKeys) { + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_ADDPARTICIPANTS, Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey), new org.web3j.abi.datatypes.DynamicArray( org.web3j.abi.datatypes.generated.Bytes32.class, org.web3j.abi.Utils.typeMap( - participants, org.web3j.abi.datatypes.generated.Bytes32.class))), + _publicEnclaveKeys, org.web3j.abi.datatypes.generated.Bytes32.class))), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall canExecute() { - final Function function = - new Function( + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_CANEXECUTE, Arrays.asList(), Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } - public RemoteFunctionCall getParticipants(byte[] enclaveKey) { - final Function function = - new Function( + public RemoteFunctionCall canUpgrade() { + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( + FUNC_CANUPGRADE, Arrays.asList(), Collections.>emptyList()); + return executeRemoteCallTransaction(function); + } + + public RemoteFunctionCall getParticipants() { + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_GETPARTICIPANTS, - Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey)), + Arrays.asList(), Arrays.>asList(new TypeReference>() {})); return new RemoteFunctionCall( function, @@ -150,8 +211,8 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { } public RemoteFunctionCall getVersion() { - final Function function = - new Function( + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_GETVERSION, Arrays.asList(), Arrays.>asList(new TypeReference() {})); @@ -159,8 +220,8 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { } public RemoteFunctionCall implementation() { - final Function function = - new Function( + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_IMPLEMENTATION, Arrays.asList(), Arrays.>asList(new TypeReference

() {})); @@ -168,32 +229,31 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { } public RemoteFunctionCall lock() { - final Function function = - new Function(FUNC_LOCK, Arrays.asList(), Collections.>emptyList()); + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( + FUNC_LOCK, Arrays.asList(), Collections.>emptyList()); return executeRemoteCallTransaction(function); } - public RemoteFunctionCall removeParticipant( - byte[] enclaveKey, byte[] account) { - final Function function = - new Function( + public RemoteFunctionCall removeParticipant(byte[] _member) { + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_REMOVEPARTICIPANT, - Arrays.asList( - new org.web3j.abi.datatypes.generated.Bytes32(enclaveKey), - new org.web3j.abi.datatypes.generated.Bytes32(account)), + Arrays.asList(new org.web3j.abi.datatypes.generated.Bytes32(_member)), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall unlock() { - final Function function = - new Function(FUNC_UNLOCK, Arrays.asList(), Collections.>emptyList()); + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( + FUNC_UNLOCK, Arrays.asList(), Collections.>emptyList()); return executeRemoteCallTransaction(function); } public RemoteFunctionCall upgradeTo(String _newImplementation) { - final Function function = - new Function( + final org.web3j.abi.datatypes.Function function = + new org.web3j.abi.datatypes.Function( FUNC_UPGRADETO, Arrays.asList(new org.web3j.abi.datatypes.Address(160, _newImplementation)), Collections.>emptyList()); @@ -313,4 +373,8 @@ public class OnChainPrivacyGroupManagementProxy extends Contract { BINARY, encodedConstructor); } + + public static class ParticipantRemovedEventResponse extends BaseEventResponse { + public byte[] publicEnclaveKey; + } } diff --git a/privacy-contracts/src/main/solidity/DefaultOnChainPrivacyGroupManagementContract.sol b/privacy-contracts/src/main/solidity/DefaultOnChainPrivacyGroupManagementContract.sol index 1e6eec39ba..547880e2bc 100644 --- a/privacy-contracts/src/main/solidity/DefaultOnChainPrivacyGroupManagementContract.sol +++ b/privacy-contracts/src/main/solidity/DefaultOnChainPrivacyGroupManagementContract.sol @@ -3,6 +3,7 @@ import "./OnChainPrivacyGroupManagementInterface.sol"; contract DefaultOnChainPrivacyGroupManagementContract is OnChainPrivacyGroupManagementInterface { + address private _owner; bool private _canExecute; bytes32 private _version; bytes32[] private distributionList; @@ -12,89 +13,92 @@ contract DefaultOnChainPrivacyGroupManagementContract is OnChainPrivacyGroupMana return _version; } - // overrides function canExecute() external view returns (bool) { return _canExecute; } function lock() public { require(_canExecute); + require(tx.origin == _owner, "Origin not the owner."); _canExecute = false; } function unlock() public { require(!_canExecute); + require(tx.origin == _owner, "Origin not the owner."); _canExecute = true; } - function addParticipants(bytes32 _enclaveKey, bytes32[] memory _accounts) public returns (bool) { + function addParticipants(bytes32[] memory _publicEnclaveKeys) public returns (bool) { require(!_canExecute); - if(distributionList.length == 0) { - addParticipant(_enclaveKey); + if (_owner == address(0x0)) { + // The account creating this group is set to be the owner + _owner = tx.origin; } - require(isMember(_enclaveKey)); - bool result = addAll(_enclaveKey, _accounts); + require(tx.origin == _owner, "Origin not the owner."); + bool result = addAll(_publicEnclaveKeys); _canExecute = true; updateVersion(); return result; } - function removeParticipant(bytes32 _enclaveKey, bytes32 _account) public returns (bool) { - require(isMember(_enclaveKey)); - bool result = removeInternal(_account); + function removeParticipant(bytes32 _member) public returns (bool) { + require(_canExecute); + require(tx.origin == _owner, "Origin not the owner."); + bool result = removeInternal(_member); updateVersion(); return result; } - function getParticipants(bytes32 _enclaveKey) public view returns (bytes32[] memory) { - require(isMember(_enclaveKey)); + function getParticipants() public view returns (bytes32[] memory) { return distributionList; } + function canUpgrade() external returns (bool) { + return tx.origin == _owner; + } + //internal functions - function addAll(bytes32 _enclaveKey, bytes32[] memory _accounts) internal returns (bool) { + function addAll(bytes32[] memory _publicEnclaveKeys) internal returns (bool) { bool allAdded = true; - for (uint i = 0; i < _accounts.length; i++) { - if (_enclaveKey == _accounts[i]) { - emit ParticipantAdded(false, _accounts[i], "Adding own account as a Member is not permitted"); - allAdded = allAdded && false; - } else if (isMember(_accounts[i])) { - emit ParticipantAdded(false, _accounts[i], "Account is already a Member"); + for (uint i = 0; i < _publicEnclaveKeys.length; i++) { + if (isMember(_publicEnclaveKeys[i])) { + emit ParticipantAdded(false, _publicEnclaveKeys[i], "Account is already a Member"); allAdded = allAdded && false; } else { - bool result = addParticipant(_accounts[i]); + bool result = addParticipant(_publicEnclaveKeys[i]); string memory message = result ? "Member account added successfully" : "Account is already a Member"; - emit ParticipantAdded(result, _accounts[i], message); + emit ParticipantAdded(result, _publicEnclaveKeys[i], message); allAdded = allAdded && result; } } return allAdded; } - function isMember(bytes32 _account) internal view returns (bool) { - return distributionIndexOf[_account] != 0; + function isMember(bytes32 _publicEnclaveKey) internal view returns (bool) { + return distributionIndexOf[_publicEnclaveKey] != 0; } - function addParticipant(bytes32 _participant) internal returns (bool) { - if (distributionIndexOf[_participant] == 0) { - distributionIndexOf[_participant] = distributionList.push(_participant); + function addParticipant(bytes32 _publicEnclaveKey) internal returns (bool) { + if (distributionIndexOf[_publicEnclaveKey] == 0) { + distributionIndexOf[_publicEnclaveKey] = distributionList.push(_publicEnclaveKey); return true; } return false; } - function removeInternal(bytes32 _participant) internal returns (bool) { - uint256 index = distributionIndexOf[_participant]; + function removeInternal(bytes32 _member) internal returns (bool) { + uint256 index = distributionIndexOf[_member]; if (index > 0 && index <= distributionList.length) { //move last address into index being vacated (unless we are dealing with last index) if (index != distributionList.length) { - bytes32 lastAccount = distributionList[distributionList.length - 1]; - distributionList[index - 1] = lastAccount; - distributionIndexOf[lastAccount] = index; + bytes32 lastPublicKey = distributionList[distributionList.length - 1]; + distributionList[index - 1] = lastPublicKey; + distributionIndexOf[lastPublicKey] = index; } distributionList.length -= 1; - distributionIndexOf[_participant] = 0; + distributionIndexOf[_member] = 0; return true; } return false; @@ -105,8 +109,8 @@ contract DefaultOnChainPrivacyGroupManagementContract is OnChainPrivacyGroupMana } event ParticipantAdded( - bool adminAdded, - bytes32 account, + bool success, + bytes32 publicEnclaveKey, string message ); } \ No newline at end of file diff --git a/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementInterface.sol b/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementInterface.sol index 43f43512e6..59dd9fd167 100644 --- a/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementInterface.sol +++ b/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementInterface.sol @@ -1,12 +1,11 @@ pragma solidity ^0.5.9; - interface OnChainPrivacyGroupManagementInterface { - function addParticipants(bytes32 enclaveKey, bytes32[] calldata participants) external returns (bool); + function addParticipants(bytes32[] calldata participants) external returns (bool); - function removeParticipant(bytes32 enclaveKey, bytes32 account) external returns (bool); + function removeParticipant(bytes32 account) external returns (bool); - function getParticipants(bytes32 enclaveKey) external view returns (bytes32[] memory); + function getParticipants() external view returns (bytes32[] memory); function lock() external; @@ -15,4 +14,6 @@ interface OnChainPrivacyGroupManagementInterface { function canExecute() external view returns (bool); function getVersion() external view returns (bytes32); -} + + function canUpgrade() external returns (bool); +} \ No newline at end of file diff --git a/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementProxy.sol b/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementProxy.sol index ebdb721cc7..96dd8f9eec 100644 --- a/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementProxy.sol +++ b/privacy-contracts/src/main/solidity/OnChainPrivacyGroupManagementProxy.sol @@ -1,5 +1,6 @@ pragma solidity ^0.5.12; +pragma solidity ^0.5.9; import "./OnChainPrivacyGroupManagementInterface.sol"; contract OnChainPrivacyGroupManagementProxy is OnChainPrivacyGroupManagementInterface { @@ -10,28 +11,27 @@ contract OnChainPrivacyGroupManagementProxy is OnChainPrivacyGroupManagementInte implementation = _implementation; } - function upgradeTo(address _newImplementation) external { - require(implementation != _newImplementation); - _setImplementation(_newImplementation); - } - function _setImplementation(address _newImp) internal { implementation = _newImp; } - function addParticipants(bytes32 enclaveKey, bytes32[] memory participants) public returns (bool) { + function addParticipants(bytes32[] memory _publicEnclaveKeys) public returns (bool) { OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); - return privacyInterface.addParticipants(enclaveKey, participants); + return privacyInterface.addParticipants(_publicEnclaveKeys); } - function getParticipants(bytes32 enclaveKey) view public returns (bytes32[] memory) { + function getParticipants() view public returns (bytes32[] memory) { OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); - return privacyInterface.getParticipants(enclaveKey); + return privacyInterface.getParticipants(); } - function removeParticipant(bytes32 enclaveKey, bytes32 account) public returns (bool) { + function removeParticipant(bytes32 _member) public returns (bool) { OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); - return privacyInterface.removeParticipant(enclaveKey, account); + bool result = privacyInterface.removeParticipant(_member); + if (result) { + emit ParticipantRemoved(_member); + } + return result; } function lock() public { @@ -53,4 +53,25 @@ contract OnChainPrivacyGroupManagementProxy is OnChainPrivacyGroupManagementInte OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); return privacyInterface.getVersion(); } + + function canUpgrade() external returns (bool) { + OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); + return privacyInterface.canUpgrade(); + } + + function upgradeTo(address _newImplementation) external { + require(this.canExecute(), "The contract is locked."); + require(implementation != _newImplementation, "The contract to upgrade to has to be different from the current management contract."); + require(this.canUpgrade(), "Not allowed to upgrade the management contract."); + bytes32[] memory participants = this.getParticipants(); + _setImplementation(_newImplementation); + OnChainPrivacyGroupManagementInterface privacyInterface = OnChainPrivacyGroupManagementInterface(implementation); + privacyInterface.addParticipants(participants); + } + + event ParticipantRemoved( + bytes32 publicEnclaveKey + ); + + }