mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 21:17:54 -05:00
chore: Removed Privacy ATs (#7530)
* chore: Removed privacy acceptance classes Signed-off-by: Preeti <35308865+pr9t@users.noreply.github.com> * Chore: removed classes that extends PrivateLogFilterAcceptanceTest and FlexiblePrivacyAcceptanceTestBase Signed-off-by: Preeti <35308865+pr9t@users.noreply.github.com> --------- Signed-off-by: Preeti <35308865+pr9t@users.noreply.github.com> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.dsl.privacy;
|
||||
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.NOOP;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.PluginCreateRandomPrivacyGroupIdTransaction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.RestrictedCreatePrivacyGroupTransaction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public abstract class ParameterizedEnclaveTestBase extends PrivacyAcceptanceTestBase {
|
||||
protected final Restriction restriction;
|
||||
protected final EnclaveType enclaveType;
|
||||
protected final EnclaveEncryptorType enclaveEncryptorType;
|
||||
|
||||
protected ParameterizedEnclaveTestBase(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType) {
|
||||
this.restriction = restriction;
|
||||
this.enclaveType = enclaveType;
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
}
|
||||
|
||||
@Parameters(name = "{0} tx with {1} enclave and {2} encryptor type")
|
||||
public static Collection<Object[]> params() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{RESTRICTED, TESSERA, NACL},
|
||||
{RESTRICTED, TESSERA, EC},
|
||||
{UNRESTRICTED, NOOP, EnclaveEncryptorType.NOOP}
|
||||
});
|
||||
}
|
||||
|
||||
public Transaction<String> createPrivacyGroup(
|
||||
final String name, final String description, final PrivacyNode... nodes) {
|
||||
|
||||
if (restriction == RESTRICTED) {
|
||||
return new RestrictedCreatePrivacyGroupTransaction(name, description, nodes);
|
||||
} else if (restriction == UNRESTRICTED) {
|
||||
return new PluginCreateRandomPrivacyGroupIdTransaction();
|
||||
} else {
|
||||
throw new RuntimeException("Do not know how to handle " + restriction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.dsl.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.WaitUtils;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.eth.EthConditions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.priv.PrivConditions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.privacy.PrivacyNodeFactory;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.PrivateContractVerifier;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.PrivateTransactionVerifier;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.contract.PrivateContractTransactions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.PrivacyTransactions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.contract.ContractTransactions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetTransactions;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import org.junit.After;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
public class PrivacyAcceptanceTestBase {
|
||||
@ClassRule public static final TemporaryFolder privacy = new TemporaryFolder();
|
||||
|
||||
protected final PrivacyTransactions privacyTransactions;
|
||||
protected final PrivateContractVerifier privateContractVerifier;
|
||||
protected final PrivateTransactionVerifier privateTransactionVerifier;
|
||||
protected final PrivacyNodeFactory privacyBesu;
|
||||
protected final PrivateContractTransactions privateContractTransactions;
|
||||
protected final PrivConditions priv;
|
||||
protected final PrivacyCluster privacyCluster;
|
||||
protected final ContractTransactions contractTransactions;
|
||||
protected final NetConditions net;
|
||||
protected final EthTransactions ethTransactions;
|
||||
protected final EthConditions eth;
|
||||
private final Vertx vertx = Vertx.vertx();
|
||||
|
||||
public PrivacyAcceptanceTestBase() {
|
||||
ethTransactions = new EthTransactions();
|
||||
net = new NetConditions(new NetTransactions());
|
||||
privacyTransactions = new PrivacyTransactions();
|
||||
privateContractVerifier = new PrivateContractVerifier();
|
||||
privateTransactionVerifier = new PrivateTransactionVerifier(privacyTransactions);
|
||||
privacyBesu = new PrivacyNodeFactory(vertx);
|
||||
privateContractTransactions = new PrivateContractTransactions();
|
||||
privacyCluster = new PrivacyCluster(net);
|
||||
priv =
|
||||
new PrivConditions(
|
||||
new org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy
|
||||
.PrivacyTransactions());
|
||||
contractTransactions = new ContractTransactions();
|
||||
eth = new EthConditions(ethTransactions);
|
||||
}
|
||||
|
||||
protected void waitForBlockHeight(final PrivacyNode node, final long blockchainHeight) {
|
||||
WaitUtils.waitFor(
|
||||
120,
|
||||
() ->
|
||||
assertThat(node.execute(ethTransactions.blockNumber()))
|
||||
.isGreaterThanOrEqualTo(BigInteger.valueOf(blockchainHeight)));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownAcceptanceTestBase() {
|
||||
privacyCluster.close();
|
||||
vertx.close();
|
||||
}
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.bft.ConsensusType;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class BftPrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
private final BftPrivacyType bftPrivacyType;
|
||||
|
||||
public static class BftPrivacyType {
|
||||
private final EnclaveType enclaveType;
|
||||
private final EnclaveEncryptorType enclaveEncryptorType;
|
||||
private final ConsensusType consensusType;
|
||||
private final Restriction restriction;
|
||||
|
||||
public BftPrivacyType(
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType,
|
||||
final ConsensusType consensusType,
|
||||
final Restriction restriction) {
|
||||
this.enclaveType = enclaveType;
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
this.consensusType = consensusType;
|
||||
this.restriction = restriction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.join(
|
||||
",",
|
||||
enclaveType.toString(),
|
||||
enclaveEncryptorType.toString(),
|
||||
consensusType.toString(),
|
||||
restriction.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public BftPrivacyClusterAcceptanceTest(final BftPrivacyType bftPrivacyType) {
|
||||
this.bftPrivacyType = bftPrivacyType;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static Collection<BftPrivacyType> bftPrivacyTypes() {
|
||||
final List<BftPrivacyType> bftPrivacyTypes = new ArrayList<>();
|
||||
for (EnclaveType x : EnclaveType.valuesForTests()) {
|
||||
for (ConsensusType consensusType : ConsensusType.values()) {
|
||||
bftPrivacyTypes.add(
|
||||
new BftPrivacyType(
|
||||
x, EnclaveEncryptorType.NACL, consensusType, Restriction.RESTRICTED));
|
||||
bftPrivacyTypes.add(
|
||||
new BftPrivacyType(x, EnclaveEncryptorType.EC, consensusType, Restriction.RESTRICTED));
|
||||
}
|
||||
}
|
||||
|
||||
for (ConsensusType consensusType : ConsensusType.values()) {
|
||||
bftPrivacyTypes.add(
|
||||
new BftPrivacyType(
|
||||
EnclaveType.NOOP,
|
||||
EnclaveEncryptorType.NOOP,
|
||||
consensusType,
|
||||
Restriction.UNRESTRICTED));
|
||||
}
|
||||
|
||||
return bftPrivacyTypes;
|
||||
}
|
||||
|
||||
private PrivacyNode alice;
|
||||
private PrivacyNode bob;
|
||||
private PrivacyNode charlie;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
alice = createNode(containerNetwork, "node1", 0);
|
||||
bob = createNode(containerNetwork, "node2", 1);
|
||||
charlie = createNode(containerNetwork, "node3", 2);
|
||||
|
||||
privacyCluster.start(alice, bob, charlie);
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
charlie.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
private PrivacyNode createNode(
|
||||
final Network containerNetwork, final String nodeName, final int privacyAccount)
|
||||
throws IOException {
|
||||
if (bftPrivacyType.consensusType == ConsensusType.IBFT2) {
|
||||
return privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
nodeName,
|
||||
PrivacyAccountResolver.values()[privacyAccount].resolve(
|
||||
bftPrivacyType.enclaveEncryptorType),
|
||||
true,
|
||||
bftPrivacyType.enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
bftPrivacyType.restriction == Restriction.UNRESTRICTED,
|
||||
"0xAA");
|
||||
} else if (bftPrivacyType.consensusType == ConsensusType.QBFT) {
|
||||
return privacyBesu.createQbftNodePrivacyEnabled(
|
||||
nodeName,
|
||||
PrivacyAccountResolver.values()[privacyAccount].resolve(
|
||||
bftPrivacyType.enclaveEncryptorType),
|
||||
bftPrivacyType.enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
bftPrivacyType.restriction == Restriction.UNRESTRICTED,
|
||||
"0xAA");
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown consensus type " + bftPrivacyType.consensusType);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyAliceAndBobCanExecuteContract() {
|
||||
// Contract address is generated from sender address and transaction nonce
|
||||
final String contractAddress =
|
||||
EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contractAddress, alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final String transactionHash =
|
||||
alice.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
bftPrivacyType.restriction,
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
final PrivateTransactionReceipt expectedReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
|
||||
bob.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash, expectedReceipt));
|
||||
|
||||
if (bftPrivacyType.restriction != Restriction.UNRESTRICTED) {
|
||||
charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(transactionHash));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliceCanDeployMultipleTimesInSingleGroup() {
|
||||
final String firstDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
privacyCluster.stopNode(charlie);
|
||||
|
||||
final EventEmitter firstEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString())
|
||||
.verify(firstEventEmitter);
|
||||
|
||||
final String secondDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType)
|
||||
? "0x5194e214fae257530710d18c868df7a295d9d53b"
|
||||
: "0x10f807f8a905da5bd319196da7523c6bd768690f";
|
||||
|
||||
final EventEmitter secondEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(secondDeployedAddress, alice.getAddress().toString())
|
||||
.verify(secondEventEmitter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInteractWithMultiplePrivacyGroups() {
|
||||
// alice deploys contract
|
||||
final String firstDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType)
|
||||
? "0x760359bc605b3848f5199829bde6b382d90fb8eb"
|
||||
: "0xff206d21150a8da5b83629d8a722f3135ed532b1";
|
||||
|
||||
final EventEmitter firstEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey(),
|
||||
charlie.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString())
|
||||
.verify(firstEventEmitter);
|
||||
|
||||
// charlie interacts with contract
|
||||
final String firstTransactionHash =
|
||||
charlie.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
firstEventEmitter.getContractAddress(),
|
||||
firstEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
charlie.getTransactionSigningKey(),
|
||||
bftPrivacyType.restriction,
|
||||
charlie.getEnclaveKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
// alice gets receipt from charlie's interaction
|
||||
final PrivateTransactionReceipt aliceReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(firstTransactionHash));
|
||||
|
||||
// verify bob and charlie have access to the same receipt
|
||||
bob.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
firstTransactionHash, aliceReceipt));
|
||||
charlie.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
firstTransactionHash, aliceReceipt));
|
||||
|
||||
// alice deploys second contract
|
||||
final String secondDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(bftPrivacyType.enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter secondEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(secondDeployedAddress, alice.getAddress().toString())
|
||||
.verify(secondEventEmitter);
|
||||
|
||||
// bob interacts with contract
|
||||
final String secondTransactionHash =
|
||||
bob.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
secondEventEmitter.getContractAddress(),
|
||||
secondEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
bob.getTransactionSigningKey(),
|
||||
bftPrivacyType.restriction,
|
||||
bob.getEnclaveKey(),
|
||||
alice.getEnclaveKey()));
|
||||
|
||||
// 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
|
||||
if (bftPrivacyType.restriction != Restriction.UNRESTRICTED) {
|
||||
charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(secondTransactionHash));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class DeployPrivateSmartContractAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode minerNode;
|
||||
|
||||
public DeployPrivateSmartContractAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
minerNode =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(minerNode);
|
||||
minerNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deployingMustGiveValidReceiptAndCode() throws Exception {
|
||||
final String contractAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0xfeeb2367e77e28f75fc3bcc55b70a535752db058"
|
||||
: "0x89ce396d0f9f937ddfa71113e29b2081c4869555";
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
minerNode.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contractAddress, minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
privateContractVerifier.validContractCodeProvided().verify(eventEmitter);
|
||||
}
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.crypto.sodium.Box;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class EnclaveErrorAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
|
||||
private final PrivacyNode alice;
|
||||
private final PrivacyNode bob;
|
||||
private final String wrongPublicKey;
|
||||
|
||||
@Parameters(name = "{0} enclave type with {1} encryptor")
|
||||
public static Collection<Object[]> enclaveParameters() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{TESSERA, NACL},
|
||||
{TESSERA, EC}
|
||||
});
|
||||
}
|
||||
|
||||
public EnclaveErrorAcceptanceTest(
|
||||
final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
alice =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"0xAA");
|
||||
bob =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"node2",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"0xBB");
|
||||
privacyCluster.start(alice, bob);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
|
||||
final byte[] wrongPublicKeyBytes =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? getSECP256r1PublicKeyByteArray()
|
||||
: Box.KeyPair.random().publicKey().bytesArray();
|
||||
|
||||
wrongPublicKey = Base64.getEncoder().encodeToString(wrongPublicKeyBytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliceCannotSendTransactionFromBobNode() {
|
||||
final Throwable throwable =
|
||||
catchThrowable(
|
||||
() ->
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
wrongPublicKey,
|
||||
bob.getEnclaveKey())));
|
||||
|
||||
assertThat(throwable)
|
||||
.hasMessageContaining(
|
||||
RpcErrorType.PRIVATE_FROM_DOES_NOT_MATCH_ENCLAVE_PUBLIC_KEY.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enclaveNoPeerUrlError() {
|
||||
final Throwable throwable =
|
||||
catchThrowable(
|
||||
() ->
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
wrongPublicKey)));
|
||||
|
||||
final String tesseraMessage = RpcErrorType.TESSERA_NODE_MISSING_PEER_URL.getMessage();
|
||||
|
||||
assertThat(throwable.getMessage()).has(matchTesseraEnclaveMessage(tesseraMessage));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenEnclaveIsDisconnectedGetReceiptReturnsInternalError() {
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final String transactionHash =
|
||||
alice.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
Restriction.RESTRICTED,
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
final PrivateTransactionReceipt receiptBeforeEnclaveLosesConnection =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
|
||||
alice.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash, receiptBeforeEnclaveLosesConnection));
|
||||
|
||||
alice.getEnclave().stop();
|
||||
|
||||
alice.verify(
|
||||
privateTransactionVerifier.internalErrorPrivateTransactionReceipt(transactionHash));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Web3J is broken by PR #1426")
|
||||
public void transactionFailsIfPartyIsOffline() {
|
||||
// Contract address is generated from sender address and transaction nonce
|
||||
final String contractAddress = "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contractAddress, alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
bob.getEnclave().stop();
|
||||
|
||||
final Throwable throwable =
|
||||
catchThrowable(
|
||||
() ->
|
||||
alice.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
Restriction.RESTRICTED,
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey())));
|
||||
|
||||
assertThat(throwable).hasMessageContaining("NodePropagatingToAllPeers");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivacyGroupReturnsCorrectError() {
|
||||
final Throwable throwable =
|
||||
catchThrowable(() -> alice.execute(privacyTransactions.createPrivacyGroup(null, null)));
|
||||
final String tesseraMessage = RpcErrorType.TESSERA_CREATE_GROUP_INCLUDE_SELF.getMessage();
|
||||
|
||||
assertThat(throwable.getMessage()).has(matchTesseraEnclaveMessage(tesseraMessage));
|
||||
}
|
||||
|
||||
private Condition<String> matchTesseraEnclaveMessage(final String enclaveMessage) {
|
||||
return new Condition<>(
|
||||
message -> message.contains(enclaveMessage),
|
||||
"Message did not match Tessera expected output");
|
||||
}
|
||||
|
||||
private byte[] getSECP256r1PublicKeyByteArray() {
|
||||
try {
|
||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
|
||||
final ECGenParameterSpec spec = new ECGenParameterSpec("secp256r1");
|
||||
keyGen.initialize(spec);
|
||||
return keyGen.generateKeyPair().getPublic().getEncoded();
|
||||
} catch (Exception exception) {
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,642 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.FLEXIBLE_PRIVACY_PROXY;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
import static org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.condition.eth.EthConditions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.testcontainers.containers.Network;
|
||||
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;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
import org.web3j.tx.Contract;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class FlexiblePrivacyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase {
|
||||
|
||||
private final EnclaveType enclaveType;
|
||||
private final EnclaveEncryptorType enclaveEncryptorType;
|
||||
|
||||
public FlexiblePrivacyAcceptanceTest(
|
||||
final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType) {
|
||||
this.enclaveType = enclaveType;
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
}
|
||||
|
||||
@Parameters(name = "{0} enclave type with {1} encryptor")
|
||||
public static Collection<Object[]> enclaveParameters() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{TESSERA, NACL},
|
||||
{TESSERA, EC}
|
||||
});
|
||||
}
|
||||
|
||||
private PrivacyNode alice;
|
||||
private PrivacyNode bob;
|
||||
private PrivacyNode charlie;
|
||||
|
||||
private final MinerTransactions minerTransactions = new MinerTransactions();
|
||||
private final EthConditions ethConditions = new EthConditions(ethTransactions);
|
||||
|
||||
private static final String EXPECTED_STORE_OUTPUT_DATA =
|
||||
"0x000000000000000000000000f17f52151ebef6c7334fad080c5704d77216b7320000000000000000000000000000000000000000000000000000000000000539";
|
||||
private static final String EXPECTED_STORE_EVENT_TOPIC =
|
||||
"0xc9db20adedc6cf2b5d25252b101ab03e124902a73fcb12b753f3d1aaa2d8f9f5";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
alice =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork));
|
||||
bob =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledNode(
|
||||
"node2",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork));
|
||||
charlie =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledNode(
|
||||
"node3",
|
||||
PrivacyAccountResolver.CHARLIE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork));
|
||||
privacyCluster.start(alice, bob, charlie);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
charlie.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeCanCreatePrivacyGroup() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deployingMustGiveValidReceipt() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice, bob);
|
||||
final Contract eventEmitter = deployPrivateContract(EventEmitter.class, privacyGroupId, alice);
|
||||
final String commitmentHash = getContractDeploymentCommitmentHash(eventEmitter);
|
||||
|
||||
alice.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(commitmentHash));
|
||||
bob.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(commitmentHash));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canAddParticipantToGroup() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice, bob);
|
||||
final Contract eventEmitter = deployPrivateContract(EventEmitter.class, privacyGroupId, alice);
|
||||
final String commitmentHash = getContractDeploymentCommitmentHash(eventEmitter);
|
||||
|
||||
charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(commitmentHash));
|
||||
|
||||
final Credentials aliceCredentials = Credentials.create(alice.getTransactionSigningKey());
|
||||
lockPrivacyGroup(privacyGroupId, alice, aliceCredentials);
|
||||
addMembersToPrivacyGroup(privacyGroupId, alice, aliceCredentials, charlie);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob, charlie);
|
||||
|
||||
charlie.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(commitmentHash));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removedMemberCannotSendTransactionToGroup() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice, bob);
|
||||
|
||||
final String removeHash =
|
||||
removeFromPrivacyGroup(
|
||||
privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob);
|
||||
|
||||
bob.verify(privateTransactionVerifier.existingPrivateTransactionReceipt(removeHash));
|
||||
|
||||
assertThatThrownBy(() -> deployPrivateContract(EventEmitter.class, privacyGroupId, bob))
|
||||
.isInstanceOf(RuntimeException.class)
|
||||
.hasMessageContaining("Flexible Privacy group does not exist.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInteractWithPrivateGenesisPreCompile() throws Exception {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice, bob);
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.loadSmartContractWithPrivacyGroupId(
|
||||
"0x1000000000000000000000000000000000000001",
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateTransactionVerifier.existingPrivateTransactionReceipt(
|
||||
eventEmitter.store(BigInteger.valueOf(42)).send().getTransactionHash());
|
||||
|
||||
final String aliceResponse =
|
||||
alice
|
||||
.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()))
|
||||
.getValue();
|
||||
|
||||
assertThat(new BigInteger(aliceResponse.substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(42));
|
||||
|
||||
final String bobResponse =
|
||||
bob.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()))
|
||||
.getValue();
|
||||
|
||||
assertThat(new BigInteger(bobResponse.substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(42));
|
||||
|
||||
final String charlieResponse =
|
||||
charlie
|
||||
.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()))
|
||||
.getValue();
|
||||
|
||||
assertThat(charlieResponse).isEqualTo("0x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void memberCanBeAddedAfterBeingRemoved() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice);
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice);
|
||||
|
||||
lockPrivacyGroup(privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()));
|
||||
addMembersToPrivacyGroup(
|
||||
privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob);
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob);
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
deployPrivateContract(EventEmitter.class, privacyGroupId, alice);
|
||||
|
||||
final int valueSetWhileBobWasMember = 17;
|
||||
final PrivateTransactionReceipt receiptWhileBobMember =
|
||||
setEventEmitterValueAndCheck(
|
||||
Lists.newArrayList(alice, bob),
|
||||
privacyGroupId,
|
||||
eventEmitter,
|
||||
valueSetWhileBobWasMember);
|
||||
|
||||
removeFromPrivacyGroup(
|
||||
privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob);
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice);
|
||||
|
||||
final int valueSetWhileBobWas_NOT_aMember = 1337;
|
||||
final PrivateTransactionReceipt receiptWhileBobRemoved =
|
||||
setEventEmitterValueAndCheck(
|
||||
Lists.newArrayList(alice),
|
||||
privacyGroupId,
|
||||
eventEmitter,
|
||||
valueSetWhileBobWas_NOT_aMember);
|
||||
checkEmitterValue(
|
||||
Lists.newArrayList(bob),
|
||||
privacyGroupId,
|
||||
eventEmitter,
|
||||
valueSetWhileBobWasMember); // bob did not get the last transaction
|
||||
|
||||
lockPrivacyGroup(privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()));
|
||||
addMembersToPrivacyGroup(
|
||||
privacyGroupId, alice, Credentials.create(alice.getTransactionSigningKey()), bob);
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob);
|
||||
|
||||
checkEmitterValue(
|
||||
Lists.newArrayList(alice, bob),
|
||||
privacyGroupId,
|
||||
eventEmitter,
|
||||
valueSetWhileBobWas_NOT_aMember);
|
||||
|
||||
PrivateTransactionReceipt receipt =
|
||||
bob.execute(
|
||||
privacyTransactions.getPrivateTransactionReceipt(
|
||||
receiptWhileBobRemoved.getcommitmentHash()));
|
||||
assertThat(receipt.getStatus()).isEqualTo("0x1");
|
||||
|
||||
receipt =
|
||||
bob.execute(
|
||||
privacyTransactions.getPrivateTransactionReceipt(
|
||||
receiptWhileBobMember.getcommitmentHash()));
|
||||
assertThat(receipt.getStatus()).isEqualTo("0x1");
|
||||
}
|
||||
|
||||
PrivateTransactionReceipt setEventEmitterValueAndCheck(
|
||||
final List<PrivacyNode> nodes,
|
||||
final String privacyGroupId,
|
||||
final EventEmitter eventEmitter,
|
||||
final int value) {
|
||||
final PrivateTransactionReceipt receiptWhileBobMember =
|
||||
setEventEmitterValue(nodes, privacyGroupId, eventEmitter, value);
|
||||
|
||||
checkEmitterValue(nodes, privacyGroupId, eventEmitter, value);
|
||||
return receiptWhileBobMember;
|
||||
}
|
||||
|
||||
private PrivateTransactionReceipt setEventEmitterValue(
|
||||
final List<PrivacyNode> nodes,
|
||||
final String privacyGroupId,
|
||||
final EventEmitter eventEmitter,
|
||||
final int value) {
|
||||
final PrivacyNode firstNode = nodes.get(0);
|
||||
final String txHash =
|
||||
firstNode.execute(
|
||||
privateContractTransactions.callOnchainPermissioningSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.valueOf(value)).encodeFunctionCall(),
|
||||
firstNode.getTransactionSigningKey(),
|
||||
firstNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
PrivateTransactionReceipt receipt = null;
|
||||
for (final PrivacyNode node : nodes) {
|
||||
receipt = node.execute(privacyTransactions.getPrivateTransactionReceipt(txHash));
|
||||
assertThat(receipt.getStatus()).isEqualTo("0x1");
|
||||
}
|
||||
return receipt;
|
||||
}
|
||||
|
||||
private void checkEmitterValue(
|
||||
final List<PrivacyNode> nodes,
|
||||
final String privacyGroupId,
|
||||
final EventEmitter eventEmitter,
|
||||
final int expectedValue) {
|
||||
for (final PrivacyNode node : nodes) {
|
||||
final EthCall response =
|
||||
node.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()));
|
||||
|
||||
assertThat(new BigInteger(response.getValue().substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(expectedValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bobCanAddCharlieAfterBeingAddedByAlice() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice);
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final Credentials aliceCredentials = Credentials.create(alice.getTransactionSigningKey());
|
||||
final String aliceLockHash =
|
||||
alice.execute(
|
||||
privacyTransactions.privxLockPrivacyGroupAndCheck(
|
||||
privacyGroupId, alice, aliceCredentials));
|
||||
|
||||
alice.execute(
|
||||
privacyTransactions.addToPrivacyGroup(privacyGroupId, alice, aliceCredentials, bob));
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob);
|
||||
|
||||
bob.execute(
|
||||
privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, bob, aliceCredentials));
|
||||
|
||||
alice.execute(minerTransactions.minerStop());
|
||||
|
||||
alice.getBesu().verify(ethConditions.miningStatus(false));
|
||||
|
||||
final BigInteger pendingTransactionFilterId =
|
||||
alice.execute(ethTransactions.newPendingTransactionsFilter());
|
||||
|
||||
final String callHash =
|
||||
alice.execute(
|
||||
privateContractTransactions.callOnchainPermissioningSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.value().encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
final String bobAddHash =
|
||||
addMembersToPrivacyGroup(privacyGroupId, bob, aliceCredentials, charlie);
|
||||
|
||||
alice
|
||||
.getBesu()
|
||||
.verify(
|
||||
ethConditions.expectNewPendingTransactions(
|
||||
pendingTransactionFilterId, Arrays.asList(callHash, bobAddHash)));
|
||||
|
||||
alice.execute(minerTransactions.minerStart());
|
||||
|
||||
alice.getBesu().verify(ethConditions.miningStatus(true));
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob, charlie);
|
||||
|
||||
final Optional<TransactionReceipt> aliceAddReceipt =
|
||||
alice.execute(ethTransactions.getTransactionReceipt(bobAddHash));
|
||||
assertThat(aliceAddReceipt.get().getStatus())
|
||||
.isEqualTo("0x1"); // this means the PMT for the "add" succeeded which is what we expect
|
||||
|
||||
final Optional<TransactionReceipt> alicePublicReceipt =
|
||||
alice.execute(ethTransactions.getTransactionReceipt(callHash));
|
||||
if (alicePublicReceipt.isPresent()) {
|
||||
assertThat(alicePublicReceipt.get().getBlockHash())
|
||||
.isEqualTo(
|
||||
aliceAddReceipt
|
||||
.get()
|
||||
.getBlockHash()); // ensure that "add" and "call" are in the same block
|
||||
assertThat(alicePublicReceipt.get().getStatus())
|
||||
.isEqualTo(
|
||||
"0x1"); // this means the PMT for the "call" succeeded which is what we expect because
|
||||
// it is in the same block as the "add" and there is no way to tell that this
|
||||
// will happen before the block is mined
|
||||
}
|
||||
|
||||
final PrivateTransactionReceipt aliceReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(callHash));
|
||||
assertThat(aliceReceipt.getStatus())
|
||||
.isEqualTo(
|
||||
"0x0"); // this means the "call" failed which is what we expect because the group was
|
||||
// locked!
|
||||
final PrivateTransactionReceipt bobReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(callHash));
|
||||
assertThat(bobReceipt.getStatus())
|
||||
.isEqualTo(
|
||||
"0x0"); // this means the "call" failed which is what we expect because the group was
|
||||
// locked!
|
||||
|
||||
// assert charlie can access private transaction information from before he was added
|
||||
final PrivateTransactionReceipt expectedAliceLockReceipt =
|
||||
new PrivateTransactionReceipt(
|
||||
null,
|
||||
alice.getAddress().toHexString(),
|
||||
FLEXIBLE_PRIVACY_PROXY.toHexString(),
|
||||
"0x",
|
||||
Collections.emptyList(),
|
||||
null,
|
||||
null,
|
||||
alice.getEnclaveKey(),
|
||||
null,
|
||||
privacyGroupId,
|
||||
"0x1",
|
||||
null);
|
||||
charlie.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
aliceLockHash, expectedAliceLockReceipt));
|
||||
|
||||
final String aliceStoreHash =
|
||||
charlie.execute(
|
||||
privateContractTransactions.callOnchainPermissioningSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.valueOf(1337)).encodeFunctionCall(),
|
||||
charlie.getTransactionSigningKey(),
|
||||
charlie.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
final PrivateTransactionReceipt expectedStoreReceipt =
|
||||
new PrivateTransactionReceipt(
|
||||
null,
|
||||
charlie.getAddress().toHexString(),
|
||||
eventEmitter.getContractAddress(),
|
||||
"0x",
|
||||
Collections.singletonList(
|
||||
new Log(
|
||||
false,
|
||||
"0x0",
|
||||
"0x0",
|
||||
aliceStoreHash,
|
||||
null,
|
||||
null,
|
||||
eventEmitter.getContractAddress(),
|
||||
EXPECTED_STORE_OUTPUT_DATA,
|
||||
null,
|
||||
Collections.singletonList(EXPECTED_STORE_EVENT_TOPIC))),
|
||||
null,
|
||||
null,
|
||||
charlie.getEnclaveKey(),
|
||||
null,
|
||||
privacyGroupId,
|
||||
"0x1",
|
||||
null);
|
||||
|
||||
alice.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
aliceStoreHash, expectedStoreReceipt));
|
||||
|
||||
bob.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
aliceStoreHash, expectedStoreReceipt));
|
||||
|
||||
charlie.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
aliceStoreHash, expectedStoreReceipt));
|
||||
|
||||
removeFromPrivacyGroup(privacyGroupId, bob, aliceCredentials, charlie);
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice, bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canOnlyCallProxyContractWhenGroupLocked() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(alice);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId, alice);
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final Credentials aliceCredentials = Credentials.create(alice.getTransactionSigningKey());
|
||||
|
||||
final Supplier<String> callContract =
|
||||
() -> {
|
||||
return alice.execute(
|
||||
privateContractTransactions.callOnchainPermissioningSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.value().encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
};
|
||||
|
||||
final String lockHash =
|
||||
alice.execute(
|
||||
privacyTransactions.privxLockPrivacyGroupAndCheck(
|
||||
privacyGroupId, alice, aliceCredentials));
|
||||
|
||||
final String callWhileLockedHash = callContract.get();
|
||||
|
||||
final String unlockHash =
|
||||
alice.execute(
|
||||
privacyTransactions.privxUnlockPrivacyGroupAndCheck(
|
||||
privacyGroupId, alice, aliceCredentials));
|
||||
|
||||
final String callAfterUnlockedHash = callContract.get();
|
||||
|
||||
alice.execute(minerTransactions.minerStart());
|
||||
alice.getBesu().verify(ethConditions.miningStatus(true));
|
||||
|
||||
final BiConsumer<String, String> assertThatTransactionReceiptIs =
|
||||
(String hash, String expectedResult) -> {
|
||||
final PrivateTransactionReceipt receipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(hash));
|
||||
assertThat(receipt.getStatus()).isEqualTo(expectedResult);
|
||||
};
|
||||
|
||||
// when locking a group succeeds ...
|
||||
assertThatTransactionReceiptIs.accept(lockHash, "0x1");
|
||||
// ... calls to contracts fail ...
|
||||
assertThatTransactionReceiptIs.accept(callWhileLockedHash, "0x0");
|
||||
// ... but unlock the group works ...
|
||||
assertThatTransactionReceiptIs.accept(unlockHash, "0x1");
|
||||
// ... and afterwards we can call contracts again
|
||||
assertThatTransactionReceiptIs.accept(callAfterUnlockedHash, "0x1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMembersToTwoGroupsInTheSameBlock() {
|
||||
final String privacyGroupId1 = createFlexiblePrivacyGroup(alice);
|
||||
final String privacyGroupId2 = createFlexiblePrivacyGroup(bob);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId1, alice);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId2, bob);
|
||||
|
||||
lockPrivacyGroup(privacyGroupId1, alice, Credentials.create(alice.getTransactionSigningKey()));
|
||||
lockPrivacyGroup(privacyGroupId2, bob, Credentials.create(bob.getTransactionSigningKey()));
|
||||
|
||||
final BigInteger pendingTransactionFilterId =
|
||||
alice.execute(ethTransactions.newPendingTransactionsFilter());
|
||||
|
||||
alice.execute(minerTransactions.minerStop());
|
||||
alice.getBesu().verify(ethConditions.miningStatus(false));
|
||||
|
||||
final String aliceAddHash =
|
||||
addMembersToPrivacyGroup(
|
||||
privacyGroupId1, alice, Credentials.create(alice.getTransactionSigningKey()), charlie);
|
||||
final String bobAddHash =
|
||||
addMembersToPrivacyGroup(
|
||||
privacyGroupId2, bob, Credentials.create(bob.getTransactionSigningKey()), alice);
|
||||
|
||||
alice
|
||||
.getBesu()
|
||||
.verify(
|
||||
ethConditions.expectNewPendingTransactions(
|
||||
pendingTransactionFilterId, Arrays.asList(aliceAddHash, bobAddHash)));
|
||||
|
||||
alice.execute(minerTransactions.minerStart());
|
||||
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId1, alice, charlie);
|
||||
checkFlexiblePrivacyGroupExists(privacyGroupId2, bob, alice);
|
||||
}
|
||||
|
||||
private <T extends Contract> T deployPrivateContract(
|
||||
final Class<T> clazz, final String privacyGroupId, final PrivacyNode sender) {
|
||||
final T contract =
|
||||
sender.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
clazz, sender.getTransactionSigningKey(), sender.getEnclaveKey(), privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contract.getContractAddress(), sender.getAddress().toString())
|
||||
.verify(contract);
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
private String addMembersToPrivacyGroup(
|
||||
final String privacyGroupId,
|
||||
final PrivacyNode nodeAddingMember,
|
||||
final Credentials signer,
|
||||
final PrivacyNode... newMembers) {
|
||||
return nodeAddingMember.execute(
|
||||
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.getEnclaveKey(),
|
||||
signer,
|
||||
memberBeingRemoved.getEnclaveKey()));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will send a transaction to lock the privacy group identified by the specified id.
|
||||
* This also checks if the lock transaction was successful.
|
||||
*
|
||||
* @return the hash of the lock privacy group transaction
|
||||
*/
|
||||
private String lockPrivacyGroup(
|
||||
final String privacyGroupId, final PrivacyNode member, final Credentials signer) {
|
||||
return member.execute(
|
||||
privacyTransactions.privxLockPrivacyGroupAndCheck(privacyGroupId, member, signer));
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.FLEXIBLE_PRIVACY_PROXY;
|
||||
import static org.hyperledger.besu.ethereum.privacy.group.FlexibleGroupManagement.GET_PARTICIPANTS_METHOD_SIGNATURE;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.condition.ExpectValidFlexiblePrivacyGroupCreated;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.CreateFlexiblePrivacyGroupTransaction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.web3j.abi.FunctionEncoder;
|
||||
import org.web3j.abi.Utils;
|
||||
import org.web3j.abi.datatypes.DynamicArray;
|
||||
import org.web3j.abi.datatypes.DynamicBytes;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
import org.web3j.tx.Contract;
|
||||
import org.web3j.utils.Base64String;
|
||||
|
||||
public class FlexiblePrivacyAcceptanceTestBase extends PrivacyAcceptanceTestBase {
|
||||
|
||||
protected String createFlexiblePrivacyGroup(final PrivacyNode... members) {
|
||||
final List<String> addresses =
|
||||
Arrays.stream(members).map(PrivacyNode::getEnclaveKey).collect(Collectors.toList());
|
||||
return createFlexiblePrivacyGroup(members[0].getEnclaveKey(), addresses, members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an flexible privacy group. The privacy group id will be randomly generated.
|
||||
*
|
||||
* <p>This method also checks that each node member has successfully processed the transaction and
|
||||
* has the expected list of member for the group.
|
||||
*
|
||||
* @param members the list of members of the privacy group. The first member of the list will be
|
||||
* the creator of the group.
|
||||
* @return the id of the privacy group
|
||||
*/
|
||||
protected String createFlexiblePrivacyGroup(
|
||||
final String privateFrom, final List<String> addresses, final PrivacyNode... members) {
|
||||
|
||||
final PrivacyNode groupCreator = members[0];
|
||||
|
||||
final CreateFlexiblePrivacyGroupTransaction createTx =
|
||||
privacyTransactions.createFlexiblePrivacyGroup(groupCreator, privateFrom, addresses);
|
||||
|
||||
final PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse createResponse =
|
||||
groupCreator.execute(createTx);
|
||||
final String privacyGroupId = createResponse.getPrivacyGroupId();
|
||||
|
||||
final List<Base64String> membersEnclaveKeys =
|
||||
Arrays.stream(members)
|
||||
.map(m -> Base64String.wrap(m.getEnclaveKey()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (final PrivacyNode member : members) {
|
||||
member.verify(flexiblePrivacyGroupExists(privacyGroupId, membersEnclaveKeys));
|
||||
}
|
||||
|
||||
final String commitmentHash =
|
||||
callGetParticipantsMethodAndReturnCommitmentHash(privacyGroupId, groupCreator, privateFrom);
|
||||
final PrivateTransactionReceipt expectedReceipt =
|
||||
buildExpectedAddMemberTransactionReceipt(privacyGroupId, groupCreator, addresses);
|
||||
|
||||
for (final PrivacyNode member : members) {
|
||||
member.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
commitmentHash, expectedReceipt));
|
||||
}
|
||||
|
||||
return privacyGroupId;
|
||||
}
|
||||
|
||||
protected String callGetParticipantsMethodAndReturnCommitmentHash(
|
||||
final String privacyGroupId, final PrivacyNode groupCreator, final String privateFrom) {
|
||||
return groupCreator.execute(
|
||||
privateContractTransactions.callOnchainPermissioningSmartContract(
|
||||
FLEXIBLE_PRIVACY_PROXY.toHexString(),
|
||||
GET_PARTICIPANTS_METHOD_SIGNATURE.toString(),
|
||||
groupCreator.getTransactionSigningKey(),
|
||||
privateFrom,
|
||||
privacyGroupId));
|
||||
}
|
||||
|
||||
protected PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt(
|
||||
final String privacyGroupId, final PrivacyNode groupCreator, final List<String> members) {
|
||||
return buildExpectedAddMemberTransactionReceipt(
|
||||
privacyGroupId, groupCreator, groupCreator.getEnclaveKey(), members);
|
||||
}
|
||||
|
||||
protected PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt(
|
||||
final String privacyGroupId,
|
||||
final PrivacyNode groupCreator,
|
||||
final String privateFrom,
|
||||
final List<String> members) {
|
||||
|
||||
final StringBuilder output = new StringBuilder();
|
||||
// hex prefix
|
||||
output.append("0x");
|
||||
|
||||
final String encodedParameters =
|
||||
FunctionEncoder.encode(
|
||||
"",
|
||||
Arrays.asList(
|
||||
new DynamicArray<>(
|
||||
DynamicBytes.class,
|
||||
Utils.typeMap(
|
||||
members.stream()
|
||||
.map(Bytes::fromBase64String)
|
||||
.map(Bytes::toArrayUnsafe)
|
||||
.collect(Collectors.toList()),
|
||||
DynamicBytes.class))));
|
||||
|
||||
output.append(encodedParameters);
|
||||
|
||||
return new PrivateTransactionReceipt(
|
||||
null,
|
||||
groupCreator.getAddress().toHexString(),
|
||||
FLEXIBLE_PRIVACY_PROXY.toHexString(),
|
||||
output.toString(),
|
||||
Collections.emptyList(),
|
||||
null,
|
||||
null,
|
||||
privateFrom,
|
||||
null,
|
||||
privacyGroupId,
|
||||
"0x1",
|
||||
null);
|
||||
}
|
||||
|
||||
protected ExpectValidFlexiblePrivacyGroupCreated flexiblePrivacyGroupExists(
|
||||
final String privacyGroupId, final List<Base64String> members) {
|
||||
return privateTransactionVerifier.flexiblePrivacyGroupExists(privacyGroupId, members);
|
||||
}
|
||||
|
||||
protected String getContractDeploymentCommitmentHash(final Contract contract) {
|
||||
final Optional<TransactionReceipt> transactionReceipt = contract.getTransactionReceipt();
|
||||
assertThat(transactionReceipt).isPresent();
|
||||
final PrivateTransactionReceipt privateTransactionReceipt =
|
||||
(PrivateTransactionReceipt) transactionReceipt.get();
|
||||
return privateTransactionReceipt.getcommitmentHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will check if a privacy group with the specified id and list of members exists.
|
||||
* Each one of the members node will be queried to ensure that they all have the same privacy
|
||||
* group in their private state.
|
||||
*
|
||||
* @param privacyGroupId the id of the privacy group
|
||||
* @param members the list of member in the privacy group
|
||||
*/
|
||||
protected void checkFlexiblePrivacyGroupExists(
|
||||
final String privacyGroupId, final PrivacyNode... members) {
|
||||
final List<Base64String> membersEnclaveKeys =
|
||||
Arrays.stream(members)
|
||||
.map(PrivacyNode::getEnclaveKey)
|
||||
.map(Base64String::wrap)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (final PrivacyNode member : members) {
|
||||
member.verify(flexiblePrivacyGroupExists(privacyGroupId, membersEnclaveKeys));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.privacy.PrivacyNodeConfiguration;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccount;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.web3j.protocol.core.DefaultBlockParameter;
|
||||
import org.web3j.protocol.core.methods.response.EthBlock.Block;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class PluginPrivacySigningAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
private PrivacyNode minerNode;
|
||||
|
||||
private final EnclaveEncryptorType enclaveEncryptorType;
|
||||
|
||||
public PluginPrivacySigningAcceptanceTest(final EnclaveEncryptorType enclaveEncryptorType) {
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
public static Collection<EnclaveEncryptorType> enclaveEncryptorTypes() {
|
||||
return Arrays.stream(EnclaveEncryptorType.values())
|
||||
.filter(encryptorType -> !EnclaveEncryptorType.NOOP.equals(encryptorType))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
final PrivacyAccount BOB = PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType);
|
||||
|
||||
minerNode =
|
||||
privacyBesu.create(
|
||||
new PrivacyNodeConfiguration(
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
new BesuNodeConfigurationBuilder()
|
||||
.name("miner")
|
||||
.miningEnabled()
|
||||
.jsonRpcEnabled()
|
||||
.webSocketEnabled()
|
||||
.enablePrivateTransactions()
|
||||
.keyFilePath(BOB.getPrivateKeyPath())
|
||||
.plugins(Collections.singletonList("testPlugins"))
|
||||
.extraCLIOptions(
|
||||
List.of(
|
||||
"--plugin-privacy-service-encryption-prefix=0xAA",
|
||||
"--plugin-privacy-service-signing-enabled=true",
|
||||
"--plugin-privacy-service-signing-key=8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63"))
|
||||
.build(),
|
||||
new EnclaveKeyConfiguration(
|
||||
BOB.getEnclaveKeyPaths(),
|
||||
BOB.getEnclavePrivateKeyPaths(),
|
||||
BOB.getEnclaveEncryptorType())),
|
||||
EnclaveType.NOOP,
|
||||
Optional.empty());
|
||||
|
||||
privacyCluster.start(minerNode);
|
||||
|
||||
minerNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canDeployContractSignedByPlugin() throws Exception {
|
||||
final String contractAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0xf01ec73d91fdeb8bb9388ec74e6a3981da86e021"
|
||||
: "0xd0152772c54cecfa7684f09f7616dcc825545dff";
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
minerNode.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contractAddress, minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
privateContractVerifier.validContractCodeProvided().verify(eventEmitter);
|
||||
|
||||
final BigInteger blockNumberContractDeployed =
|
||||
eventEmitter.getTransactionReceipt().get().getBlockNumber();
|
||||
final Block blockContractDeployed =
|
||||
minerNode.execute(
|
||||
ethTransactions.block(DefaultBlockParameter.valueOf(blockNumberContractDeployed)));
|
||||
|
||||
assertThat(blockContractDeployed.getTransactions().size()).isEqualTo(1);
|
||||
|
||||
final String transactionHashContractDeployed =
|
||||
(String) blockContractDeployed.getTransactions().get(0).get();
|
||||
final TransactionReceipt pmtReceipt =
|
||||
minerNode
|
||||
.execute(ethTransactions.getTransactionReceipt(transactionHashContractDeployed))
|
||||
.get();
|
||||
|
||||
assertThat(pmtReceipt.getStatus()).isEqualTo("0x1");
|
||||
assertThat(pmtReceipt.getFrom()).isEqualTo("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73");
|
||||
}
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.tests.web3j.generated.RevertReason.FUNC_REVERTWITHREVERTREASON;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.besu.tests.web3j.generated.RevertReason;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.junit.Test;
|
||||
import org.web3j.abi.FunctionEncoder;
|
||||
import org.web3j.abi.TypeReference;
|
||||
import org.web3j.abi.datatypes.Bool;
|
||||
import org.web3j.abi.datatypes.Function;
|
||||
import org.web3j.abi.datatypes.Type;
|
||||
import org.web3j.abi.datatypes.generated.Uint256;
|
||||
import org.web3j.protocol.core.Request;
|
||||
import org.web3j.protocol.core.methods.request.Transaction;
|
||||
import org.web3j.protocol.core.methods.response.EthCall;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
import org.web3j.protocol.http.HttpService;
|
||||
import org.web3j.tx.Contract;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivCallAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private static final int VALUE = 1024;
|
||||
|
||||
private final PrivacyNode minerNode;
|
||||
|
||||
public PrivCallAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
minerNode =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(minerNode);
|
||||
minerNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustReturnCorrectValue() throws Exception {
|
||||
|
||||
final String privacyGroupId =
|
||||
minerNode.execute(createPrivacyGroup("myGroupName", "my group description", minerNode));
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
restriction,
|
||||
minerNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final Request<Object, EthCall> priv_call =
|
||||
privCall(privacyGroupId, eventEmitter, false, false, false);
|
||||
|
||||
EthCall resp = priv_call.send();
|
||||
|
||||
String value = resp.getValue();
|
||||
assertThat(new BigInteger(value.substring(2), 16)).isEqualByComparingTo(BigInteger.ZERO);
|
||||
|
||||
final TransactionReceipt receipt = eventEmitter.store(BigInteger.valueOf(VALUE)).send();
|
||||
assertThat(receipt).isNotNull();
|
||||
|
||||
resp = priv_call.send();
|
||||
value = resp.getValue();
|
||||
assertThat(new BigInteger(value.substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustRevertWithRevertReason() throws Exception {
|
||||
|
||||
final String privacyGroupId =
|
||||
minerNode.execute(createPrivacyGroup("myGroupName", "my group description", minerNode));
|
||||
|
||||
final RevertReason revertReasonContract =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
RevertReason.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
restriction,
|
||||
minerNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
revertReasonContract.getContractAddress(), minerNode.getAddress().toString())
|
||||
.verify(revertReasonContract);
|
||||
|
||||
final Request<Object, EthCall> priv_call =
|
||||
privCall(privacyGroupId, revertReasonContract, false, false, true);
|
||||
|
||||
EthCall resp = priv_call.send();
|
||||
assertThat(resp.getRevertReason()).isEqualTo("Execution reverted: RevertReason");
|
||||
|
||||
byte[] bytes = Hex.decode(resp.getError().getData().substring(3, 203));
|
||||
String revertMessage =
|
||||
new String(Arrays.copyOfRange(bytes, 4, bytes.length), Charset.defaultCharset()).trim();
|
||||
assertThat(revertMessage).isEqualTo("RevertReason");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnEmptyResultWithNonExistingPrivacyGroup() throws IOException {
|
||||
|
||||
final String privacyGroupId =
|
||||
minerNode.execute(createPrivacyGroup("myGroupName", "my group description", minerNode));
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
restriction,
|
||||
minerNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final String invalidPrivacyGroup = constructInvalidString(privacyGroupId);
|
||||
final Request<Object, EthCall> privCall =
|
||||
privCall(invalidPrivacyGroup, eventEmitter, false, false, false);
|
||||
|
||||
final EthCall result = privCall.send();
|
||||
|
||||
assertThat(result.getResult()).isEqualTo("0x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustNotSucceedWithWronglyEncodedFunction() throws IOException {
|
||||
|
||||
final String privacyGroupId =
|
||||
minerNode.execute(createPrivacyGroup("myGroupName", "my group description", minerNode));
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
restriction,
|
||||
minerNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final Request<Object, EthCall> priv_call =
|
||||
privCall(privacyGroupId, eventEmitter, true, false, false);
|
||||
|
||||
final String errorMessage = priv_call.send().getError().getMessage();
|
||||
assertThat(errorMessage).isEqualTo("Private transaction failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustReturn0xUsingInvalidContractAddress() throws IOException {
|
||||
|
||||
final String privacyGroupId =
|
||||
minerNode.execute(createPrivacyGroup("myGroupName", "my group description", minerNode));
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
minerNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
minerNode.getTransactionSigningKey(),
|
||||
restriction,
|
||||
minerNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), minerNode.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final Request<Object, EthCall> priv_call =
|
||||
privCall(privacyGroupId, eventEmitter, false, true, false);
|
||||
|
||||
final EthCall result = priv_call.send();
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getResult()).isEqualTo("0x");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private String constructInvalidString(final String privacyGroupId) {
|
||||
final char[] chars = privacyGroupId.toCharArray();
|
||||
if (chars[3] == '0') {
|
||||
chars[3] = '1';
|
||||
} else {
|
||||
chars[3] = '0';
|
||||
}
|
||||
return String.valueOf(chars);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Request<Object, EthCall> privCall(
|
||||
final String privacyGroupId,
|
||||
final Contract contract,
|
||||
final boolean useInvalidParameters,
|
||||
final boolean useInvalidContractAddress,
|
||||
final boolean useRevertFunction) {
|
||||
|
||||
final Uint256 invalid = new Uint256(BigInteger.TEN);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
final List<Type> inputParameters =
|
||||
useInvalidParameters ? Arrays.asList(invalid) : Collections.emptyList();
|
||||
|
||||
final Function function =
|
||||
useRevertFunction
|
||||
? new Function(
|
||||
FUNC_REVERTWITHREVERTREASON,
|
||||
inputParameters,
|
||||
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {}))
|
||||
: new Function(
|
||||
"value",
|
||||
inputParameters,
|
||||
Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
|
||||
|
||||
final String encoded = FunctionEncoder.encode(function);
|
||||
|
||||
final HttpService httpService =
|
||||
new HttpService(
|
||||
"http://"
|
||||
+ minerNode.getBesu().getHostName()
|
||||
+ ":"
|
||||
+ minerNode.getBesu().getJsonRpcPort().get());
|
||||
|
||||
final String validContractAddress = contract.getContractAddress();
|
||||
final String invalidContractAddress = constructInvalidString(validContractAddress);
|
||||
final String contractAddress =
|
||||
useInvalidContractAddress ? invalidContractAddress : validContractAddress;
|
||||
|
||||
final Transaction transaction =
|
||||
Transaction.createEthCallTransaction(null, contractAddress, encoded);
|
||||
|
||||
return new Request<>(
|
||||
"priv_call",
|
||||
Arrays.asList(privacyGroupId, transaction, "latest"),
|
||||
httpService,
|
||||
EthCall.class);
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes32;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.testcontainers.containers.Network;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class PrivDebugGetStateRootFlexibleGroupAcceptanceTest
|
||||
extends FlexiblePrivacyAcceptanceTestBase {
|
||||
|
||||
private final EnclaveType enclaveType;
|
||||
|
||||
public PrivDebugGetStateRootFlexibleGroupAcceptanceTest(final EnclaveType enclaveType) {
|
||||
this.enclaveType = enclaveType;
|
||||
}
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static Collection<EnclaveType> enclaveTypes() {
|
||||
return EnclaveType.valuesForTests();
|
||||
}
|
||||
|
||||
private PrivacyNode aliceNode;
|
||||
private PrivacyNode bobNode;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException, URISyntaxException {
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
aliceNode =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode(
|
||||
"alice-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(EnclaveEncryptorType.NACL),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork));
|
||||
bobNode =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledNode(
|
||||
"bob-node",
|
||||
PrivacyAccountResolver.BOB.resolve(EnclaveEncryptorType.NACL),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork));
|
||||
|
||||
privacyCluster.start(aliceNode, bobNode);
|
||||
|
||||
aliceNode.verify(priv.syncingStatus(false));
|
||||
bobNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodesInGroupShouldHaveSameStateRoot() {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(aliceNode, bobNode);
|
||||
|
||||
final Hash aliceStateRootId =
|
||||
aliceNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
final Hash bobStateRootId =
|
||||
bobNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
assertThat(aliceStateRootId).isEqualTo(bobStateRootId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownGroupShouldReturnError() {
|
||||
final PrivacyRequestFactory.DebugGetStateRoot aliceResult =
|
||||
aliceNode.execute(
|
||||
privacyTransactions.debugGetStateRoot(
|
||||
Hash.wrap(Bytes32.random()).toBase64String(), "latest"));
|
||||
|
||||
assertThat(aliceResult.getResult()).isNull();
|
||||
assertThat(aliceResult.hasError()).isTrue();
|
||||
assertThat(aliceResult.getError()).isNotNull();
|
||||
assertThat(aliceResult.getError().getMessage()).contains("Error finding privacy group");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockParamShouldBeApplied() {
|
||||
waitForBlockHeight(aliceNode, 2);
|
||||
waitForBlockHeight(bobNode, 2);
|
||||
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(aliceNode, bobNode);
|
||||
|
||||
waitForBlockHeight(aliceNode, 10);
|
||||
waitForBlockHeight(bobNode, 10);
|
||||
|
||||
final Hash aliceResult1 =
|
||||
aliceNode.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "1")).getResult();
|
||||
final Hash bobResultInt1 =
|
||||
bobNode.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "1")).getResult();
|
||||
|
||||
assertThat(aliceResult1).isEqualTo(bobResultInt1);
|
||||
|
||||
final Hash aliceResultLatest =
|
||||
aliceNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
final Hash bobResultLatest =
|
||||
bobNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
assertThat(aliceResultLatest).isEqualTo(bobResultLatest);
|
||||
assertThat(aliceResult1).isNotEqualTo(aliceResultLatest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInteractWithPrivateGenesisPreCompile() throws Exception {
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(aliceNode, bobNode);
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
aliceNode.execute(
|
||||
privateContractTransactions.loadSmartContractWithPrivacyGroupId(
|
||||
"0x1000000000000000000000000000000000000001",
|
||||
EventEmitter.class,
|
||||
aliceNode.getTransactionSigningKey(),
|
||||
aliceNode.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateTransactionVerifier.existingPrivateTransactionReceipt(
|
||||
eventEmitter.store(BigInteger.valueOf(42)).send().getTransactionHash());
|
||||
|
||||
final String aliceResponse =
|
||||
aliceNode
|
||||
.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()))
|
||||
.getValue();
|
||||
|
||||
assertThat(new BigInteger(aliceResponse.substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(42));
|
||||
|
||||
final String bobResponse =
|
||||
bobNode
|
||||
.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()))
|
||||
.getValue();
|
||||
|
||||
assertThat(new BigInteger(bobResponse.substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(42));
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes32;
|
||||
import org.junit.Test;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivDebugGetStateRootOffchainGroupAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode aliceNode;
|
||||
private final PrivacyNode bobNode;
|
||||
|
||||
public PrivDebugGetStateRootOffchainGroupAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
aliceNode =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"alice-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"0xAA");
|
||||
bobNode =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"bob-node",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"0xBB");
|
||||
|
||||
privacyCluster.start(aliceNode, bobNode);
|
||||
|
||||
aliceNode.verify(priv.syncingStatus(false));
|
||||
bobNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodesInGroupShouldHaveSameStateRoot() {
|
||||
final String privacyGroupId =
|
||||
aliceNode.execute(
|
||||
createPrivacyGroup("testGroup", "A group for everyone", aliceNode, bobNode));
|
||||
|
||||
final Hash aliceStateRootId =
|
||||
aliceNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
final Hash bobStateRootId =
|
||||
bobNode
|
||||
.execute(privacyTransactions.debugGetStateRoot(privacyGroupId, "latest"))
|
||||
.getResult();
|
||||
|
||||
assertThat(aliceStateRootId).isEqualTo(bobStateRootId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownGroupShouldReturnError() {
|
||||
if (restriction != UNRESTRICTED) {
|
||||
final PrivacyRequestFactory.DebugGetStateRoot aliceResult =
|
||||
aliceNode.execute(
|
||||
privacyTransactions.debugGetStateRoot(
|
||||
Hash.wrap(Bytes32.random()).toBase64String(), "latest"));
|
||||
|
||||
assertThat(aliceResult.getResult()).isNull();
|
||||
assertThat(aliceResult.hasError()).isTrue();
|
||||
assertThat(aliceResult.getError()).isNotNull();
|
||||
assertThat(aliceResult.getError().getMessage()).contains("Error finding privacy group");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.Test;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivGetCodeAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode alice;
|
||||
|
||||
public PrivGetCodeAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
alice =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(alice);
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privGetCodeReturnsDeployedContractBytecode() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployPrivateContract(privacyGroupId);
|
||||
|
||||
final Bytes deployedContractCode =
|
||||
alice.execute(
|
||||
privacyTransactions.privGetCode(
|
||||
privacyGroupId,
|
||||
Address.fromHexString(eventEmitterContract.getContractAddress()),
|
||||
"latest"));
|
||||
|
||||
assertThat(eventEmitterContract.getContractBinary())
|
||||
.contains(deployedContractCode.toUnprefixedHexString());
|
||||
}
|
||||
|
||||
private EventEmitter deployPrivateContract(final String privacyGroupId) {
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
restriction,
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
return eventEmitter;
|
||||
}
|
||||
|
||||
private String createPrivacyGroup() {
|
||||
final String privacyGroupId =
|
||||
alice.execute(createPrivacyGroup("myGroupName", "my group description", alice));
|
||||
|
||||
assertThat(privacyGroupId).isNotNull();
|
||||
|
||||
return privacyGroupId;
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.core.methods.response.EthLog.LogResult;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class PrivGetLogsAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
/*
|
||||
This value is derived from the contract event signature
|
||||
*/
|
||||
private static final String EVENT_EMITTER_EVENT_TOPIC =
|
||||
"0xc9db20adedc6cf2b5d25252b101ab03e124902a73fcb12b753f3d1aaa2d8f9f5";
|
||||
|
||||
private final PrivacyNode node;
|
||||
|
||||
public PrivGetLogsAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
node =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(node);
|
||||
node.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLogsUsingBlockRangeFilter() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployEventEmitterContract(privacyGroupId);
|
||||
|
||||
/*
|
||||
Updating the contract value 2 times
|
||||
*/
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 1);
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 2);
|
||||
|
||||
final LogFilterJsonParameter filter =
|
||||
blockRangeLogFilter("earliest", "latest", eventEmitterContract.getContractAddress());
|
||||
|
||||
final List<LogResult> logs =
|
||||
node.execute(privacyTransactions.privGetLogs(privacyGroupId, filter));
|
||||
|
||||
/*
|
||||
We expect one log entry per tx changing the contract value
|
||||
*/
|
||||
assertThat(logs).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLogsUsingBlockHashFilter() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployEventEmitterContract(privacyGroupId);
|
||||
|
||||
/*
|
||||
Updating the contract value 1 times
|
||||
*/
|
||||
final PrivateTransactionReceipt updateValueReceipt =
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 1);
|
||||
final String blockHash = updateValueReceipt.getBlockHash();
|
||||
|
||||
final LogFilterJsonParameter filter =
|
||||
blockHashLogFilter(blockHash, eventEmitterContract.getContractAddress());
|
||||
|
||||
final List<LogResult> logs =
|
||||
node.execute(privacyTransactions.privGetLogs(privacyGroupId, filter));
|
||||
|
||||
assertThat(logs).hasSize(1);
|
||||
}
|
||||
|
||||
private LogFilterJsonParameter blockRangeLogFilter(
|
||||
final String fromBlock, final String toBlock, final String contractAddress) {
|
||||
return new LogFilterJsonParameter(
|
||||
fromBlock,
|
||||
toBlock,
|
||||
List.of(contractAddress),
|
||||
List.of(List.of(EVENT_EMITTER_EVENT_TOPIC)),
|
||||
null);
|
||||
}
|
||||
|
||||
private LogFilterJsonParameter blockHashLogFilter(
|
||||
final String blockHash, final String contractAddress) {
|
||||
return new LogFilterJsonParameter(
|
||||
null,
|
||||
null,
|
||||
List.of(contractAddress),
|
||||
List.of(List.of(EVENT_EMITTER_EVENT_TOPIC)),
|
||||
blockHash);
|
||||
}
|
||||
|
||||
private String createPrivacyGroup() {
|
||||
return node.execute(createPrivacyGroup("myGroupName", "my group description", node));
|
||||
}
|
||||
|
||||
private EventEmitter deployEventEmitterContract(final String privacyGroupId) {
|
||||
final EventEmitter eventEmitter =
|
||||
node.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), node.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
return eventEmitter;
|
||||
}
|
||||
|
||||
private PrivateTransactionReceipt updateContractValue(
|
||||
final String privacyGroupId, final EventEmitter eventEmitterContract, final int value) {
|
||||
final String transactionHash =
|
||||
node.execute(
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
eventEmitterContract.getContractAddress(),
|
||||
eventEmitterContract.store(BigInteger.valueOf(value)).encodeFunctionCall(),
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
return node.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
|
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.Test;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivGetPrivateTransactionAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode alice;
|
||||
private final PrivacyNode bob;
|
||||
|
||||
public PrivGetPrivateTransactionAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
alice =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"0xAA");
|
||||
bob =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"node2",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"0xBB");
|
||||
|
||||
privacyCluster.start(alice, bob);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsTransaction() {
|
||||
final Transaction<String> onlyAlice = createPrivacyGroup("Only Alice", "", alice);
|
||||
|
||||
final String privacyGroupId = alice.execute(onlyAlice);
|
||||
|
||||
final PrivateTransaction validSignedPrivateTransaction =
|
||||
getValidSignedPrivateTransaction(alice, privacyGroupId);
|
||||
final BytesValueRLPOutput rlpOutput = getRLPOutput(validSignedPrivateTransaction);
|
||||
|
||||
final Hash transactionHash =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash.toString()));
|
||||
|
||||
alice
|
||||
.getBesu()
|
||||
.verify(priv.getPrivateTransaction(transactionHash, validSignedPrivateTransaction));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonExistentHashReturnsNull() {
|
||||
alice.getBesu().verify(priv.getPrivateTransactionReturnsNull(Hash.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnsNullTransactionNotInNodesPrivacyGroup() {
|
||||
final Transaction<String> onlyAlice = createPrivacyGroup("Only Alice", "", alice);
|
||||
|
||||
final String privacyGroupId = alice.execute(onlyAlice);
|
||||
|
||||
final PrivateTransaction validSignedPrivateTransaction =
|
||||
getValidSignedPrivateTransaction(alice, privacyGroupId);
|
||||
final BytesValueRLPOutput rlpOutput = getRLPOutput(validSignedPrivateTransaction);
|
||||
|
||||
final Hash transactionHash =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash.toString()));
|
||||
|
||||
bob.getBesu().verify(priv.getPrivateTransactionReturnsNull(transactionHash));
|
||||
}
|
||||
|
||||
private BytesValueRLPOutput getRLPOutput(final PrivateTransaction privateTransaction) {
|
||||
final BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput();
|
||||
privateTransaction.writeTo(bvrlpo);
|
||||
return bvrlpo;
|
||||
}
|
||||
|
||||
private PrivateTransaction getValidSignedPrivateTransaction(
|
||||
final PrivacyNode node, final String privacyGoupId) {
|
||||
|
||||
org.hyperledger.besu.plugin.data.Restriction besuRestriction =
|
||||
restriction == RESTRICTED
|
||||
? org.hyperledger.besu.plugin.data.Restriction.RESTRICTED
|
||||
: org.hyperledger.besu.plugin.data.Restriction.UNRESTRICTED;
|
||||
|
||||
return PrivateTransaction.builder()
|
||||
.nonce(0)
|
||||
.gasPrice(Wei.of(999999))
|
||||
.gasLimit(3000000)
|
||||
.to(null)
|
||||
.value(Wei.ZERO)
|
||||
.payload(Bytes.wrap(new byte[] {}))
|
||||
.sender(node.getAddress())
|
||||
.privateFrom(Bytes.fromBase64String(node.getEnclaveKey()))
|
||||
.restriction(besuRestriction)
|
||||
.privacyGroupId(Bytes.fromBase64String(privacyGoupId))
|
||||
.signAndBuild(node.getBesu().getPrivacyParameters().getSigningKeyPair().get());
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Copyright contributors to Hyperledger Besu.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.SimpleStorage;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.Test;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivTraceTransactionAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode node;
|
||||
|
||||
private final PrivacyNode wrongNode;
|
||||
|
||||
public PrivTraceTransactionAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
node =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
wrongNode =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(node);
|
||||
privacyCluster.start(wrongNode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTransactionTrace() throws JsonProcessingException {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final SimpleStorage simpleStorageContract = deploySimpleStorageContract(privacyGroupId);
|
||||
|
||||
Hash transactionHash =
|
||||
Hash.fromHexString(doTransaction(privacyGroupId, simpleStorageContract, 0));
|
||||
|
||||
final String result =
|
||||
node.execute(privacyTransactions.privTraceTransaction(privacyGroupId, transactionHash));
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
JsonNode rootNode = mapper.readTree(result);
|
||||
JsonNode resultNode = rootNode.get("result");
|
||||
|
||||
assertThat(resultNode).isNotNull();
|
||||
assertThat(resultNode.isArray()).isTrue();
|
||||
assertThat(resultNode.size()).isGreaterThan(0);
|
||||
|
||||
JsonNode trace = resultNode.get(0);
|
||||
assertThat(trace.get("action").get("callType").asText()).isEqualTo("call");
|
||||
assertThat(trace.get("action").get("from").asText()).isEqualTo(node.getAddress().toString());
|
||||
assertThat(trace.get("action").get("input").asText()).startsWith("0x60fe47b1");
|
||||
assertThat(trace.get("action").get("to").asText())
|
||||
.isEqualTo(simpleStorageContract.getContractAddress());
|
||||
assertThat(trace.get("action").get("value").asText()).isEqualTo("0x0");
|
||||
assertThat(trace.get("blockHash").asText()).isNotEmpty();
|
||||
assertThat(trace.get("blockNumber").asInt()).isGreaterThan(0);
|
||||
assertThat(trace.get("transactionHash").asText()).isEqualTo(transactionHash.toString());
|
||||
assertThat(trace.get("type").asText()).isEqualTo("call");
|
||||
|
||||
final String wrongPrivacyGroupId = createWrongPrivacyGroup();
|
||||
|
||||
final String resultEmpty =
|
||||
wrongNode.execute(
|
||||
privacyTransactions.privTraceTransaction(wrongPrivacyGroupId, transactionHash));
|
||||
|
||||
ObjectMapper mapperEmpty = new ObjectMapper();
|
||||
|
||||
JsonNode rootNodeEmpty = mapperEmpty.readTree(resultEmpty);
|
||||
JsonNode resultNodeEmpty = rootNodeEmpty.get("result");
|
||||
|
||||
assertThat(resultNodeEmpty).isNotNull();
|
||||
assertThat(resultNodeEmpty.isArray()).isTrue();
|
||||
assertThat(resultNodeEmpty.isEmpty()).isTrue();
|
||||
|
||||
final String resultWrongHash =
|
||||
wrongNode.execute(privacyTransactions.privTraceTransaction(privacyGroupId, Hash.EMPTY));
|
||||
|
||||
ObjectMapper mapperWrongHash = new ObjectMapper();
|
||||
|
||||
JsonNode rootNodeWrongHash = mapperWrongHash.readTree(resultWrongHash);
|
||||
JsonNode resultNodeWrongHash = rootNodeWrongHash.get("result");
|
||||
|
||||
assertThat(resultNodeWrongHash).isNotNull();
|
||||
assertThat(resultNodeWrongHash.isArray()).isTrue();
|
||||
assertThat(resultNodeWrongHash.isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
private String createPrivacyGroup() {
|
||||
return node.execute(createPrivacyGroup("myGroupName", "my group description", node));
|
||||
}
|
||||
|
||||
private String createWrongPrivacyGroup() {
|
||||
return wrongNode.execute(createPrivacyGroup("myGroupName", "my group description", wrongNode));
|
||||
}
|
||||
|
||||
private SimpleStorage deploySimpleStorageContract(final String privacyGroupId) {
|
||||
final SimpleStorage simpleStorage =
|
||||
node.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
SimpleStorage.class,
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
simpleStorage.getContractAddress(), node.getAddress().toString())
|
||||
.verify(simpleStorage);
|
||||
|
||||
return simpleStorage;
|
||||
}
|
||||
|
||||
private String doTransaction(
|
||||
final String privacyGroupId, final SimpleStorage simpleStorageContract, final int value) {
|
||||
return node.execute(
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
simpleStorageContract.getContractAddress(),
|
||||
simpleStorageContract.set(BigInteger.valueOf(value)).encodeFunctionCall(),
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
}
|
||||
}
|
||||
@@ -1,407 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.ethereum.core.PrivacyParameters.DEFAULT_PRIVACY;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.enclave.Enclave;
|
||||
import org.hyperledger.besu.enclave.EnclaveFactory;
|
||||
import org.hyperledger.besu.enclave.types.ReceiveResponse;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.crypto.Credentials;
|
||||
import org.web3j.crypto.RawTransaction;
|
||||
import org.web3j.crypto.TransactionEncoder;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.eea.crypto.PrivateTransactionEncoder;
|
||||
import org.web3j.protocol.eea.crypto.RawPrivateTransaction;
|
||||
import org.web3j.utils.Base64String;
|
||||
import org.web3j.utils.Numeric;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class PrivacyClusterAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
|
||||
private final PrivacyNode alice;
|
||||
private final PrivacyNode bob;
|
||||
private final PrivacyNode charlie;
|
||||
private final EnclaveEncryptorType enclaveEncryptorType;
|
||||
private final Vertx vertx = Vertx.vertx();
|
||||
private final EnclaveFactory enclaveFactory = new EnclaveFactory(vertx);
|
||||
|
||||
@Parameters(name = "{0} enclave type with {1} encryptor")
|
||||
public static Collection<Object[]> enclaveParameters() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{TESSERA, NACL},
|
||||
{TESSERA, EC}
|
||||
});
|
||||
}
|
||||
|
||||
public PrivacyClusterAcceptanceTest(
|
||||
final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
alice =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
bob =
|
||||
privacyBesu.createPrivateTransactionEnabledNode(
|
||||
"node2",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
charlie =
|
||||
privacyBesu.createPrivateTransactionEnabledNode(
|
||||
"node3",
|
||||
PrivacyAccountResolver.CHARLIE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
privacyCluster.start(alice, bob, charlie);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
charlie.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
vertx.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyAliceAndBobCanExecuteContract() {
|
||||
// Contract address is generated from sender address and transaction nonce
|
||||
final String contractAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(contractAddress, alice.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
final String transactionHash =
|
||||
alice.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
final PrivateTransactionReceipt expectedReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
|
||||
bob.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash, expectedReceipt));
|
||||
|
||||
charlie.verify(privateTransactionVerifier.noPrivateTransactionReceipt(transactionHash));
|
||||
|
||||
// When Alice executes a contract call in the wrong privacy group the transaction should pass
|
||||
// but it should NOT return any output
|
||||
final String transactionHash2 =
|
||||
alice.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.value().encodeFunctionCall(),
|
||||
alice.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
alice.getEnclaveKey(),
|
||||
charlie.getEnclaveKey()));
|
||||
|
||||
final PrivateTransactionReceipt expectedReceipt2 =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash2));
|
||||
|
||||
assertThat(expectedReceipt2.getOutput()).isEqualTo("0x");
|
||||
|
||||
charlie.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash2, expectedReceipt2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliceCanUsePrivDistributeTransaction() {
|
||||
// Contract address is generated from sender address and transaction nonce
|
||||
final String contractAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
final String receiptPrivacyGroupId =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "MjuFB4b9Hz+f8zvkWWasxZWRjHWXU4t7B2nOHo4mekA="
|
||||
: "DyAOiF/ynpc+JXa2YAGB0bCitSlOMNm+ShmB/7M6C4w=";
|
||||
|
||||
final RawPrivateTransaction rawPrivateTransaction =
|
||||
RawPrivateTransaction.createContractTransaction(
|
||||
BigInteger.ZERO,
|
||||
BigInteger.ZERO,
|
||||
BigInteger.ZERO,
|
||||
Numeric.prependHexPrefix(EventEmitter.BINARY),
|
||||
Base64String.wrap(alice.getEnclaveKey()),
|
||||
Collections.singletonList(Base64String.wrap(bob.getEnclaveKey())),
|
||||
Base64String.wrap(receiptPrivacyGroupId),
|
||||
RESTRICTED);
|
||||
|
||||
final String signedPrivateTransaction =
|
||||
Numeric.toHexString(
|
||||
PrivateTransactionEncoder.signMessage(
|
||||
rawPrivateTransaction, Credentials.create(alice.getTransactionSigningKey())));
|
||||
final String transactionKey =
|
||||
alice.execute(privacyTransactions.privDistributeTransaction(signedPrivateTransaction));
|
||||
|
||||
final Enclave aliceEnclave = enclaveFactory.createVertxEnclave(alice.getEnclave().clientUrl());
|
||||
final ReceiveResponse aliceRR =
|
||||
aliceEnclave.receive(
|
||||
Bytes.fromHexString(transactionKey).toBase64String(), alice.getEnclaveKey());
|
||||
|
||||
final Enclave bobEnclave = enclaveFactory.createVertxEnclave(bob.getEnclave().clientUrl());
|
||||
final ReceiveResponse bobRR =
|
||||
bobEnclave.receive(
|
||||
Bytes.fromHexString(transactionKey).toBase64String(), bob.getEnclaveKey());
|
||||
|
||||
assertThat(bobRR).usingRecursiveComparison().isEqualTo(aliceRR);
|
||||
|
||||
final RawTransaction pmt =
|
||||
RawTransaction.createTransaction(
|
||||
BigInteger.ZERO,
|
||||
BigInteger.valueOf(1000),
|
||||
BigInteger.valueOf(65000),
|
||||
DEFAULT_PRIVACY.toString(),
|
||||
transactionKey);
|
||||
|
||||
final String signedPmt =
|
||||
Numeric.toHexString(
|
||||
TransactionEncoder.signMessage(
|
||||
pmt, Credentials.create(alice.getTransactionSigningKey())));
|
||||
|
||||
final String transactionHash = alice.execute(ethTransactions.sendRawTransaction(signedPmt));
|
||||
|
||||
final String receiptPrivateFrom =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES8nC4qT/KdoAoTSF3qs/47DUsDihyVbWiRjZAiyvqp9eSDkqV1RzlM+58oOwnpFRwvWNZM+AxMVxT+MvxdsqMA=="
|
||||
: "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
|
||||
final ArrayList<String> receiptPrivateFor =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? new ArrayList<>(
|
||||
Collections.singletonList(
|
||||
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXIgZqRA25V+3nN+Do6b5r0jiUunub6ubjPhqwHpPxP44uUYh9RKCQNRnsqCJ9PjeTnC8R3ieJk7HWAlycU1bug=="))
|
||||
: new ArrayList<>(
|
||||
Collections.singletonList("Ko2bVqD+nNlNYL5EE7y3IdOnviftjiizpjRt+HTuFBs="));
|
||||
|
||||
final PrivateTransactionReceipt expectedReceipt =
|
||||
new PrivateTransactionReceipt(
|
||||
contractAddress,
|
||||
"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
|
||||
null,
|
||||
null, // ignored in the following call, checked separately below
|
||||
Collections.emptyList(),
|
||||
"0x023955c49d6265c579561940287449242704d5fd239ff07ea36a3fc7aface61c",
|
||||
"0x82e521ee16ff13104c5f81e8354ecaaafd5450b710b07f620204032bfe76041a",
|
||||
receiptPrivateFrom,
|
||||
receiptPrivateFor,
|
||||
receiptPrivacyGroupId,
|
||||
"0x1",
|
||||
null);
|
||||
|
||||
alice.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash, expectedReceipt, true));
|
||||
|
||||
final PrivateTransactionReceipt alicePrivateTransactionReceipt =
|
||||
alice.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
assertThat(EventEmitter.BINARY)
|
||||
.contains(alicePrivateTransactionReceipt.getOutput().substring(2));
|
||||
|
||||
bob.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash, expectedReceipt, true));
|
||||
|
||||
final PrivateTransactionReceipt bobPrivateTransactionReceipt =
|
||||
bob.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
assertThat(EventEmitter.BINARY).contains(bobPrivateTransactionReceipt.getOutput().substring(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aliceCanDeployMultipleTimesInSingleGroup() {
|
||||
final String firstDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter firstEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString())
|
||||
.verify(firstEventEmitter);
|
||||
|
||||
final String secondDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x5194e214fae257530710d18c868df7a295d9d53b"
|
||||
: "0x10f807f8a905da5bd319196da7523c6bd768690f";
|
||||
|
||||
final EventEmitter secondEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(secondDeployedAddress, alice.getAddress().toString())
|
||||
.verify(secondEventEmitter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInteractWithMultiplePrivacyGroups() {
|
||||
// alice deploys contract
|
||||
final String firstDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x760359bc605b3848f5199829bde6b382d90fb8eb"
|
||||
: "0xff206d21150a8da5b83629d8a722f3135ed532b1";
|
||||
|
||||
final EventEmitter firstEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey(),
|
||||
charlie.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(firstDeployedAddress, alice.getAddress().toString())
|
||||
.verify(firstEventEmitter);
|
||||
|
||||
// charlie interacts with contract
|
||||
final String firstTransactionHash =
|
||||
charlie.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
firstEventEmitter.getContractAddress(),
|
||||
firstEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
charlie.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
charlie.getEnclaveKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
// 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 secondDeployedAddress =
|
||||
EnclaveEncryptorType.EC.equals(enclaveEncryptorType)
|
||||
? "0x3e5d325a03ad3ce5640502219833d30b89ce3ce1"
|
||||
: "0xebf56429e6500e84442467292183d4d621359838";
|
||||
|
||||
final EventEmitter secondEventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
bob.getEnclaveKey()));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(secondDeployedAddress, alice.getAddress().toString())
|
||||
.verify(secondEventEmitter);
|
||||
|
||||
// bob interacts with contract
|
||||
final String secondTransactionHash =
|
||||
bob.execute(
|
||||
privateContractTransactions.callSmartContract(
|
||||
secondEventEmitter.getContractAddress(),
|
||||
secondEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
bob.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
bob.getEnclaveKey(),
|
||||
alice.getEnclaveKey()));
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.besu.util.LogConfigurator;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivacyGroup;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.utils.Base64String;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class PrivacyGroupAcceptanceTest extends PrivacyAcceptanceTestBase {
|
||||
|
||||
private final PrivacyNode alice;
|
||||
private final PrivacyNode bob;
|
||||
private final PrivacyNode charlie;
|
||||
|
||||
@Parameters(name = "{0} enclave type with {1} encryptor")
|
||||
public static Collection<Object[]> enclaveParameters() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{TESSERA, NACL},
|
||||
{TESSERA, EC}
|
||||
});
|
||||
}
|
||||
|
||||
public PrivacyGroupAcceptanceTest(
|
||||
final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
alice =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
bob =
|
||||
privacyBesu.createPrivateTransactionEnabledNode(
|
||||
"node2",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
|
||||
charlie =
|
||||
privacyBesu.createPrivateTransactionEnabledNode(
|
||||
"node3",
|
||||
PrivacyAccountResolver.CHARLIE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
privacyCluster.start(alice, bob, charlie);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
bob.verify(priv.syncingStatus(false));
|
||||
charlie.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeCanCreatePrivacyGroup() {
|
||||
LogConfigurator.setLevel("", "DEBUG");
|
||||
final String privacyGroupId =
|
||||
alice.execute(
|
||||
privacyTransactions.createPrivacyGroup(
|
||||
"myGroupName", "my group description", alice, bob));
|
||||
|
||||
assertThat(privacyGroupId).isNotNull();
|
||||
|
||||
final PrivacyGroup expected =
|
||||
new PrivacyGroup(
|
||||
privacyGroupId,
|
||||
PrivacyGroup.Type.PANTHEON,
|
||||
"myGroupName",
|
||||
"my group description",
|
||||
Base64String.wrapList(alice.getEnclaveKey(), bob.getEnclaveKey()));
|
||||
|
||||
alice.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
|
||||
bob.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeCanCreatePrivacyGroupWithoutName() {
|
||||
final String privacyGroupId =
|
||||
alice.execute(
|
||||
privacyTransactions.createPrivacyGroup(null, "my group description", alice, bob));
|
||||
|
||||
assertThat(privacyGroupId).isNotNull();
|
||||
|
||||
final PrivacyGroup expected =
|
||||
new PrivacyGroup(
|
||||
privacyGroupId,
|
||||
PrivacyGroup.Type.PANTHEON,
|
||||
"",
|
||||
"my group description",
|
||||
Base64String.wrapList(alice.getEnclaveKey(), bob.getEnclaveKey()));
|
||||
|
||||
alice.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
|
||||
bob.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeCanCreatePrivacyGroupWithoutDescription() {
|
||||
final String privacyGroupId =
|
||||
alice.execute(privacyTransactions.createPrivacyGroup("myGroupName", null, alice, bob));
|
||||
|
||||
assertThat(privacyGroupId).isNotNull();
|
||||
|
||||
final PrivacyGroup expected =
|
||||
new PrivacyGroup(
|
||||
privacyGroupId,
|
||||
PrivacyGroup.Type.PANTHEON,
|
||||
"myGroupName",
|
||||
"",
|
||||
Base64String.wrapList(alice.getEnclaveKey(), bob.getEnclaveKey()));
|
||||
|
||||
alice.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
|
||||
bob.verify(privateTransactionVerifier.validPrivacyGroupCreated(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nodeCanCreatePrivacyGroupWithoutOptionalParams() {
|
||||
final String privacyGroupId =
|
||||
alice.execute(privacyTransactions.createPrivacyGroup(null, null, alice));
|
||||
|
||||
assertThat(privacyGroupId).isNotNull();
|
||||
|
||||
final PrivacyGroup expected =
|
||||
new PrivacyGroup(
|
||||
privacyGroupId,
|
||||
PrivacyGroup.Type.PANTHEON,
|
||||
"",
|
||||
"",
|
||||
Base64String.wrapList(alice.getEnclaveKey()));
|
||||
|
||||
alice.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(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupIdABC));
|
||||
|
||||
// charlie interacts with contract
|
||||
final String firstTransactionHash =
|
||||
charlie.execute(
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
firstEventEmitter.getContractAddress(),
|
||||
firstEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
charlie.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
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(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupIdAB));
|
||||
|
||||
// bob interacts with contract
|
||||
final String secondTransactionHash =
|
||||
bob.execute(
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
secondEventEmitter.getContractAddress(),
|
||||
secondEventEmitter.store(BigInteger.ONE).encodeFunctionCall(),
|
||||
bob.getTransactionSigningKey(),
|
||||
RESTRICTED,
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static java.util.Optional.empty;
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
|
||||
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.Test;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivacyReceiptAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
final MinerTransactions minerTransactions = new MinerTransactions();
|
||||
|
||||
private final PrivacyNode alice;
|
||||
|
||||
public PrivacyReceiptAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
alice =
|
||||
privacyBesu.createIbft2NodePrivacyEnabled(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
false,
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"0xAA");
|
||||
privacyCluster.start(alice);
|
||||
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivateTransactionReceiptSuccessfulTransaction() {
|
||||
final Transaction<String> onlyAlice = createPrivacyGroup("Only Alice", "", alice);
|
||||
|
||||
final String privacyGroupId = alice.execute(onlyAlice);
|
||||
|
||||
final PrivateTransaction validTransaction =
|
||||
createSignedTransaction(alice, privacyGroupId, empty());
|
||||
final BytesValueRLPOutput rlpOutput = getRLPOutput(validTransaction);
|
||||
|
||||
final Hash transactionHash =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
|
||||
// Successful PMT
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash.toString()));
|
||||
// Successful private transaction
|
||||
alice.getBesu().verify(priv.getSuccessfulTransactionReceipt(transactionHash));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivateTransactionReceiptFailedTransaction() {
|
||||
final Transaction<String> onlyAlice = createPrivacyGroup("Only Alice", "", alice);
|
||||
|
||||
final String privacyGroupId = alice.execute(onlyAlice);
|
||||
|
||||
final PrivateTransaction invalidPayloadTransaction =
|
||||
createSignedTransaction(
|
||||
alice, privacyGroupId, Optional.of(Bytes.fromBase64String("invalidPayload")));
|
||||
final BytesValueRLPOutput rlpOutput = getRLPOutput(invalidPayloadTransaction);
|
||||
|
||||
final Hash transactionHash =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
|
||||
// Successful PMT
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash.toString()));
|
||||
// Failed private transaction
|
||||
alice.getBesu().verify(priv.getFailedTransactionReceipt(transactionHash));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivateTransactionReceiptInvalidTransaction() {
|
||||
final Transaction<String> onlyAlice = createPrivacyGroup("Only Alice", "", alice);
|
||||
|
||||
final String privacyGroupId = alice.execute(onlyAlice);
|
||||
|
||||
final PrivateTransaction validTransaction =
|
||||
createSignedTransaction(alice, privacyGroupId, empty());
|
||||
final BytesValueRLPOutput rlpOutput = getRLPOutput(validTransaction);
|
||||
|
||||
// Stop mining, to allow adding duplicate nonce block
|
||||
alice.getBesu().execute(minerTransactions.minerStop());
|
||||
|
||||
final Hash transactionHash1 =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
final Hash transactionHash2 =
|
||||
alice.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));
|
||||
|
||||
// Start mining again
|
||||
alice.getBesu().execute(minerTransactions.minerStart());
|
||||
|
||||
// Successful PMTs
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash1.toString()));
|
||||
alice.getBesu().verify(eth.expectSuccessfulTransactionReceipt(transactionHash2.toString()));
|
||||
// Successful first private transaction
|
||||
alice.getBesu().verify(priv.getSuccessfulTransactionReceipt(transactionHash1));
|
||||
// Invalid second private transaction
|
||||
alice.getBesu().verify(priv.getInvalidTransactionReceipt(transactionHash2));
|
||||
}
|
||||
|
||||
private BytesValueRLPOutput getRLPOutput(final PrivateTransaction privateTransaction) {
|
||||
final BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput();
|
||||
privateTransaction.writeTo(bvrlpo);
|
||||
return bvrlpo;
|
||||
}
|
||||
|
||||
private PrivateTransaction createSignedTransaction(
|
||||
final PrivacyNode node, final String privacyGoupId, final Optional<Bytes> payload) {
|
||||
|
||||
org.hyperledger.besu.plugin.data.Restriction besuRestriction =
|
||||
restriction == RESTRICTED
|
||||
? org.hyperledger.besu.plugin.data.Restriction.RESTRICTED
|
||||
: org.hyperledger.besu.plugin.data.Restriction.UNRESTRICTED;
|
||||
|
||||
final Bytes defaultPayload = Bytes.wrap(new byte[] {});
|
||||
return PrivateTransaction.builder()
|
||||
.nonce(0)
|
||||
.gasPrice(Wei.of(999999))
|
||||
.gasLimit(3000000)
|
||||
.to(null)
|
||||
.value(Wei.ZERO)
|
||||
.payload(payload.orElse(defaultPayload))
|
||||
.sender(node.getAddress())
|
||||
.privateFrom(Bytes.fromBase64String(node.getEnclaveKey()))
|
||||
.restriction(besuRestriction)
|
||||
.privacyGroupId(Bytes.fromBase64String(privacyGoupId))
|
||||
.signAndBuild(node.getBesu().getPrivacyParameters().getSigningKeyPair().get());
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.CrossContractReader;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.besu.tests.web3j.generated.RemoteSimpleStorage;
|
||||
import org.hyperledger.besu.tests.web3j.generated.SimpleStorage;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.testcontainers.containers.Network;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.core.RemoteFunctionCall;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
import org.web3j.protocol.exceptions.TransactionException;
|
||||
import org.web3j.tx.exceptions.ContractCallException;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
public class PrivateContractPublicStateAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode transactionNode;
|
||||
|
||||
public PrivateContractPublicStateAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
final Network containerNetwork = Network.newNetwork();
|
||||
|
||||
final PrivacyNode minerNode =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-miner-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
transactionNode =
|
||||
privacyBesu.createPrivateTransactionEnabledNode(
|
||||
restriction + "-transaction-node",
|
||||
PrivacyAccountResolver.BOB.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.of(containerNetwork),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(minerNode, transactionNode);
|
||||
|
||||
minerNode.verify(priv.syncingStatus(false));
|
||||
transactionNode.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustAllowAccessToPublicStateFromPrivateTx() throws Exception {
|
||||
final EventEmitter publicEventEmitter =
|
||||
transactionNode.execute(contractTransactions.createSmartContract(EventEmitter.class));
|
||||
|
||||
final TransactionReceipt receipt = publicEventEmitter.store(BigInteger.valueOf(12)).send();
|
||||
assertThat(receipt).isNotNull();
|
||||
|
||||
final CrossContractReader reader =
|
||||
transactionNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
CrossContractReader.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey()));
|
||||
|
||||
final RemoteFunctionCall<BigInteger> remoteFunctionCall =
|
||||
reader.read(publicEventEmitter.getContractAddress());
|
||||
final BigInteger result = remoteFunctionCall.send();
|
||||
|
||||
assertThat(result).isEqualTo(BigInteger.valueOf(12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mustNotAllowAccessToPrivateStateFromPublicTx() throws Exception {
|
||||
final EventEmitter privateEventEmitter =
|
||||
transactionNode.execute(
|
||||
(privateContractTransactions.createSmartContract(
|
||||
EventEmitter.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey())));
|
||||
|
||||
final TransactionReceipt receipt = privateEventEmitter.store(BigInteger.valueOf(12)).send();
|
||||
assertThat(receipt).isNotNull();
|
||||
|
||||
final CrossContractReader publicReader =
|
||||
transactionNode.execute(
|
||||
contractTransactions.createSmartContract(CrossContractReader.class));
|
||||
final RemoteFunctionCall<BigInteger> functionCall =
|
||||
publicReader.read(privateEventEmitter.getContractAddress());
|
||||
assertThatThrownBy(functionCall::send).isInstanceOf(ContractCallException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateContractMustNotBeAbleToCallPublicContractWhichChangesState() throws Exception {
|
||||
final CrossContractReader privateReader =
|
||||
transactionNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
CrossContractReader.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey()));
|
||||
|
||||
final CrossContractReader publicReader =
|
||||
transactionNode.execute(
|
||||
contractTransactions.createSmartContract(CrossContractReader.class));
|
||||
|
||||
assertThatExceptionOfType(TransactionException.class)
|
||||
.isThrownBy(() -> privateReader.incrementRemote(publicReader.getContractAddress()).send())
|
||||
.returns(
|
||||
"0x", e -> ((PrivateTransactionReceipt) e.getTransactionReceipt().get()).getOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateContractMustNotBeAbleToCallPublicContractWhichInstantiatesContract()
|
||||
throws Exception {
|
||||
final CrossContractReader privateReader =
|
||||
transactionNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
CrossContractReader.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey()));
|
||||
|
||||
final CrossContractReader publicReader =
|
||||
transactionNode.execute(
|
||||
contractTransactions.createSmartContract(CrossContractReader.class));
|
||||
|
||||
assertThatExceptionOfType(TransactionException.class)
|
||||
.isThrownBy(() -> privateReader.deployRemote(publicReader.getContractAddress()).send())
|
||||
.returns(0, e -> e.getTransactionReceipt().get().getLogs().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateContractMustNotBeAbleToCallSelfDestructOnPublicContract() throws Exception {
|
||||
final CrossContractReader privateReader =
|
||||
transactionNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
CrossContractReader.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey()));
|
||||
|
||||
final CrossContractReader publicReader =
|
||||
transactionNode
|
||||
.getBesu()
|
||||
.execute(contractTransactions.createSmartContract(CrossContractReader.class));
|
||||
|
||||
assertThatExceptionOfType(TransactionException.class)
|
||||
.isThrownBy(() -> privateReader.remoteDestroy(publicReader.getContractAddress()).send())
|
||||
.withMessage(
|
||||
"Transaction null has failed with status: 0x0. Gas used: unknown. Revert reason: '0x'.")
|
||||
.returns(
|
||||
"0x", e -> ((PrivateTransactionReceipt) e.getTransactionReceipt().get()).getOutput());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateContractCanCallPublicContractThatCallsPublicContract() throws Exception {
|
||||
final SimpleStorage simpleStorage =
|
||||
transactionNode
|
||||
.getBesu()
|
||||
.execute(contractTransactions.createSmartContract(SimpleStorage.class));
|
||||
|
||||
final RemoteSimpleStorage remoteSimpleStorage =
|
||||
transactionNode
|
||||
.getBesu()
|
||||
.execute(contractTransactions.createSmartContract(RemoteSimpleStorage.class));
|
||||
|
||||
remoteSimpleStorage.setRemote(simpleStorage.getContractAddress()).send();
|
||||
|
||||
final RemoteSimpleStorage reallyRemoteSimpleStorage =
|
||||
transactionNode
|
||||
.getBesu()
|
||||
.execute(contractTransactions.createSmartContract(RemoteSimpleStorage.class));
|
||||
|
||||
reallyRemoteSimpleStorage.setRemote(remoteSimpleStorage.getContractAddress()).send();
|
||||
|
||||
simpleStorage.set(BigInteger.valueOf(42)).send();
|
||||
|
||||
assertThat(simpleStorage.get().send()).isEqualTo(BigInteger.valueOf(42));
|
||||
assertThat(remoteSimpleStorage.get().send()).isEqualTo(BigInteger.valueOf(42));
|
||||
assertThat(reallyRemoteSimpleStorage.get().send()).isEqualTo(BigInteger.valueOf(42));
|
||||
|
||||
final RemoteSimpleStorage privateRemoteSimpleStorage =
|
||||
transactionNode.execute(
|
||||
privateContractTransactions.createSmartContract(
|
||||
RemoteSimpleStorage.class,
|
||||
transactionNode.getTransactionSigningKey(),
|
||||
transactionNode.getEnclaveKey()));
|
||||
|
||||
privateRemoteSimpleStorage.setRemote(simpleStorage.getContractAddress()).send();
|
||||
assertThat(privateRemoteSimpleStorage.get().send()).isEqualTo(BigInteger.valueOf(42));
|
||||
|
||||
privateRemoteSimpleStorage.setRemote(reallyRemoteSimpleStorage.getContractAddress()).send();
|
||||
assertThat(privateRemoteSimpleStorage.get().send()).isEqualTo(BigInteger.valueOf(42));
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.RESTRICTED;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.web3j.protocol.core.methods.response.EthCall;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class PrivateGenesisAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
private final PrivacyNode alice;
|
||||
|
||||
public PrivateGenesisAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
alice =
|
||||
privacyBesu.createIbft2NodePrivacyEnabledWithGenesis(
|
||||
"node1",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
true,
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED,
|
||||
"AA");
|
||||
|
||||
privacyCluster.start(alice);
|
||||
alice.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInteractWithPrivateGenesisPreCompile() throws Exception {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
alice.execute(
|
||||
privateContractTransactions.loadSmartContractWithPrivacyGroupId(
|
||||
"0x1000000000000000000000000000000000000001",
|
||||
EventEmitter.class,
|
||||
alice.getTransactionSigningKey(),
|
||||
alice.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
eventEmitter.store(BigInteger.valueOf(42)).send();
|
||||
|
||||
final EthCall response =
|
||||
alice.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()));
|
||||
|
||||
final String value = response.getValue();
|
||||
|
||||
assertThat(new BigInteger(value.substring(2), 16)).isEqualByComparingTo(BigInteger.valueOf(42));
|
||||
}
|
||||
|
||||
private String createPrivacyGroup() {
|
||||
if (restriction == RESTRICTED) {
|
||||
return alice.execute(privacyTransactions.createPrivacyGroup("name", "description", alice));
|
||||
} else if (restriction == UNRESTRICTED) {
|
||||
return "gsvwYfGPurL7wgXKmgFtCamXarAl9fA5jaSXi8TLpJw=";
|
||||
} else {
|
||||
throw new RuntimeException("Do not know how to handle " + restriction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.web3j.utils.Restriction.UNRESTRICTED;
|
||||
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.ParameterizedEnclaveTestBase;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.core.methods.response.EthLog.LogResult;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class PrivateLogFilterAcceptanceTest extends ParameterizedEnclaveTestBase {
|
||||
|
||||
private final PrivacyNode node;
|
||||
|
||||
public PrivateLogFilterAcceptanceTest(
|
||||
final Restriction restriction,
|
||||
final EnclaveType enclaveType,
|
||||
final EnclaveEncryptorType enclaveEncryptorType)
|
||||
throws IOException {
|
||||
|
||||
super(restriction, enclaveType, enclaveEncryptorType);
|
||||
|
||||
node =
|
||||
privacyBesu.createPrivateTransactionEnabledMinerNode(
|
||||
restriction + "-node",
|
||||
PrivacyAccountResolver.ALICE.resolve(enclaveEncryptorType),
|
||||
enclaveType,
|
||||
Optional.empty(),
|
||||
false,
|
||||
false,
|
||||
restriction == UNRESTRICTED);
|
||||
|
||||
privacyCluster.start(node);
|
||||
node.verify(priv.syncingStatus(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void installAndUninstallFilter() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployEventEmitterContract(privacyGroupId);
|
||||
|
||||
final LogFilterJsonParameter filter =
|
||||
blockRangeLogFilter("earliest", "latest", eventEmitterContract.getContractAddress());
|
||||
|
||||
final String filterId = node.execute(privacyTransactions.newFilter(privacyGroupId, filter));
|
||||
|
||||
final boolean filterUninstalled =
|
||||
node.execute(privacyTransactions.uninstallFilter(privacyGroupId, filterId));
|
||||
|
||||
assertThat(filterUninstalled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFilterLogs() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployEventEmitterContract(privacyGroupId);
|
||||
|
||||
final LogFilterJsonParameter filter =
|
||||
blockRangeLogFilter("earliest", "latest", eventEmitterContract.getContractAddress());
|
||||
final String filterId = node.execute(privacyTransactions.newFilter(privacyGroupId, filter));
|
||||
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 1);
|
||||
|
||||
final List<LogResult> logs =
|
||||
node.execute(privacyTransactions.getFilterLogs(privacyGroupId, filterId));
|
||||
|
||||
assertThat(logs).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFilterChanges() {
|
||||
final String privacyGroupId = createPrivacyGroup();
|
||||
final EventEmitter eventEmitterContract = deployEventEmitterContract(privacyGroupId);
|
||||
|
||||
final LogFilterJsonParameter filter =
|
||||
blockRangeLogFilter("earliest", "latest", eventEmitterContract.getContractAddress());
|
||||
final String filterId = node.execute(privacyTransactions.newFilter(privacyGroupId, filter));
|
||||
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 1);
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 2);
|
||||
|
||||
assertThat(node.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasSize(2);
|
||||
|
||||
updateContractValue(privacyGroupId, eventEmitterContract, 3);
|
||||
|
||||
assertThat(node.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
private LogFilterJsonParameter blockRangeLogFilter(
|
||||
final String fromBlock, final String toBlock, final String contractAddress) {
|
||||
return new LogFilterJsonParameter(
|
||||
fromBlock, toBlock, List.of(contractAddress), Collections.emptyList(), null);
|
||||
}
|
||||
|
||||
private String createPrivacyGroup() {
|
||||
return node.execute(createPrivacyGroup("myGroupName", "my group description", node));
|
||||
}
|
||||
|
||||
private EventEmitter deployEventEmitterContract(final String privacyGroupId) {
|
||||
final EventEmitter eventEmitter =
|
||||
node.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
privateContractVerifier
|
||||
.validPrivateContractDeployed(
|
||||
eventEmitter.getContractAddress(), node.getAddress().toString())
|
||||
.verify(eventEmitter);
|
||||
|
||||
return eventEmitter;
|
||||
}
|
||||
|
||||
private PrivateTransactionReceipt updateContractValue(
|
||||
final String privacyGroupId, final EventEmitter eventEmitterContract, final int value) {
|
||||
final String transactionHash =
|
||||
node.execute(
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
eventEmitterContract.getContractAddress(),
|
||||
eventEmitterContract.store(BigInteger.valueOf(value)).encodeFunctionCall(),
|
||||
node.getTransactionSigningKey(),
|
||||
restriction,
|
||||
node.getEnclaveKey(),
|
||||
privacyGroupId));
|
||||
|
||||
return node.execute(privacyTransactions.getPrivateTransactionReceipt(transactionHash));
|
||||
}
|
||||
}
|
||||
@@ -1,491 +0,0 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.tests.acceptance.privacy.multitenancy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.EC;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveEncryptorType.NACL;
|
||||
import static org.hyperledger.enclave.testutil.EnclaveType.TESSERA;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.PrivacyNode;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.account.PrivacyAccountResolver;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.contract.CallPrivateSmartContractFunction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.transaction.CreateFlexiblePrivacyGroupTransaction;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.privacy.util.LogFilterJsonParameter;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.PermissioningTransactions;
|
||||
import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyRequestFactory;
|
||||
import org.hyperledger.besu.tests.acceptance.privacy.FlexiblePrivacyAcceptanceTestBase;
|
||||
import org.hyperledger.besu.tests.web3j.generated.EventEmitter;
|
||||
import org.hyperledger.enclave.testutil.EnclaveEncryptorType;
|
||||
import org.hyperledger.enclave.testutil.EnclaveType;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.web3j.crypto.Credentials;
|
||||
import org.web3j.protocol.besu.response.privacy.PrivateTransactionReceipt;
|
||||
import org.web3j.protocol.core.methods.response.EthCall;
|
||||
import org.web3j.utils.Base64String;
|
||||
import org.web3j.utils.Restriction;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class FlexibleMultiTenancyAcceptanceTest extends FlexiblePrivacyAcceptanceTestBase {
|
||||
|
||||
private final EnclaveType enclaveType;
|
||||
private final EnclaveEncryptorType enclaveEncryptorType;
|
||||
|
||||
public FlexibleMultiTenancyAcceptanceTest(
|
||||
final EnclaveType enclaveType, final EnclaveEncryptorType enclaveEncryptorType) {
|
||||
this.enclaveType = enclaveType;
|
||||
this.enclaveEncryptorType = enclaveEncryptorType;
|
||||
}
|
||||
|
||||
@Parameterized.Parameters(name = "{0} enclave type with {1} encryptor")
|
||||
public static Collection<Object[]> enclaveParameters() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{TESSERA, NACL},
|
||||
{TESSERA, EC}
|
||||
});
|
||||
}
|
||||
|
||||
private static final PermissioningTransactions permissioningTransactions =
|
||||
new PermissioningTransactions();
|
||||
private static final long VALUE_SET = 10L;
|
||||
|
||||
private PrivacyNode alice;
|
||||
private MultiTenancyPrivacyNode aliceMultiTenancyPrivacyNode;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
alice =
|
||||
privacyBesu.createFlexiblePrivacyGroupEnabledMinerNode(
|
||||
"node1",
|
||||
PrivacyAccountResolver.MULTI_TENANCY.resolve(enclaveEncryptorType),
|
||||
true,
|
||||
enclaveType,
|
||||
Optional.empty());
|
||||
final BesuNode aliceBesu = alice.getBesu();
|
||||
privacyCluster.startNodes(alice);
|
||||
final String alice1Token =
|
||||
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
|
||||
aliceBesu.useAuthenticationTokenInHeaderForJsonRpc(alice1Token);
|
||||
final String alice2Token =
|
||||
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user2", "Password2"));
|
||||
final String alice3Token =
|
||||
aliceBesu.execute(permissioningTransactions.createSuccessfulLogin("user3", "Password3"));
|
||||
privacyCluster.awaitPeerCount(alice);
|
||||
|
||||
final String alice1EnclaveKey = alice.getEnclave().getPublicKeys().get(0);
|
||||
final String alice2EnclaveKey = alice.getEnclave().getPublicKeys().get(1);
|
||||
final String alice3EnclaveKey = alice.getEnclave().getPublicKeys().get(2);
|
||||
|
||||
aliceMultiTenancyPrivacyNode = new MultiTenancyPrivacyNode(alice);
|
||||
aliceMultiTenancyPrivacyNode
|
||||
.addTenantWithToken(alice1EnclaveKey, alice1Token)
|
||||
.addTenantWithToken(alice2EnclaveKey, alice2Token)
|
||||
.addTenantWithToken(alice3EnclaveKey, alice3Token);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
privacyCluster.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivacyGroup() {
|
||||
createFlexiblePrivacyGroup(alice);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPrivacyGroupWithAllTenants() {
|
||||
final MultiTenancyPrivacyGroup privacyGroup = new MultiTenancyPrivacyGroup();
|
||||
privacyGroup.addNodeWithTenants(
|
||||
aliceMultiTenancyPrivacyNode, aliceMultiTenancyPrivacyNode.getTenants());
|
||||
createFlexiblePrivacyGroup(privacyGroup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noAccessWhenNotAMember() {
|
||||
final MultiTenancyPrivacyGroup twoTenantsFromAlice = new MultiTenancyPrivacyGroup();
|
||||
final List<String> tenants = aliceMultiTenancyPrivacyNode.getTenants();
|
||||
final String removedTenant = tenants.remove(tenants.size() - 1);
|
||||
twoTenantsFromAlice.addNodeWithTenants(aliceMultiTenancyPrivacyNode, tenants);
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(twoTenantsFromAlice);
|
||||
|
||||
final MultiTenancyPrivacyNode multiTenancyPrivacyNode =
|
||||
twoTenantsFromAlice.getPrivacyNodes().get(0);
|
||||
final String tenant = tenants.get(0);
|
||||
final PrivacyNode privacyNode = multiTenancyPrivacyNode.getPrivacyNode();
|
||||
final BesuNode privacyNodeBesu = privacyNode.getBesu();
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final EventEmitter eventEmitter =
|
||||
privacyNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
privacyNode.getTransactionSigningKey(),
|
||||
tenant,
|
||||
privacyGroupId));
|
||||
|
||||
final String transactionHash = getContractDeploymentCommitmentHash(eventEmitter);
|
||||
|
||||
// check that a member can get the transaction receipt
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
privacyNode.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
transactionHash,
|
||||
(PrivateTransactionReceipt) eventEmitter.getTransactionReceipt().get()));
|
||||
final String actual =
|
||||
privacyNode
|
||||
.execute(
|
||||
privacyTransactions.privGetCode(
|
||||
privacyGroupId,
|
||||
Address.fromHexString(eventEmitter.getContractAddress()),
|
||||
"latest"))
|
||||
.toHexString();
|
||||
assertThat(EventEmitter.BINARY).contains(actual.substring(2));
|
||||
|
||||
// check that getting the transaction receipt does not work if you are not a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
privacyNode.verify(
|
||||
privateTransactionVerifier.noPrivateTransactionReceipt(
|
||||
transactionHash)); // returning null because the RPC is using the enclave key
|
||||
|
||||
// check that getting the code of the event emitter does not work when you are not a member
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
privacyNode.execute(
|
||||
privacyTransactions.privGetCode(
|
||||
privacyGroupId,
|
||||
Address.fromHexString(eventEmitter.getContractAddress()),
|
||||
"latest")))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
|
||||
final LogFilterJsonParameter filterParameter =
|
||||
new LogFilterJsonParameter(
|
||||
"earliest",
|
||||
"latest",
|
||||
List.of(eventEmitter.getContractAddress()),
|
||||
Collections.emptyList(),
|
||||
null);
|
||||
|
||||
// create a valid filter
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final String filterId =
|
||||
privacyNode.execute(privacyTransactions.newFilter(privacyGroupId, filterParameter));
|
||||
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final CallPrivateSmartContractFunction storeTransaction =
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
|
||||
privacyNode.getTransactionSigningKey(),
|
||||
Restriction.RESTRICTED,
|
||||
tenant,
|
||||
privacyGroupId);
|
||||
final String storeTransactionHash = privacyNode.execute(storeTransaction);
|
||||
|
||||
privacyNode.execute(privacyTransactions.getPrivateTransactionReceipt(storeTransactionHash));
|
||||
|
||||
// check that getting the filter changes works for a member
|
||||
assertThat(privacyNode.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasSize(1);
|
||||
|
||||
// check that getting the filter changes does not work if you are not a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
privacyNode.execute(privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
|
||||
// check that getting the filter logs works for a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
assertThat(privacyNode.execute(privacyTransactions.getFilterLogs(privacyGroupId, filterId)))
|
||||
.hasSize(3); // create privacy group, deploy event emitter, store on event emitter
|
||||
|
||||
// check that getting the filter logs does not work if you are not a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() -> privacyNode.execute(privacyTransactions.getFilterLogs(privacyGroupId, filterId)))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
|
||||
// check that getting the logs works for a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
assertThat(
|
||||
privacyNode.execute(privacyTransactions.privGetLogs(privacyGroupId, filterParameter)))
|
||||
.hasSize(3); // create privacy group, deploy event emitter, store on event emitter
|
||||
|
||||
// check that getting the logs does not work if you are not a member
|
||||
privacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
privacyNode.execute(
|
||||
privacyTransactions.privGetLogs(privacyGroupId, filterParameter)))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
|
||||
final List<Base64String> base64StringList =
|
||||
tenants.stream().map(Base64String::wrap).collect(Collectors.toList());
|
||||
|
||||
// check that a member can find the on-chain privacy group
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final List<PrivacyRequestFactory.FlexiblePrivacyGroup> group =
|
||||
privacyNode.execute(
|
||||
privacyTransactions.findFlexiblePrivacyGroup(
|
||||
Base64String.unwrapList(base64StringList)));
|
||||
assertThat(group.size()).isEqualTo(1);
|
||||
assertThat(group.get(0).getMembers()).containsAll(base64StringList).hasSize(2);
|
||||
|
||||
// check that when you are not a member you cannot find the privacy group
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
privacyNode.execute(
|
||||
privacyTransactions.findFlexiblePrivacyGroup(
|
||||
Base64String.unwrapList(base64StringList))))
|
||||
.hasMessageContaining("Error finding flexible privacy group");
|
||||
|
||||
// check that a member can do a priv_call
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final EthCall readValue =
|
||||
privacyNode.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall()));
|
||||
assertThat(new BigInteger(readValue.getValue().substring(2), 16))
|
||||
.isEqualByComparingTo(BigInteger.valueOf(VALUE_SET));
|
||||
|
||||
// check that when you are not a member you cannot do a priv_call
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
privacyNode.execute(
|
||||
privacyTransactions.privCall(
|
||||
privacyGroupId, eventEmitter, eventEmitter.value().encodeFunctionCall())))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
|
||||
// check that a member can do a priv_getTransaction
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenant));
|
||||
final PrivacyRequestFactory.GetPrivateTransactionResponse privTransaction =
|
||||
privacyNode.execute(privacyTransactions.privGetTransaction(storeTransactionHash));
|
||||
assertThat(privTransaction.getResult().getPrivacyGroupId()).isEqualTo(privacyGroupId);
|
||||
|
||||
// check that when you are not a member you cannot do a priv_getTransaction
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(removedTenant));
|
||||
assertThatThrownBy(
|
||||
() -> privacyNode.execute(privacyTransactions.privGetTransaction(storeTransactionHash)))
|
||||
.hasMessageContaining(
|
||||
"Expecting actual not to be null"); // TODO: returning null because the RPC is using the
|
||||
// enclave key
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removedMemberCannotGetFilterChanges() {
|
||||
final MultiTenancyPrivacyGroup allTenantsFromAlice = new MultiTenancyPrivacyGroup();
|
||||
final List<String> tenants = aliceMultiTenancyPrivacyNode.getTenants();
|
||||
allTenantsFromAlice.addNodeWithTenants(aliceMultiTenancyPrivacyNode, tenants);
|
||||
final String privacyGroupId = createFlexiblePrivacyGroup(allTenantsFromAlice);
|
||||
final MultiTenancyPrivacyNode multiTenancyPrivacyNode =
|
||||
allTenantsFromAlice.getPrivacyNodes().get(0);
|
||||
final String groupCreatingTenant = allTenantsFromAlice.getGroupCreatingTenant();
|
||||
final String tenantToBeRemoved =
|
||||
tenants.stream().filter(t -> !t.equals(groupCreatingTenant)).findFirst().orElseThrow();
|
||||
final PrivacyNode groupCreatingPrivacyNode = allTenantsFromAlice.getGroupCreatingPrivacyNode();
|
||||
final BesuNode groupCreatingPrivacyNodeBesu = groupCreatingPrivacyNode.getBesu();
|
||||
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(groupCreatingTenant));
|
||||
|
||||
final EventEmitter eventEmitter =
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privateContractTransactions.createSmartContractWithPrivacyGroupId(
|
||||
EventEmitter.class,
|
||||
groupCreatingPrivacyNode.getTransactionSigningKey(),
|
||||
groupCreatingTenant,
|
||||
privacyGroupId));
|
||||
|
||||
final LogFilterJsonParameter filterParameter =
|
||||
new LogFilterJsonParameter(
|
||||
"earliest",
|
||||
"latest",
|
||||
List.of(eventEmitter.getContractAddress()),
|
||||
Collections.emptyList(),
|
||||
null);
|
||||
|
||||
final String filterId =
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.newFilter(privacyGroupId, filterParameter));
|
||||
|
||||
final CallPrivateSmartContractFunction storeTransaction =
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
|
||||
groupCreatingPrivacyNode.getTransactionSigningKey(),
|
||||
Restriction.RESTRICTED,
|
||||
groupCreatingTenant,
|
||||
privacyGroupId);
|
||||
final String storeTransactionHash = groupCreatingPrivacyNode.execute(storeTransaction);
|
||||
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.getPrivateTransactionReceipt(storeTransactionHash));
|
||||
|
||||
// check that getting the filter changes works for a member
|
||||
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenantToBeRemoved));
|
||||
|
||||
assertThat(
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasSize(1);
|
||||
|
||||
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(groupCreatingTenant));
|
||||
final CallPrivateSmartContractFunction store2Transaction =
|
||||
privateContractTransactions.callSmartContractWithPrivacyGroupId(
|
||||
eventEmitter.getContractAddress(),
|
||||
eventEmitter.store(BigInteger.valueOf(VALUE_SET)).encodeFunctionCall(),
|
||||
groupCreatingPrivacyNode.getTransactionSigningKey(),
|
||||
Restriction.RESTRICTED,
|
||||
groupCreatingTenant,
|
||||
privacyGroupId);
|
||||
final String store2TransactionHash = groupCreatingPrivacyNode.execute(store2Transaction);
|
||||
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.getPrivateTransactionReceipt(store2TransactionHash));
|
||||
|
||||
// now remove from privacy group
|
||||
final String removeTransactionHash =
|
||||
removeFromPrivacyGroup(
|
||||
privacyGroupId,
|
||||
groupCreatingPrivacyNode,
|
||||
groupCreatingTenant,
|
||||
Credentials.create(groupCreatingPrivacyNode.getTransactionSigningKey()),
|
||||
tenantToBeRemoved);
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.getPrivateTransactionReceipt(removeTransactionHash));
|
||||
|
||||
// check that it does not work anymore when member has been removed
|
||||
groupCreatingPrivacyNodeBesu.useAuthenticationTokenInHeaderForJsonRpc(
|
||||
multiTenancyPrivacyNode.getTokenForTenant(tenantToBeRemoved));
|
||||
assertThatThrownBy(
|
||||
() ->
|
||||
groupCreatingPrivacyNode.execute(
|
||||
privacyTransactions.getFilterChanges(privacyGroupId, filterId)))
|
||||
.hasMessageContaining("Unauthorized");
|
||||
}
|
||||
|
||||
private String createFlexiblePrivacyGroup(final MultiTenancyPrivacyGroup group) {
|
||||
final List<MultiTenancyPrivacyNode> multiTenancyPrivacyNodes = group.getPrivacyNodes();
|
||||
final MultiTenancyPrivacyNode groupCreatorMultiTenancyPrivacyNode =
|
||||
multiTenancyPrivacyNodes.get(0);
|
||||
final PrivacyNode groupCreatorNode = group.getGroupCreatingPrivacyNode();
|
||||
final String groupCreatorTenant = group.getGroupCreatingTenant();
|
||||
final List<String> members = group.getTenants();
|
||||
final String token = groupCreatorMultiTenancyPrivacyNode.getTokenForTenant(groupCreatorTenant);
|
||||
final CreateFlexiblePrivacyGroupTransaction createTx =
|
||||
privacyTransactions.createFlexiblePrivacyGroup(
|
||||
groupCreatorNode, groupCreatorTenant, members, token);
|
||||
|
||||
final PrivacyRequestFactory.PrivxCreatePrivacyGroupResponse createResponse =
|
||||
groupCreatorNode.execute(createTx);
|
||||
final String privacyGroupId = createResponse.getPrivacyGroupId();
|
||||
|
||||
final List<Base64String> base64StringList =
|
||||
members.stream().map(Base64String::wrap).collect(Collectors.toList());
|
||||
for (final MultiTenancyPrivacyNode mtpn : multiTenancyPrivacyNodes) {
|
||||
final PrivacyNode privacyNode = mtpn.getPrivacyNode();
|
||||
for (final String tenant : mtpn.getTenants()) {
|
||||
if (members.contains(tenant)) {
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(mtpn.getTokenForTenant(tenant));
|
||||
privacyNode.verify(flexiblePrivacyGroupExists(privacyGroupId, base64StringList));
|
||||
}
|
||||
}
|
||||
}
|
||||
groupCreatorNode.getBesu().useAuthenticationTokenInHeaderForJsonRpc(token);
|
||||
final String commitmentHash =
|
||||
callGetParticipantsMethodAndReturnCommitmentHash(
|
||||
privacyGroupId, groupCreatorNode, groupCreatorTenant);
|
||||
final PrivateTransactionReceipt expectedReceipt =
|
||||
buildExpectedAddMemberTransactionReceipt(
|
||||
privacyGroupId, groupCreatorNode, groupCreatorTenant, members);
|
||||
|
||||
for (final MultiTenancyPrivacyNode mtpn : multiTenancyPrivacyNodes) {
|
||||
final PrivacyNode privacyNode = mtpn.getPrivacyNode();
|
||||
for (final String tenant : mtpn.getTenants()) {
|
||||
if (members.contains(tenant)) {
|
||||
privacyNode
|
||||
.getBesu()
|
||||
.useAuthenticationTokenInHeaderForJsonRpc(mtpn.getTokenForTenant(tenant));
|
||||
privacyNode.verify(
|
||||
privateTransactionVerifier.validPrivateTransactionReceipt(
|
||||
commitmentHash, expectedReceipt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return privacyGroupId;
|
||||
}
|
||||
|
||||
private String removeFromPrivacyGroup(
|
||||
final String privacyGroupId,
|
||||
final PrivacyNode node,
|
||||
final String nodeRemovingMember,
|
||||
final Credentials signer,
|
||||
final String memberBeingRemoved) {
|
||||
return node.execute(
|
||||
privacyTransactions.removeFromPrivacyGroup(
|
||||
privacyGroupId, nodeRemovingMember, signer, memberBeingRemoved));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user