Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increment private nonce even if transaction failed. #6593

Merged
merged 45 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9e57548
add flag and update Forest State
gtebrean Feb 19, 2024
62bbc2a
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean Apr 26, 2024
4826611
fix merge
gtebrean Apr 29, 2024
958600b
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean May 10, 2024
eceaf82
updates
gtebrean May 16, 2024
e2d4e96
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean May 16, 2024
8a38d85
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean May 18, 2024
30683b1
debug
gtebrean May 18, 2024
3940f4e
fix hash
gtebrean May 18, 2024
c7665c0
enable acceptancePrivacy tests
gtebrean May 18, 2024
4ede744
spotless
gtebrean May 18, 2024
d487715
enable acceptanceTests
gtebrean May 18, 2024
719117e
enable acceptanceTestsPrivacy
gtebrean May 18, 2024
0dc324e
enable acceptanceTestsPrivacy
gtebrean May 18, 2024
b79cab9
spotless
gtebrean May 18, 2024
d817886
debug phase
gtebrean May 18, 2024
818cd29
integration debug mess
gtebrean May 22, 2024
add450a
refactor
gtebrean May 23, 2024
908869c
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean May 23, 2024
d1cc3c1
fix conflicts
gtebrean May 23, 2024
b61714e
enable privacy tests
gtebrean May 23, 2024
7463e3b
fix
gtebrean May 23, 2024
f4b0581
clean
gtebrean May 23, 2024
1f372b7
potless
gtebrean May 23, 2024
641a61a
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean May 27, 2024
451e463
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean Jun 4, 2024
66ed9f5
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean Jun 5, 2024
77c8683
clean method
gtebrean Jun 26, 2024
1c10c80
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean Jun 27, 2024
83ea92a
clear transaction processor
gtebrean Jun 27, 2024
199a4ad
refactor method name
gtebrean Jul 1, 2024
b671c0c
extract interface
gtebrean Jul 1, 2024
01e7961
clean
gtebrean Jul 1, 2024
2238dab
fix import
gtebrean Jul 1, 2024
488cb0c
fix
gtebrean Jul 1, 2024
3955c95
fix doc
gtebrean Jul 1, 2024
3ac02fe
Merge remote-tracking branch 'upstream/main' into issue_1942_private_…
gtebrean Jul 1, 2024
b0cd635
remove changes to ForestMutableWorldState
pinges Jul 5, 2024
d1b22f5
Merge branch 'main' of github.com:hyperledger/besu into issue_1942_pr…
pinges Jul 5, 2024
0fd452f
clean up a bit
pinges Jul 5, 2024
8f88ef1
rename flag
gtebrean Jul 5, 2024
715bd09
Merge branch 'main' of github.com:hyperledger/besu into issue_1942_pr…
pinges Jul 10, 2024
2a2bf5c
some renaming and CHANGELOG entry
pinges Jul 10, 2024
e52a002
fix unit test
pinges Jul 10, 2024
6044b73
Merge branch 'main' into issue_1942_private_nonce
pinges Jul 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ public void startNode(final BesuNode node) {
if (node.getPrivacyParameters().isPrivacyPluginEnabled()) {
params.add("--Xprivacy-plugin-enabled");
}
if (node.getPrivacyParameters().isPrivateNonceIncrementationEnabled()) {
params.add("--privacy-nonce-always-increment");
}
}

if (!node.getBootnodes().isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ public BesuNode createNodeWithMultiTenantedPrivacy(
final String enclaveUrl,
final String authFile,
final String privTransactionSigningKey,
final boolean enableFlexiblePrivacy)
final boolean enableFlexiblePrivacy,
final boolean enableIncrementingPrivateNonce)
throws IOException, URISyntaxException {
final PrivacyParameters.Builder privacyParametersBuilder = new PrivacyParameters.Builder();
final PrivacyParameters privacyParameters =
Expand All @@ -298,6 +299,7 @@ public BesuNode createNodeWithMultiTenantedPrivacy(
.setStorageProvider(new InMemoryPrivacyStorageProvider())
.setEnclaveFactory(new EnclaveFactory(Vertx.vertx()))
.setEnclaveUrl(URI.create(enclaveUrl))
.setPrivateNonceIncrementationEnabled(enableIncrementingPrivateNonce)
.setPrivateKeyPath(
Paths.get(ClassLoader.getSystemResource(privTransactionSigningKey).toURI()))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public void setUp() throws Exception {
"http://127.0.0.1:" + wireMockRule.port(),
"authentication/auth_priv.toml",
"authentication/auth_priv_key",
false,
false);
multiTenancyCluster.start(node);
final String token =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* 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.multitenancy;

import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static java.nio.charset.StandardCharsets.UTF_8;

import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.enclave.types.PrivacyGroup;
import org.hyperledger.besu.enclave.types.ReceiveResponse;
import org.hyperledger.besu.enclave.types.SendResponse;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.plugin.data.Restriction;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.Cluster;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import org.hyperledger.besu.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;

import java.math.BigInteger;
import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

public class MultiTenancyPrivateNonceIncrementingTest extends AcceptanceTestBase {
private BesuNode node;
private final ObjectMapper mapper = new ObjectMapper();
private Cluster multiTenancyCluster;

private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final KeyPair TEST_KEY =
SIGNATURE_ALGORITHM
.get()
.createKeyPair(
SIGNATURE_ALGORITHM
.get()
.createPrivateKey(
new BigInteger(
"853d7f0010fd86d0d7811c1f9d968ea89a24484a8127b4a483ddf5d2cfec766d", 16)));
private static final String PRIVACY_GROUP_ID = "B1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static final String PARTICIPANT_ENCLAVE_KEY0 =
"A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static final String PARTICIPANT_ENCLAVE_KEY1 =
"sgFkVOyFndZe/5SAZJO5UYbrl7pezHetveriBBWWnE8=";
private final Address senderAddress =
Address.wrap(Bytes.fromHexString(accounts.getPrimaryBenefactor().getAddress()));

@Rule public WireMockRule wireMockRule = new WireMockRule(options().dynamicPort());

@Before
public void setUp() throws Exception {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().awaitPeerDiscovery(false).build();
multiTenancyCluster = new Cluster(clusterConfiguration, net);
node =
besu.createNodeWithMultiTenantedPrivacy(
"node1",
"http://127.0.0.1:" + wireMockRule.port(),
"authentication/auth_priv.toml",
"authentication/auth_priv_key",
false,
true);
multiTenancyCluster.start(node);
final String token =
node.execute(permissioningTransactions.createSuccessfulLogin("user", "pegasys"));
node.useAuthenticationTokenInHeaderForJsonRpc(token);
}

@After
public void tearDown() {
multiTenancyCluster.close();
}

@Test
public void validateUnsuccessfulPrivateTransactionsNonceIncrementation()
throws JsonProcessingException {
executePrivateFailingTransaction(0, 0, 1);
executePrivateValidTransaction(1, 1, 2);
executePrivateFailingTransaction(2, 2, 3);
executePrivateFailingTransaction(3, 3, 4);
executePrivateValidTransaction(4, 4, 5);
}

private void executePrivateValidTransaction(
final int nonce,
final int expectedTransactionCountBeforeExecution,
final int expectedTransactionCountAfterExecution)
throws JsonProcessingException {
final PrivateTransaction validSignedPrivateTransaction =
getValidSignedPrivateTransaction(senderAddress, nonce);

final String accountAddress = validSignedPrivateTransaction.getSender().toHexString();
final BytesValueRLPOutput rlpOutput = getRLPOutput(validSignedPrivateTransaction);

processEnclaveStub(validSignedPrivateTransaction);

node.verify(
priv.getTransactionCount(
accountAddress, PRIVACY_GROUP_ID, expectedTransactionCountBeforeExecution));

final Hash transactionReceipt =
node.execute(privacyTransactions.sendRawTransaction(rlpOutput.encoded().toHexString()));

node.verify(priv.getSuccessfulTransactionReceipt(transactionReceipt));
node.verify(
priv.getTransactionCount(
accountAddress, PRIVACY_GROUP_ID, expectedTransactionCountAfterExecution));
}

private void executePrivateFailingTransaction(
final int nonce,
final int expectedTransactionCountBeforeExecution,
final int expectedTransactionCountAfterExecution)
throws JsonProcessingException {
final PrivateTransaction invalidSignedPrivateTransaction =
getInvalidSignedPrivateTransaction(senderAddress, nonce);
final String accountAddress = invalidSignedPrivateTransaction.getSender().toHexString();
final BytesValueRLPOutput invalidTxRlp = getRLPOutput(invalidSignedPrivateTransaction);

processEnclaveStub(invalidSignedPrivateTransaction);

node.verify(
priv.getTransactionCount(
accountAddress, PRIVACY_GROUP_ID, expectedTransactionCountBeforeExecution));
final Hash invalidTransactionReceipt =
node.execute(privacyTransactions.sendRawTransaction(invalidTxRlp.encoded().toHexString()));

node.verify(priv.getFailedTransactionReceipt(invalidTransactionReceipt));
node.verify(
priv.getTransactionCount(
accountAddress, PRIVACY_GROUP_ID, expectedTransactionCountAfterExecution));
}

private void processEnclaveStub(final PrivateTransaction validSignedPrivateTransaction)
throws JsonProcessingException {
retrievePrivacyGroupEnclaveStub();
sendEnclaveStub();
receiveEnclaveStub(validSignedPrivateTransaction);
}

private void retrievePrivacyGroupEnclaveStub() throws JsonProcessingException {
final String retrieveGroupResponse =
mapper.writeValueAsString(
createPrivacyGroup(
List.of(PARTICIPANT_ENCLAVE_KEY0, PARTICIPANT_ENCLAVE_KEY1),
PrivacyGroup.Type.PANTHEON));
stubFor(post("/retrievePrivacyGroup").willReturn(ok(retrieveGroupResponse)));
}

private void sendEnclaveStub() throws JsonProcessingException {
final String sendResponse =
mapper.writeValueAsString(new SendResponse(PARTICIPANT_ENCLAVE_KEY1));
stubFor(post("/send").willReturn(ok(sendResponse)));
}

private void receiveEnclaveStub(final PrivateTransaction privTx) throws JsonProcessingException {
final BytesValueRLPOutput rlpOutput = getRLPOutput(privTx);
final String senderKey = privTx.getPrivateFrom().toBase64String();
final String receiveResponse =
mapper.writeValueAsString(
new ReceiveResponse(
rlpOutput.encoded().toBase64String().getBytes(UTF_8), PRIVACY_GROUP_ID, senderKey));
stubFor(post("/receive").willReturn(ok(receiveResponse)));
}

private BytesValueRLPOutput getRLPOutput(final PrivateTransaction privateTransaction) {
final BytesValueRLPOutput bvrlpo = new BytesValueRLPOutput();
privateTransaction.writeTo(bvrlpo);
return bvrlpo;
}

private PrivacyGroup createPrivacyGroup(
final List<String> groupMembers, final PrivacyGroup.Type groupType) {
return new PrivacyGroup(PRIVACY_GROUP_ID, groupType, "test", "testGroup", groupMembers);
}

private static PrivateTransaction getInvalidSignedPrivateTransaction(
final Address senderAddress, final int nonce) {
return PrivateTransaction.builder()
.nonce(nonce)
.gasPrice(Wei.ZERO)
.gasLimit(3000000)
.to(null)
.value(Wei.ZERO)
.payload(Bytes.fromHexString("0x1234"))
.sender(senderAddress)
.chainId(BigInteger.valueOf(1337))
.privateFrom(Bytes.fromBase64String(PARTICIPANT_ENCLAVE_KEY0))
.restriction(Restriction.RESTRICTED)
.privacyGroupId(Bytes.fromBase64String(PRIVACY_GROUP_ID))
.signAndBuild(TEST_KEY);
}

private static PrivateTransaction getValidSignedPrivateTransaction(
final Address senderAddress, final int nonce) {
return PrivateTransaction.builder()
.nonce(nonce)
.gasPrice(Wei.ZERO)
.gasLimit(3000000)
.to(null)
.value(Wei.ZERO)
.payload(Bytes.wrap(new byte[] {}))
.sender(senderAddress)
.chainId(BigInteger.valueOf(1337))
.privateFrom(Bytes.fromBase64String(PARTICIPANT_ENCLAVE_KEY0))
.restriction(Restriction.RESTRICTED)
.privacyGroupId(Bytes.fromBase64String(PRIVACY_GROUP_ID))
.signAndBuild(TEST_KEY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public void setUp() throws Exception {
"http://127.0.0.1:" + wireMockRule.port(),
"authentication/auth_priv.toml",
"authentication/auth_priv_key",
false,
false);
multiTenancyCluster.start(node);

Expand Down
8 changes: 8 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,12 @@ static class PrivacyOptionGroup {
names = {"--privacy-flexible-groups-enabled"},
description = "Enable flexible privacy groups (default: ${DEFAULT-VALUE})")
private final Boolean isFlexiblePrivacyGroupsEnabled = false;

@Option(
names = {"--privacy-nonce-always-increment"},
description =
"Enable private nonce incrementation even if the transaction didn't succeeded (default: ${DEFAULT-VALUE})")
private final Boolean isPrivateNonceIncrementationEnabled = false;
}

// Metrics Option Group
Expand Down Expand Up @@ -2062,6 +2068,8 @@ private PrivacyParameters privacyParameters() {
privacyOptionGroup.isFlexiblePrivacyGroupsEnabled);
privacyParametersBuilder.setPrivacyPluginEnabled(
unstablePrivacyPluginOptions.isPrivacyPluginEnabled());
privacyParametersBuilder.setPrivateNonceIncrementationEnabled(
privacyOptionGroup.isPrivateNonceIncrementationEnabled);

final boolean hasPrivacyPublicKey = privacyOptionGroup.privacyPublicKeyFile != null;

Expand Down
1 change: 1 addition & 0 deletions besu/src/test/resources/everything_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ privacy-multi-tenancy-enabled=true
privacy-marker-transaction-signing-key-file="./signerKey"
privacy-enable-database-migration=false
privacy-flexible-groups-enabled=false
privacy-nonce-always-increment=false

# Transaction Pool
tx-pool="layered"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ public void testSendAndReceive() {
new PrivateStateRootResolver(privateStateStorage),
new PrivateStateGenesisAllocator(
false, (privacyGroupId, blockNumber) -> Collections::emptyList),
false,
pinges marked this conversation as resolved.
Show resolved Hide resolved
"IntegrationTest");

privacyPrecompiledContract.setPrivateTransactionProcessor(mockPrivateTxProcessor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class PrivacyParameters {
private PrivateStateRootResolver privateStateRootResolver;
private PrivateWorldStateReader privateWorldStateReader;
private PrivacyPluginService privacyPluginService;
private boolean privateNonceIncrementationEnabled;

public Address getPrivacyAddress() {
if (isPrivacyPluginEnabled()) {
Expand Down Expand Up @@ -228,6 +229,15 @@ private PrivacyGroupGenesisProvider createPrivateGenesisProvider() {
}
}

public boolean isPrivateNonceIncrementationEnabled() {
return privateNonceIncrementationEnabled;
}

public void setPrivateNonceIncrementationEnabled(
final boolean privateNonceIncrementationEnabled) {
this.privateNonceIncrementationEnabled = privateNonceIncrementationEnabled;
}

@Override
public String toString() {
return "PrivacyParameters{"
Expand Down Expand Up @@ -263,6 +273,7 @@ public static class Builder {
private boolean flexiblePrivacyGroupsEnabled;
private boolean privacyPluginEnabled;
private PrivacyPluginService privacyPluginService;
private boolean privateNonceIncrementationEnabled;

public Builder setEnclaveUrl(final URI enclaveUrl) {
this.enclaveUrl = enclaveUrl;
Expand Down Expand Up @@ -314,6 +325,12 @@ public Builder setFlexiblePrivacyGroupsEnabled(final boolean flexiblePrivacyGrou
return this;
}

public Builder setPrivateNonceIncrementationEnabled(
final boolean isPrivateNonceIncrementationEnabled) {
this.privateNonceIncrementationEnabled = isPrivateNonceIncrementationEnabled;
return this;
}

public Builder setPrivacyPluginEnabled(final boolean privacyPluginEnabled) {
this.privacyPluginEnabled = privacyPluginEnabled;
return this;
Expand Down Expand Up @@ -382,6 +399,7 @@ public PrivacyParameters build() {
config.setMultiTenancyEnabled(multiTenancyEnabled);
config.setFlexiblePrivacyGroupsEnabled(flexiblePrivacyGroupsEnabled);
config.setPrivacyPluginEnabled(privacyPluginEnabled);
config.setPrivateNonceIncrementationEnabled(privateNonceIncrementationEnabled);
return config;
}
}
Expand Down
Loading
Loading