[PRIV] tests for onchain privacy (#465)

* testing around privx_findOnChainPrivacyGroup

Signed-off-by: Ivaylo Kirilov <iikirilov@gmail.com>

* test existence of on chain privacy precompile

Signed-off-by: Ivaylo Kirilov <iikirilov@gmail.com>

* test rehydration occurs in privacy block processor

Signed-off-by: Ivaylo Kirilov <iikirilov@gmail.com>

* fix compile

Signed-off-by: Ivaylo Kirilov <iikirilov@gmail.com>
pull/472/head
Ivaylo Kirilov 5 years ago committed by GitHub
parent 6770d67265
commit cf5307540a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 78
      besu/src/test/java/org/hyperledger/besu/PrivacyTest.java
  2. 22
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindOnChainPrivacyGroup.java
  3. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java
  4. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivFindPrivacyGroupTest.java
  5. 120
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/privx/PrivxFindOnChainPrivacyGroupTest.java
  6. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/MultiTenancyPrivacyController.java
  7. 22
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/PrivateTransactionDataFixture.java
  8. 122
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java

@ -70,7 +70,32 @@ public class PrivacyTest {
} }
@Test @Test
public void privacyPrecompiled() throws IOException, URISyntaxException { public void defaultPrivacy() throws IOException, URISyntaxException {
final BesuController<?> besuController = setUpControllerWithPrivacyEnabled(false);
final PrecompiledContract precompiledContract =
getPrecompile(besuController, Address.DEFAULT_PRIVACY);
assertThat(precompiledContract.getName()).isEqualTo("Privacy");
}
@Test
public void onchainEnabledPrivacy() throws IOException, URISyntaxException {
final BesuController<?> besuController = setUpControllerWithPrivacyEnabled(true);
final PrecompiledContract privacyPrecompiledContract =
getPrecompile(besuController, Address.DEFAULT_PRIVACY);
assertThat(privacyPrecompiledContract.getName()).isEqualTo("Privacy");
final PrecompiledContract onchainPrecompiledContract =
getPrecompile(besuController, Address.ONCHAIN_PRIVACY);
assertThat(onchainPrecompiledContract.getName()).isEqualTo("OnChainPrivacy");
}
private BesuController<?> setUpControllerWithPrivacyEnabled(final boolean onChainEnabled)
throws IOException, URISyntaxException {
final Path dataDir = folder.newFolder().toPath(); final Path dataDir = folder.newFolder().toPath();
final Path dbDir = dataDir.resolve("database"); final Path dbDir = dataDir.resolve("database");
final PrivacyParameters privacyParameters = final PrivacyParameters privacyParameters =
@ -80,33 +105,23 @@ public class PrivacyTest {
.setEnclaveUrl(new URI("http://127.0.0.1:8000")) .setEnclaveUrl(new URI("http://127.0.0.1:8000"))
.setStorageProvider(createKeyValueStorageProvider(dataDir, dbDir)) .setStorageProvider(createKeyValueStorageProvider(dataDir, dbDir))
.setEnclaveFactory(new EnclaveFactory(vertx)) .setEnclaveFactory(new EnclaveFactory(vertx))
.setOnchainPrivacyGroupsEnabled(onChainEnabled)
.build(); .build();
final BesuController<?> besuController = return new BesuController.Builder()
new BesuController.Builder() .fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet()) .synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.synchronizerConfiguration(SynchronizerConfiguration.builder().build()) .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryStorageProvider())
.storageProvider(new InMemoryStorageProvider()) .networkId(BigInteger.ONE)
.networkId(BigInteger.ONE) .miningParameters(new MiningParametersTestBuilder().enabled(false).build())
.miningParameters(new MiningParametersTestBuilder().enabled(false).build()) .nodeKeys(KeyPair.generate())
.nodeKeys(KeyPair.generate()) .metricsSystem(new NoOpMetricsSystem())
.metricsSystem(new NoOpMetricsSystem()) .dataDirectory(dataDir)
.dataDirectory(dataDir) .clock(TestClock.fixed())
.clock(TestClock.fixed()) .privacyParameters(privacyParameters)
.privacyParameters(privacyParameters) .transactionPoolConfiguration(TransactionPoolConfiguration.builder().build())
.transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) .targetGasLimit(GasLimitCalculator.DEFAULT)
.targetGasLimit(GasLimitCalculator.DEFAULT) .build();
.build();
final Address privacyContractAddress = Address.DEFAULT_PRIVACY;
final PrecompiledContract precompiledContract =
besuController
.getProtocolSchedule()
.getByBlockNumber(1)
.getPrecompileContractRegistry()
.get(privacyContractAddress, Account.DEFAULT_VERSION);
assertThat(precompiledContract.getName()).isEqualTo("Privacy");
} }
private PrivacyStorageProvider createKeyValueStorageProvider( private PrivacyStorageProvider createKeyValueStorageProvider(
@ -127,4 +142,13 @@ public class PrivacyTest {
.withMetricsSystem(new NoOpMetricsSystem()) .withMetricsSystem(new NoOpMetricsSystem())
.build(); .build();
} }
private PrecompiledContract getPrecompile(
final BesuController<?> besuController, final Address defaultPrivacy) {
return besuController
.getProtocolSchedule()
.getByBlockNumber(1)
.getPrecompileContractRegistry()
.get(defaultPrivacy, Account.DEFAULT_VERSION);
}
} }

@ -15,14 +15,17 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.privx; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.privx;
import static org.apache.logging.log4j.LogManager.getLogger; import static org.apache.logging.log4j.LogManager.getLogger;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.FIND_ON_CHAIN_PRIVACY_GROUP_ERROR;
import org.hyperledger.besu.enclave.types.PrivacyGroup; import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException;
import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Arrays; import java.util.Arrays;
@ -56,10 +59,21 @@ public class PrivxFindOnChainPrivacyGroup implements JsonRpcMethod {
LOG.trace("Finding a privacy group with members {}", Arrays.toString(addresses)); LOG.trace("Finding a privacy group with members {}", Arrays.toString(addresses));
final List<PrivacyGroup> response = final List<PrivacyGroup> response;
privacyController.findOnChainPrivacyGroup( try {
Arrays.asList(addresses), response =
enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser())); privacyController.findOnChainPrivacyGroup(
Arrays.asList(addresses),
enclavePublicKeyProvider.getEnclaveKey(requestContext.getUser()));
} catch (final MultiTenancyValidationException e) {
LOG.error("Unauthorized privacy multi-tenancy rpc request. {}", e.getMessage());
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), FIND_ON_CHAIN_PRIVACY_GROUP_ERROR);
} catch (final Exception e) {
LOG.error("Failed to fetch on chain privacy group", e);
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), FIND_ON_CHAIN_PRIVACY_GROUP_ERROR);
}
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response); return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), response);
} }

@ -111,6 +111,7 @@ public enum JsonRpcError {
CREATE_PRIVACY_GROUP_ERROR(-50100, "Error creating privacy group"), CREATE_PRIVACY_GROUP_ERROR(-50100, "Error creating privacy group"),
DELETE_PRIVACY_GROUP_ERROR(-50100, "Error deleting privacy group"), DELETE_PRIVACY_GROUP_ERROR(-50100, "Error deleting privacy group"),
FIND_PRIVACY_GROUP_ERROR(-50100, "Error finding privacy group"), FIND_PRIVACY_GROUP_ERROR(-50100, "Error finding privacy group"),
FIND_ON_CHAIN_PRIVACY_GROUP_ERROR(-50100, "Error finding on-chain privacy group"),
VALUE_NOT_ZERO(-50100, "We cannot transfer ether in private transaction yet."), VALUE_NOT_ZERO(-50100, "We cannot transfer ether in private transaction yet."),
DECODE_ERROR(-50100, "Unable to decode the private signed raw transaction"), DECODE_ERROR(-50100, "Unable to decode the private signed raw transaction"),
GET_PRIVATE_TRANSACTION_NONCE_ERROR(-50100, "Unable to determine nonce for account in group."), GET_PRIVATE_TRANSACTION_NONCE_ERROR(-50100, "Unable to determine nonce for account in group."),

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.priv;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.VALID_BASE64_ENCLAVE_KEY;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -43,7 +44,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class PrivFindPrivacyGroupTest { public class PrivFindPrivacyGroupTest {
private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="; private static final String ENCLAVE_PUBLIC_KEY = VALID_BASE64_ENCLAVE_KEY.toBase64String();
private static final List<String> ADDRESSES = private static final List<String> ADDRESSES =
List.of( List.of(
"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
@ -65,7 +66,7 @@ public class PrivFindPrivacyGroupTest {
when(privacyParameters.isEnabled()).thenReturn(true); when(privacyParameters.isEnabled()).thenReturn(true);
request = request =
new JsonRpcRequestContext( new JsonRpcRequestContext(
new JsonRpcRequest("1", "priv_deletePrivacyGroup", new Object[] {ADDRESSES}), user); new JsonRpcRequest("1", "priv_findPrivacyGroup", new Object[] {ADDRESSES}), user);
privacyGroup = new PrivacyGroup(); privacyGroup = new PrivacyGroup();
privacyGroup.setName("privacyGroup"); privacyGroup.setName("privacyGroup");
privacyGroup.setDescription("privacyGroup desc"); privacyGroup.setDescription("privacyGroup desc");
@ -115,5 +116,6 @@ public class PrivFindPrivacyGroupTest {
request.getRequest().getId(), JsonRpcError.FIND_PRIVACY_GROUP_ERROR); request.getRequest().getId(), JsonRpcError.FIND_PRIVACY_GROUP_ERROR);
final JsonRpcResponse response = privFindPrivacyGroup.response(request); final JsonRpcResponse response = privFindPrivacyGroup.response(request);
assertThat(response).isEqualTo(expectedResponse); assertThat(response).isEqualTo(expectedResponse);
verify(privacyController).findPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY);
} }
} }

@ -0,0 +1,120 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.privx;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.enclave.EnclaveClientException;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.EnclavePublicKeyProvider;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.privacy.MultiTenancyValidationException;
import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import java.util.Collections;
import java.util.List;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.User;
import io.vertx.ext.auth.jwt.impl.JWTUser;
import org.assertj.core.util.Lists;
import org.junit.Before;
import org.junit.Test;
public class PrivxFindOnChainPrivacyGroupTest {
private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static final List<String> ADDRESSES =
List.of(
"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73",
"0x627306090abab3a6e1400e9345bc60c78a8bef57");
private final Enclave enclave = mock(Enclave.class);
private final PrivacyParameters privacyParameters = mock(PrivacyParameters.class);
private final PrivacyController privacyController = mock(PrivacyController.class);
private final User user =
new JWTUser(new JsonObject().put("privacyPublicKey", ENCLAVE_PUBLIC_KEY), "");
private final EnclavePublicKeyProvider enclavePublicKeyProvider = (user) -> ENCLAVE_PUBLIC_KEY;
private JsonRpcRequestContext request;
private PrivacyGroup privacyGroup;
private PrivxFindOnChainPrivacyGroup privxFindOnChainPrivacyGroup;
@Before
public void setUp() {
when(privacyParameters.getEnclave()).thenReturn(enclave);
when(privacyParameters.isEnabled()).thenReturn(true);
request =
new JsonRpcRequestContext(
new JsonRpcRequest("1", "privx_findOnChainPrivacyGroup", new Object[] {ADDRESSES}),
user);
privacyGroup = new PrivacyGroup();
privacyGroup.setName("");
privacyGroup.setDescription("");
privacyGroup.setPrivacyGroupId("privacy group id");
privacyGroup.setMembers(Lists.list("member1"));
privxFindOnChainPrivacyGroup =
new PrivxFindOnChainPrivacyGroup(privacyController, enclavePublicKeyProvider);
}
@SuppressWarnings("unchecked")
@Test
public void findsPrivacyGroupWithValidAddresses() {
when(privacyController.findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY))
.thenReturn(Collections.singletonList(privacyGroup));
final JsonRpcSuccessResponse response =
(JsonRpcSuccessResponse) privxFindOnChainPrivacyGroup.response(request);
final List<PrivacyGroup> result = (List<PrivacyGroup>) response.getResult();
assertThat(result).hasSize(1);
assertThat(result.get(0)).isEqualToComparingFieldByField(privacyGroup);
verify(privacyController).findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY);
}
@Test
public void failsWithFindPrivacyGroupErrorIfEnclaveFails() {
when(privacyController.findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY))
.thenThrow(new EnclaveClientException(500, "some failure"));
final JsonRpcErrorResponse response =
(JsonRpcErrorResponse) privxFindOnChainPrivacyGroup.response(request);
assertThat(response.getError()).isEqualTo(JsonRpcError.FIND_ON_CHAIN_PRIVACY_GROUP_ERROR);
verify(privacyController).findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY);
}
@Test
public void failsWithUnauthorizedErrorIfMultiTenancyValidationFails() {
when(privacyController.findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY))
.thenThrow(new MultiTenancyValidationException("validation failed"));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(
request.getRequest().getId(), JsonRpcError.FIND_ON_CHAIN_PRIVACY_GROUP_ERROR);
final JsonRpcResponse response = privxFindOnChainPrivacyGroup.response(request);
assertThat(response).isEqualTo(expectedResponse);
verify(privacyController).findOnChainPrivacyGroup(ADDRESSES, ENCLAVE_PUBLIC_KEY);
}
}

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.transaction.CallParameter;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
@ -165,8 +166,16 @@ public class MultiTenancyPrivacyController implements PrivacyController {
@Override @Override
public List<PrivacyGroup> findOnChainPrivacyGroup( public List<PrivacyGroup> findOnChainPrivacyGroup(
final List<String> asList, final String enclaveKey) { final List<String> addresses, final String enclavePublicKey) {
return privacyController.findOnChainPrivacyGroup(asList, enclaveKey); if (!addresses.contains(enclavePublicKey)) {
throw new MultiTenancyValidationException(
"Privacy group addresses must contain the enclave public key");
}
List<PrivacyGroup> resultantGroups =
privacyController.findOnChainPrivacyGroup(addresses, enclavePublicKey);
return resultantGroups.stream()
.filter(g -> g.getMembers().contains(enclavePublicKey))
.collect(Collectors.toList());
} }
@Override @Override

@ -47,8 +47,8 @@ public class PrivateTransactionDataFixture {
new BigInteger( new BigInteger(
"8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16))); "8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", 16)));
public static final Bytes VALID_BASE64_ENCLAVE_KEY = public static final Bytes32 VALID_BASE64_ENCLAVE_KEY =
Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="); Bytes32.wrap(Bytes.fromBase64String("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo="));
public static final Bytes VALID_CONTRACT_DEPLOYMENT_PAYLOAD = public static final Bytes VALID_CONTRACT_DEPLOYMENT_PAYLOAD =
Bytes.fromHexString( Bytes.fromHexString(
@ -139,6 +139,24 @@ public class PrivateTransactionDataFixture {
null); null);
} }
public static ReceiveResponse generateAddToGroupReceiveResponse(
final PrivateTransaction privateTransaction, final Transaction markerTransaction) {
final List<PrivateTransactionWithMetadata> privateTransactionWithMetadataList =
generateAddBlobResponse(privateTransaction, markerTransaction);
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput();
rlpOutput.startList();
privateTransactionWithMetadataList.stream()
.forEach(
privateTransactionWithMetadata -> privateTransactionWithMetadata.writeTo(rlpOutput));
rlpOutput.endList();
return new ReceiveResponse(
rlpOutput.encoded().toBase64String().getBytes(UTF_8),
privateTransaction.getPrivacyGroupId().isPresent()
? privateTransaction.getPrivacyGroupId().get().toBase64String()
: "",
null);
}
public static List<PrivateTransactionWithMetadata> generateAddBlobResponse( public static List<PrivateTransactionWithMetadata> generateAddBlobResponse(
final PrivateTransaction privateTransaction, final Transaction markerTransaction) { final PrivateTransaction privateTransaction, final Transaction markerTransaction) {
final PrivateTransactionWithMetadata privateTransactionWithMetadata = final PrivateTransactionWithMetadata privateTransactionWithMetadata =

@ -15,23 +15,39 @@
package org.hyperledger.besu.ethereum.mainnet; package org.hyperledger.besu.ethereum.mainnet;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.VALID_BASE64_ENCLAVE_KEY;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.enclave.Enclave; import org.hyperledger.besu.enclave.Enclave;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.TransactionLocation;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.DefaultEvmAccount;
import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.MutableAccount;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap; import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateBlockMetadata;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateKeyValueStorage; import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateKeyValueStorage;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -44,6 +60,7 @@ public class PrivacyBlockProcessorTest {
private WorldStateArchive privateWorldStateArchive; private WorldStateArchive privateWorldStateArchive;
private Enclave enclave; private Enclave enclave;
private ProtocolSchedule<?> protocolSchedule; private ProtocolSchedule<?> protocolSchedule;
private WorldStateArchive publicWorldStateArchive;
@Before @Before
public void setUp() { public void setUp() {
@ -59,6 +76,8 @@ public class PrivacyBlockProcessorTest {
enclave, enclave,
privateStateStorage, privateStateStorage,
privateWorldStateArchive); privateWorldStateArchive);
publicWorldStateArchive = mock(WorldStateArchive.class);
privacyBlockProcessor.setPublicWorldStateArchive(publicWorldStateArchive);
} }
@Test @Test
@ -87,5 +106,108 @@ public class PrivacyBlockProcessorTest {
firstBlock.getHeader(), firstBlock.getHeader(),
firstBlock.getBody().getTransactions(), firstBlock.getBody().getTransactions(),
firstBlock.getBody().getOmmers()); firstBlock.getBody().getOmmers());
verify(blockProcessor)
.processBlock(
blockchain,
mutableWorldState,
secondBlock.getHeader(),
secondBlock.getBody().getTransactions(),
secondBlock.getBody().getOmmers());
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Test
public void mustPerformRehydration() {
final BlockDataGenerator blockDataGenerator = new BlockDataGenerator();
final Blockchain blockchain = mock(Blockchain.class);
final MutableWorldState mutableWorldState = mock(MutableWorldState.class);
when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class));
final Block firstBlock =
blockDataGenerator.block(
BlockDataGenerator.BlockOptions.create()
.addTransaction(PrivateTransactionDataFixture.privacyMarkerTransactionOnChain()));
final Block secondBlock =
blockDataGenerator.block(
BlockDataGenerator.BlockOptions.create()
.addTransaction(
PrivateTransactionDataFixture.privacyMarkerTransactionOnChainAdd()));
when(enclave.receive(any()))
.thenReturn(
PrivateTransactionDataFixture.generateAddToGroupReceiveResponse(
PrivateTransactionDataFixture.privateTransactionBesu(),
PrivateTransactionDataFixture.privacyMarkerTransactionOnChain()));
when(blockchain.getTransactionLocation(any()))
.thenReturn(Optional.of(new TransactionLocation(firstBlock.getHash(), 0)));
when(blockchain.getBlockByHash(any())).thenReturn(Optional.of(firstBlock));
when(blockchain.getBlockHeader(any())).thenReturn(Optional.of(firstBlock.getHeader()));
final ProtocolSpec protocolSpec = mockProtocolSpec();
when(protocolSchedule.getByBlockNumber(anyLong())).thenReturn(protocolSpec);
when(publicWorldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState));
final MutableWorldState mockPrivateStateArchive = mockPrivateStateArchive();
when(privateWorldStateArchive.getMutable(any()))
.thenReturn(Optional.of(mockPrivateStateArchive));
final PrivacyGroupHeadBlockMap expected =
new PrivacyGroupHeadBlockMap(
Collections.singletonMap(VALID_BASE64_ENCLAVE_KEY, firstBlock.getHash()));
privateStateStorage
.updater()
.putPrivacyGroupHeadBlockMap(firstBlock.getHash(), expected)
.putPrivateBlockMetadata(
firstBlock.getHash(), VALID_BASE64_ENCLAVE_KEY, PrivateBlockMetadata.empty())
.commit();
privacyBlockProcessor.processBlock(blockchain, mutableWorldState, secondBlock);
verify(blockProcessor)
.processBlock(
blockchain,
mutableWorldState,
secondBlock.getHeader(),
secondBlock.getBody().getTransactions(),
secondBlock.getBody().getOmmers());
}
private MutableWorldState mockPrivateStateArchive() {
final MutableWorldState mockPrivateState = mock(MutableWorldState.class);
final WorldUpdater mockWorldUpdater = mock(WorldUpdater.class);
final DefaultEvmAccount mockDefaultEvmAccount = mock(DefaultEvmAccount.class);
final MutableAccount mockMutableAccount = mock(MutableAccount.class);
when(mockDefaultEvmAccount.getMutable()).thenReturn(mockMutableAccount);
when(mockWorldUpdater.createAccount(any())).thenReturn(mockDefaultEvmAccount);
when(mockPrivateState.updater()).thenReturn(mockWorldUpdater);
when(mockPrivateState.rootHash()).thenReturn(Hash.ZERO);
return mockPrivateState;
}
@SuppressWarnings("rawtypes")
private ProtocolSpec mockProtocolSpec() {
final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
final TransactionProcessor mockPublicTransactionProcessor = mock(TransactionProcessor.class);
when(mockPublicTransactionProcessor.processTransaction(
any(), any(), any(), any(), any(), any(), anyBoolean(), any()))
.thenReturn(
MainnetTransactionProcessor.Result.successful(
Collections.emptyList(), 0, Bytes.EMPTY, ValidationResult.valid()));
when(protocolSpec.getTransactionProcessor()).thenReturn(mockPublicTransactionProcessor);
final PrivateTransactionProcessor mockPrivateTransactionProcessor =
mock(PrivateTransactionProcessor.class);
when(mockPrivateTransactionProcessor.processTransaction(
any(), any(), any(), any(), any(), any(), any(), any(), any()))
.thenReturn(
PrivateTransactionProcessor.Result.successful(
Collections.emptyList(), 0, Bytes.EMPTY, ValidationResult.valid()));
when(protocolSpec.getPrivateTransactionProcessor()).thenReturn(mockPrivateTransactionProcessor);
final AbstractBlockProcessor.TransactionReceiptFactory mockTransactionReceiptFactory =
mock(AbstractBlockProcessor.TransactionReceiptFactory.class);
when(mockTransactionReceiptFactory.create(any(), any(), anyLong()))
.thenReturn(new TransactionReceipt(0, 0, Collections.emptyList(), Optional.empty()));
when(protocolSpec.getTransactionReceiptFactory()).thenReturn(mockTransactionReceiptFactory);
when(protocolSpec.getBlockReward()).thenReturn(Wei.ZERO);
when(protocolSpec.getMiningBeneficiaryCalculator())
.thenReturn(mock(MiningBeneficiaryCalculator.class));
when(protocolSpec.isSkipZeroBlockRewards()).thenReturn(true);
return protocolSpec;
} }
} }

Loading…
Cancel
Save