diff --git a/CHANGELOG.md b/CHANGELOG.md index 51494f46b..798e53457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ ### Upcoming Breaking Changes +### Breaking Changes + +### Additions and Improvements +- Include current chain head block when computing `eth_maxPriorityFeePerGas` [#7485](https://github.com/hyperledger/besu/pull/7485) + +### Bug fixes + +## 24.9.0 + +### Upcoming Breaking Changes + ### Breaking Changes - Receipt compaction is enabled by default. It will no longer be possible to downgrade Besu to versions prior to 24.5.1. @@ -11,6 +22,7 @@ - Add 'inbound' field to admin_peers JSON-RPC Call [#7461](https://github.com/hyperledger/besu/pull/7461) - Add pending block header to `TransactionEvaluationContext` plugin API [#7483](https://github.com/hyperledger/besu/pull/7483) - Add bootnode to holesky config [#7500](https://github.com/hyperledger/besu/pull/7500) +- Implement engine_getClientVersionV1 [#7512](https://github.com/hyperledger/besu/pull/7512) - Performance optimzation for ECMUL (1 of 2) [#7509](https://github.com/hyperledger/besu/pull/7509) - Performance optimzation for ECMUL (2 of 2) [#7543](https://github.com/hyperledger/besu/pull/7543) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java deleted file mode 100644 index 581fd7172..000000000 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/ParameterizedEnclaveTestBase.java +++ /dev/null @@ -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 params() { - return Arrays.asList( - new Object[][] { - {RESTRICTED, TESSERA, NACL}, - {RESTRICTED, TESSERA, EC}, - {UNRESTRICTED, NOOP, EnclaveEncryptorType.NOOP} - }); - } - - public Transaction 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); - } - } -} diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java deleted file mode 100644 index 8e12cbc7a..000000000 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyAcceptanceTestBase.java +++ /dev/null @@ -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(); - } -} diff --git a/acceptance-tests/test-plugins/build.gradle b/acceptance-tests/test-plugins/build.gradle index 19a45d218..65a3dc64d 100644 --- a/acceptance-tests/test-plugins/build.gradle +++ b/acceptance-tests/test-plugins/build.gradle @@ -25,7 +25,8 @@ task testPluginsJar(type: Jar) { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } from sourceSets.main.output diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java deleted file mode 100644 index 4475627fd..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/BftPrivacyClusterAcceptanceTest.java +++ /dev/null @@ -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 bftPrivacyTypes() { - final List 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)); - } - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java deleted file mode 100644 index 65786988c..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/DeployPrivateSmartContractAcceptanceTest.java +++ /dev/null @@ -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); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java deleted file mode 100644 index 3eab2b724..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/EnclaveErrorAcceptanceTest.java +++ /dev/null @@ -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 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 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]; - } - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java deleted file mode 100644 index fb0a128b8..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTest.java +++ /dev/null @@ -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 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 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 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 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 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 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 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 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 deployPrivateContract( - final Class 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTestBase.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTestBase.java deleted file mode 100644 index 9e4f1638d..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/FlexiblePrivacyAcceptanceTestBase.java +++ /dev/null @@ -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 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. - * - *

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 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 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 members) { - return buildExpectedAddMemberTransactionReceipt( - privacyGroupId, groupCreator, groupCreator.getEnclaveKey(), members); - } - - protected PrivateTransactionReceipt buildExpectedAddMemberTransactionReceipt( - final String privacyGroupId, - final PrivacyNode groupCreator, - final String privateFrom, - final List 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 members) { - return privateTransactionVerifier.flexiblePrivacyGroupExists(privacyGroupId, members); - } - - protected String getContractDeploymentCommitmentHash(final Contract contract) { - final Optional 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 membersEnclaveKeys = - Arrays.stream(members) - .map(PrivacyNode::getEnclaveKey) - .map(Base64String::wrap) - .collect(Collectors.toList()); - - for (final PrivacyNode member : members) { - member.verify(flexiblePrivacyGroupExists(privacyGroupId, membersEnclaveKeys)); - } - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java deleted file mode 100644 index 330f00554..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PluginPrivacySigningAcceptanceTest.java +++ /dev/null @@ -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 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"); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java deleted file mode 100644 index 9d8a32590..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivCallAcceptanceTest.java +++ /dev/null @@ -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 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 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 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 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 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 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 inputParameters = - useInvalidParameters ? Arrays.asList(invalid) : Collections.emptyList(); - - final Function function = - useRevertFunction - ? new Function( - FUNC_REVERTWITHREVERTREASON, - inputParameters, - Arrays.>asList(new TypeReference() {})) - : new Function( - "value", - inputParameters, - Arrays.>asList(new TypeReference() {})); - - 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); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java deleted file mode 100644 index b2e0d92dd..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootFlexibleGroupAcceptanceTest.java +++ /dev/null @@ -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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java deleted file mode 100644 index 6921da147..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivDebugGetStateRootOffchainGroupAcceptanceTest.java +++ /dev/null @@ -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"); - } - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java deleted file mode 100644 index 6ca47035d..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetCodeAcceptanceTest.java +++ /dev/null @@ -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; - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java deleted file mode 100644 index 7ebdcea82..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetLogsAcceptanceTest.java +++ /dev/null @@ -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 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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java deleted file mode 100644 index 59c5b8f71..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivGetPrivateTransactionAcceptanceTest.java +++ /dev/null @@ -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 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 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()); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivTraceTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivTraceTransactionAcceptanceTest.java deleted file mode 100644 index 9cac6d8bf..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivTraceTransactionAcceptanceTest.java +++ /dev/null @@ -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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java deleted file mode 100644 index e1bb0a980..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyClusterAcceptanceTest.java +++ /dev/null @@ -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 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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java deleted file mode 100644 index ea94bb293..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyGroupAcceptanceTest.java +++ /dev/null @@ -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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java deleted file mode 100644 index 56e2b04a3..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivacyReceiptAcceptanceTest.java +++ /dev/null @@ -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 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 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 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 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()); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java deleted file mode 100644 index c0a63446b..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateContractPublicStateAcceptanceTest.java +++ /dev/null @@ -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 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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java deleted file mode 100644 index 82267f8b5..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateGenesisAcceptanceTest.java +++ /dev/null @@ -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); - } - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java deleted file mode 100644 index e9307beda..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/PrivateLogFilterAcceptanceTest.java +++ /dev/null @@ -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 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)); - } -} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java deleted file mode 100644 index da692f21b..000000000 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/privacy/multitenancy/FlexibleMultiTenancyAcceptanceTest.java +++ /dev/null @@ -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 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 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 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 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 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 multiTenancyPrivacyNodes = group.getPrivacyNodes(); - final MultiTenancyPrivacyNode groupCreatorMultiTenancyPrivacyNode = - multiTenancyPrivacyNodes.get(0); - final PrivacyNode groupCreatorNode = group.getGroupCreatingPrivacyNode(); - final String groupCreatorTenant = group.getGroupCreatingTenant(); - final List 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 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)); - } -} diff --git a/besu/build.gradle b/besu/build.gradle index 286ca7a30..a0e6c7843 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java index 54447a596..94414ee5f 100644 --- a/besu/src/main/java/org/hyperledger/besu/BesuInfo.java +++ b/besu/src/main/java/org/hyperledger/besu/BesuInfo.java @@ -16,7 +16,11 @@ package org.hyperledger.besu; import org.hyperledger.besu.util.platform.PlatformDetector; +import java.net.JarURLConnection; +import java.net.URL; import java.util.Optional; +import java.util.jar.Attributes; +import java.util.jar.Manifest; /** * Represent Besu information such as version, OS etc. Used with --version option and during Besu @@ -27,6 +31,24 @@ public final class BesuInfo { private static final String VERSION = BesuInfo.class.getPackage().getImplementationVersion(); private static final String OS = PlatformDetector.getOS(); private static final String VM = PlatformDetector.getVM(); + private static final String COMMIT; + + static { + String className = BesuInfo.class.getSimpleName() + ".class"; + String classPath = BesuInfo.class.getResource(className).toString(); + + String commit; + try { + URL url = new URL(classPath); + JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); + Manifest manifest = jarConnection.getManifest(); + Attributes attributes = manifest.getMainAttributes(); + commit = attributes.getValue("Commit-Hash"); + } catch (Exception e) { + commit = null; + } + COMMIT = commit; + } private BesuInfo() {} @@ -60,4 +82,13 @@ public final class BesuInfo { .map(identity -> String.format("%s/%s/v%s/%s/%s", CLIENT, identity, VERSION, OS, VM)) .orElse(version()); } + + /** + * Generate the commit hash for this besu version + * + * @return the commit hash for this besu version + */ + public static String commit() { + return COMMIT; + } } diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index e34c0115f..9eaf254bb 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -1291,6 +1291,8 @@ public class RunnerBuilder { new JsonRpcMethodsFactory() .methods( BesuInfo.nodeName(identityString), + BesuInfo.shortVersion(), + BesuInfo.commit(), ethNetworkConfig.networkId(), besuController.getGenesisConfigOptions(), network, diff --git a/build.gradle b/build.gradle index 1bbd29018..6e2de8bf0 100644 --- a/build.gradle +++ b/build.gradle @@ -148,10 +148,6 @@ allprojects { url 'https://splunk.jfrog.io/splunk/ext-releases-local' content { includeGroupByRegex('com\\.splunk\\..*') } } - maven { - url 'https://gitlab.com/api/v4/projects/19871573/packages/maven' - content { includeGroupByRegex('com\\.gitlab\\.javafuzz(\\..*)?') } - } mavenCentral() diff --git a/config/build.gradle b/config/build.gradle index ae6b2ff4c..a78b9a710 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/consensus/clique/build.gradle b/consensus/clique/build.gradle index f09e58377..d2fb44c6e 100644 --- a/consensus/clique/build.gradle +++ b/consensus/clique/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/consensus/common/build.gradle b/consensus/common/build.gradle index 0043fe071..7a937f757 100644 --- a/consensus/common/build.gradle +++ b/consensus/common/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/consensus/ibft/build.gradle b/consensus/ibft/build.gradle index dd0594480..da6304c4e 100644 --- a/consensus/ibft/build.gradle +++ b/consensus/ibft/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/consensus/merge/build.gradle b/consensus/merge/build.gradle index 9476f09d9..e1b98e21e 100644 --- a/consensus/merge/build.gradle +++ b/consensus/merge/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/consensus/qbft/build.gradle b/consensus/qbft/build.gradle index bb3d9a3f8..9675c4df8 100644 --- a/consensus/qbft/build.gradle +++ b/consensus/qbft/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/crypto/algorithms/build.gradle b/crypto/algorithms/build.gradle index b9bb6d62f..cc25c0fa8 100644 --- a/crypto/algorithms/build.gradle +++ b/crypto/algorithms/build.gradle @@ -23,6 +23,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.internal.crypto' ) } diff --git a/crypto/services/build.gradle b/crypto/services/build.gradle index 6188462f5..50d0de051 100644 --- a/crypto/services/build.gradle +++ b/crypto/services/build.gradle @@ -23,6 +23,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.internal.crypto' ) } diff --git a/datatypes/build.gradle b/datatypes/build.gradle index da1e70e56..c2c8d3d44 100644 --- a/datatypes/build.gradle +++ b/datatypes/build.gradle @@ -23,6 +23,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.datatypes' ) } diff --git a/ethereum/api/build.gradle b/ethereum/api/build.gradle index ed395df8c..3269812fe 100644 --- a/ethereum/api/build.gradle +++ b/ethereum/api/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java index a8226a6a6..b5f65e6d4 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java @@ -64,7 +64,9 @@ import io.vertx.core.VertxOptions; /** Provides a facade to construct the JSON-RPC component. */ public class JsonRpcTestMethodsFactory { - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger NETWORK_ID = BigInteger.valueOf(123); private final BlockchainImporter importer; @@ -175,7 +177,9 @@ public class JsonRpcTestMethodsFactory { return new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, NETWORK_ID, new StubGenesisConfigOptions(), peerDiscovery, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java index 0b97bdb2e..d4338d58c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java @@ -203,7 +203,7 @@ public class GraphQLDataFetchers { * *

The DataFetcher is a functional interface. It has a single method that takes a * DataFetchingEnvironment object as input and returns the maximum priority fee per gas as a Wei - * object. If the maximum priority fee per gas is not available, it returns Wei.ZERO. + * object. * * @return a DataFetcher that fetches the maximum priority fee per gas of the Ethereum node */ @@ -211,7 +211,7 @@ public class GraphQLDataFetchers { return dataFetchingEnvironment -> { final BlockchainQueries blockchainQuery = dataFetchingEnvironment.getGraphQlContext().get(GraphQLContextType.BLOCKCHAIN_QUERIES); - return blockchainQuery.gasPriorityFee().orElse(Wei.ZERO); + return blockchainQuery.gasPriorityFee(); }; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 5c9da63bc..79d33ffba 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -63,6 +63,7 @@ public enum RpcMethod { ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"), ENGINE_FORKCHOICE_UPDATED_V3("engine_forkchoiceUpdatedV3"), ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"), + ENGINE_GET_CLIENT_VERSION_V1("engine_getClientVersionV1"), ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1("engine_getPayloadBodiesByHashV1"), ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1("engine_getPayloadBodiesByRangeV1"), ENGINE_EXCHANGE_CAPABILITIES("engine_exchangeCapabilities"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGas.java index 2828fee7a..71cb5ea3c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGas.java @@ -21,19 +21,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; - -import java.util.Optional; public class EthMaxPriorityFeePerGas implements JsonRpcMethod { private final BlockchainQueries blockchainQueries; - private final MiningCoordinator miningCoordinator; - public EthMaxPriorityFeePerGas( - final BlockchainQueries blockchainQueries, final MiningCoordinator miningCoordinator) { + public EthMaxPriorityFeePerGas(final BlockchainQueries blockchainQueries) { this.blockchainQueries = blockchainQueries; - this.miningCoordinator = miningCoordinator; } @Override @@ -48,7 +42,6 @@ public class EthMaxPriorityFeePerGas implements JsonRpcMethod { } private Wei fetchAndLimitPriorityFeePerGas() { - final Optional gasPrice = blockchainQueries.gasPriorityFee(); - return gasPrice.orElseGet(miningCoordinator::getMinPriorityFeePerGas); + return blockchainQueries.gasPriorityFee(); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java new file mode 100644 index 000000000..689cb44e6 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1.java @@ -0,0 +1,57 @@ +/* + * 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.ethereum.api.jsonrpc.internal.methods.engine; + +import org.hyperledger.besu.ethereum.ProtocolContext; +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.methods.ExecutionEngineJsonRpcMethod; +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.results.EngineGetClientVersionResultV1; + +import io.vertx.core.Vertx; + +public class EngineGetClientVersionV1 extends ExecutionEngineJsonRpcMethod { + private static final String ENGINE_CLIENT_CODE = "BU"; + private static final String ENGINE_CLIENT_NAME = "Besu"; + + private final String clientVersion; + private final String commit; + + public EngineGetClientVersionV1( + final Vertx vertx, + final ProtocolContext protocolContext, + final EngineCallListener engineCallListener, + final String clientVersion, + final String commit) { + super(vertx, protocolContext, engineCallListener); + this.clientVersion = clientVersion; + this.commit = commit; + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_CLIENT_VERSION_V1.getMethodName(); + } + + @Override + public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + new EngineGetClientVersionResultV1( + ENGINE_CLIENT_CODE, ENGINE_CLIENT_NAME, clientVersion, commit.substring(0, 8))); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetClientVersionResultV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetClientVersionResultV1.java new file mode 100644 index 000000000..8251de6dc --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetClientVersionResultV1.java @@ -0,0 +1,52 @@ +/* + * 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.ethereum.api.jsonrpc.internal.results; + +import com.fasterxml.jackson.annotation.JsonGetter; + +public class EngineGetClientVersionResultV1 { + private final String code; + private final String name; + private final String version; + private final String commit; + + public EngineGetClientVersionResultV1( + final String code, final String name, final String version, final String commit) { + this.code = code; + this.name = name; + this.version = version; + this.commit = commit; + } + + @JsonGetter(value = "code") + public String getCode() { + return code; + } + + @JsonGetter(value = "name") + public String getName() { + return name; + } + + @JsonGetter(value = "version") + public String getVersion() { + return version; + } + + @JsonGetter(value = "commit") + public String getCommit() { + return commit; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index c7575a543..5baa11064 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -185,6 +185,6 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods { new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule), new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule), new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule), - new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator)); + new EthMaxPriorityFeePerGas(blockchainQueries)); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index ca6692665..6dda09bce 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineE import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV3; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetClientVersionV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByHashV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByRangeV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV1; @@ -57,13 +58,17 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { private final ProtocolContext protocolContext; private final EthPeers ethPeers; private final Vertx consensusEngineServer; + private final String clientVersion; + private final String commit; ExecutionEngineJsonRpcMethods( final MiningCoordinator miningCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthPeers ethPeers, - final Vertx consensusEngineServer) { + final Vertx consensusEngineServer, + final String clientVersion, + final String commit) { this.mergeCoordinator = Optional.ofNullable(miningCoordinator) .filter(mc -> mc.isCompatibleWithEngineApi()) @@ -72,6 +77,8 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { this.protocolContext = protocolContext; this.ethPeers = ethPeers; this.consensusEngineServer = consensusEngineServer; + this.clientVersion = clientVersion; + this.commit = commit; } @Override @@ -147,7 +154,9 @@ public class ExecutionEngineJsonRpcMethods extends ApiGroupJsonRpcMethods { new EngineExchangeCapabilities( consensusEngineServer, protocolContext, engineQosTimer), new EnginePreparePayloadDebug( - consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get()))); + consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get()), + new EngineGetClientVersionV1( + consensusEngineServer, protocolContext, engineQosTimer, clientVersion, commit))); if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("cancun"))) { executionEngineApisSupported.add( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 924889ef4..41227c2ca 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -54,7 +54,9 @@ import io.vertx.core.Vertx; public class JsonRpcMethodsFactory { public Map methods( + final String clientNodeName, final String clientVersion, + final String commit, final BigInteger networkId, final GenesisConfigOptions genesisConfigOptions, final P2PNetwork p2pNetwork, @@ -89,7 +91,7 @@ public class JsonRpcMethodsFactory { final List availableApiGroups = List.of( new AdminJsonRpcMethods( - clientVersion, + clientNodeName, networkId, genesisConfigOptions, p2pNetwork, @@ -115,7 +117,9 @@ public class JsonRpcMethodsFactory { protocolSchedule, protocolContext, ethPeers, - consensusEngineServer), + consensusEngineServer, + clientVersion, + commit), new EthJsonRpcMethods( blockchainQueries, synchronizer, @@ -141,7 +145,7 @@ public class JsonRpcMethodsFactory { filterManager), new PrivxJsonRpcMethods( blockchainQueries, protocolSchedule, transactionPool, privacyParameters), - new Web3JsonRpcMethods(clientVersion), + new Web3JsonRpcMethods(clientNodeName), new TraceJsonRpcMethods( blockchainQueries, protocolSchedule, protocolContext, apiConfiguration), new TxPoolJsonRpcMethods(transactionPool), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 6e0f0e3e3..c03bf124c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -46,7 +46,6 @@ import org.hyperledger.besu.evm.log.LogsBloomFilter; import java.io.EOFException; import java.io.IOException; import java.io.RandomAccessFile; -import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -1006,7 +1005,7 @@ public class BlockchainQueries { .sorted() .toArray(Wei[]::new); - return (gasCollection == null || gasCollection.length == 0) + return gasCollection.length == 0 ? gasPriceLowerBound(chainHeadHeader, nextBlockFeeMarket) : UInt256s.max( gasPriceLowerBound(chainHeadHeader, nextBlockFeeMarket), @@ -1045,31 +1044,39 @@ public class BlockchainQueries { return minGasPrice; } - public Optional gasPriorityFee() { - final long blockHeight = headBlockNumber(); - final BigInteger[] gasCollection = - LongStream.range(Math.max(0, blockHeight - apiConfig.getGasPriceBlocks()), blockHeight) - .mapToObj( - l -> - blockchain - .getBlockByNumber(l) - .map(Block::getBody) - .map(BlockBody::getTransactions) - .orElseThrow( - () -> new IllegalStateException("Could not retrieve block #" + l))) + public Wei gasPriorityFee() { + final Block chainHeadBlock = blockchain.getChainHeadBlock(); + final long blockHeight = chainHeadBlock.getHeader().getNumber(); + + final Wei[] gasCollection = + Stream.concat( + LongStream.range( + Math.max(0, blockHeight - apiConfig.getGasPriceBlocks() + 1), blockHeight) + .mapToObj( + l -> + blockchain + .getBlockByNumber(l) + .orElseThrow( + () -> + new IllegalStateException( + "Could not retrieve block #" + l))), + Stream.of(chainHeadBlock)) + .map(Block::getBody) + .map(BlockBody::getTransactions) .flatMap(Collection::stream) .filter(t -> t.getMaxPriorityFeePerGas().isPresent()) - .map(t -> t.getMaxPriorityFeePerGas().get().toBigInteger()) - .sorted(BigInteger::compareTo) - .toArray(BigInteger[]::new); - return (gasCollection.length == 0) - ? Optional.empty() - : Optional.of( - Wei.of( - gasCollection[ - Math.min( - gasCollection.length - 1, - (int) ((gasCollection.length) * apiConfig.getGasPriceFraction()))])); + .map(t -> t.getMaxPriorityFeePerGas().get()) + .sorted() + .toArray(Wei[]::new); + + return gasCollection.length == 0 + ? miningParameters.getMinPriorityFeePerGas() + : UInt256s.max( + miningParameters.getMinPriorityFeePerGas(), + gasCollection[ + Math.min( + gasCollection.length - 1, + (int) ((gasCollection.length) * apiConfig.getGasPriceFraction()))]); } /** diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java index d6a04b4cb..0e008568d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceCorsTest.java @@ -14,6 +14,10 @@ */ package org.hyperledger.besu.ethereum.api.graphql; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -38,7 +42,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mockito; public class GraphQLHttpServiceCorsTest { @TempDir private Path folder; @@ -208,10 +211,11 @@ public class GraphQLHttpServiceCorsTest { config.setCorsAllowedDomains(Lists.newArrayList(corsAllowedDomains)); } - final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class); - final Synchronizer synchronizer = Mockito.mock(Synchronizer.class); + final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); + when(blockchainQueries.gasPriorityFee()).thenReturn(Wei.ONE); + final Synchronizer synchronizer = mock(Synchronizer.class); - final PoWMiningCoordinator miningCoordinatorMock = Mockito.mock(PoWMiningCoordinator.class); + final PoWMiningCoordinator miningCoordinatorMock = mock(PoWMiningCoordinator.class); // mock graphql context final Map graphQLContextMap = @@ -219,7 +223,7 @@ public class GraphQLHttpServiceCorsTest { GraphQLContextType.BLOCKCHAIN_QUERIES, blockchainQueries, GraphQLContextType.TRANSACTION_POOL, - Mockito.mock(TransactionPool.class), + mock(TransactionPool.class), GraphQLContextType.MINING_COORDINATOR, miningCoordinatorMock, GraphQLContextType.SYNCHRONIZER, @@ -233,7 +237,7 @@ public class GraphQLHttpServiceCorsTest { final GraphQLHttpService graphQLHttpService = new GraphQLHttpService( - vertx, folder, config, graphQL, graphQLContextMap, Mockito.mock(EthScheduler.class)); + vertx, folder, config, graphQL, graphQLContextMap, mock(EthScheduler.class)); graphQLHttpService.start().join(); return graphQLHttpService; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java index ec33bd926..90833c42a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLHttpServiceHostWhitelistTest.java @@ -14,6 +14,10 @@ */ package org.hyperledger.besu.ethereum.api.graphql; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator; import org.hyperledger.besu.ethereum.core.Synchronizer; @@ -42,7 +46,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.mockito.Mockito; public class GraphQLHttpServiceHostWhitelistTest { @@ -69,17 +72,18 @@ public class GraphQLHttpServiceHostWhitelistTest { } private GraphQLHttpService createGraphQLHttpService() throws Exception { - final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class); - final Synchronizer synchronizer = Mockito.mock(Synchronizer.class); + final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); + when(blockchainQueries.gasPriorityFee()).thenReturn(Wei.ONE); + final Synchronizer synchronizer = mock(Synchronizer.class); - final PoWMiningCoordinator miningCoordinatorMock = Mockito.mock(PoWMiningCoordinator.class); + final PoWMiningCoordinator miningCoordinatorMock = mock(PoWMiningCoordinator.class); final Map graphQLContextMap = Map.of( GraphQLContextType.BLOCKCHAIN_QUERIES, blockchainQueries, GraphQLContextType.TRANSACTION_POOL, - Mockito.mock(TransactionPool.class), + mock(TransactionPool.class), GraphQLContextType.MINING_COORDINATOR, miningCoordinatorMock, GraphQLContextType.SYNCHRONIZER, @@ -92,7 +96,7 @@ public class GraphQLHttpServiceHostWhitelistTest { final GraphQL graphQL = GraphQLProvider.buildGraphQL(dataFetchers); return new GraphQLHttpService( - vertx, folder, graphQLConfig, graphQL, graphQLContextMap, Mockito.mock(EthScheduler.class)); + vertx, folder, graphQLConfig, graphQL, graphQLContextMap, mock(EthScheduler.class)); } private static GraphQLConfiguration createGraphQLConfig() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index 9193574c4..862e17b89 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -75,7 +75,9 @@ public abstract class AbstractJsonRpcHttpServiceTest { protected BlockchainSetupUtil blockchainSetupUtil; - protected static String CLIENT_VERSION = "TestClientVersion/0.1.0"; + protected static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + protected static final String CLIENT_VERSION = "0.1.0"; + protected static final String CLIENT_COMMIT = "12345678"; protected static final BigInteger NETWORK_ID = BigInteger.valueOf(123); protected static final Collection JSON_RPC_APIS = Arrays.asList( @@ -168,7 +170,9 @@ public abstract class AbstractJsonRpcHttpServiceTest { return new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, NETWORK_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java index 061d2a2d6..4a03b2eb9 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AdminJsonRpcHttpServiceTest.java @@ -58,13 +58,13 @@ public class AdminJsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { final List peerList = new ArrayList<>(); final PeerInfo info1 = new PeerInfo( - 4, CLIENT_VERSION, caps, 30302, Bytes.fromHexString(String.format("%0128x", 1))); + 4, CLIENT_NODE_NAME, caps, 30302, Bytes.fromHexString(String.format("%0128x", 1))); final PeerInfo info2 = new PeerInfo( - 4, CLIENT_VERSION, caps, 60302, Bytes.fromHexString(String.format("%0128x", 2))); + 4, CLIENT_NODE_NAME, caps, 60302, Bytes.fromHexString(String.format("%0128x", 2))); final PeerInfo info3 = new PeerInfo( - 4, CLIENT_VERSION, caps, 60303, Bytes.fromHexString(String.format("%0128x", 3))); + 4, CLIENT_NODE_NAME, caps, 60303, Bytes.fromHexString(String.format("%0128x", 3))); final InetSocketAddress addr30301 = new InetSocketAddress("localhost", 30301); final InetSocketAddress addr30302 = new InetSocketAddress("localhost", 30302); final InetSocketAddress addr60301 = new InetSocketAddress("localhost", 60301); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index 80626ef2f..25077bbf8 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -79,7 +79,9 @@ public class JsonRpcHttpServiceHostAllowlistTest { private static OkHttpClient client; private static String baseUrl; private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger CHAIN_ID = BigInteger.valueOf(123); private final JsonRpcConfiguration jsonRpcConfig = createJsonRpcConfig(); @@ -100,7 +102,9 @@ public class JsonRpcHttpServiceHostAllowlistTest { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 0fb55fdf3..eb23b054d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -100,7 +100,9 @@ public class JsonRpcHttpServiceLoginTest { protected static OkHttpClient client; protected static String baseUrl; protected static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - protected static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + protected static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + protected static final String CLIENT_VERSION = "0.1.0"; + protected static final String CLIENT_COMMIT = "12345678"; protected static final BigInteger CHAIN_ID = BigInteger.valueOf(123); protected static P2PNetwork peerDiscoveryMock; protected static BlockchainQueries blockchainQueries; @@ -131,7 +133,9 @@ public class JsonRpcHttpServiceLoginTest { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, genesisConfigOptions, peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java index 8323f61b2..f35893490 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java @@ -94,7 +94,9 @@ public class JsonRpcHttpServiceRpcApisTest { private JsonRpcHttpService service; private static String baseUrl; private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger NETWORK_ID = BigInteger.valueOf(123); private JsonRpcConfiguration configuration; private static final List netServices = @@ -202,7 +204,9 @@ public class JsonRpcHttpServiceRpcApisTest { final Map rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, NETWORK_ID, new StubGenesisConfigOptions(), mock(P2PNetwork.class), @@ -310,7 +314,9 @@ public class JsonRpcHttpServiceRpcApisTest { final Map rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, NETWORK_ID, new StubGenesisConfigOptions(), p2pNetwork, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java index bb5cb68a2..52f2ee050 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTest.java @@ -202,7 +202,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1127,7 +1127,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1143,7 +1143,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { final JsonObject json = new JsonObject(resp.body().string()); testHelper.assertValidJsonRpcResult(json, id); final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1175,7 +1175,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, null); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1197,7 +1197,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1218,7 +1218,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1242,7 +1242,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1268,7 +1268,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1289,7 +1289,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { testHelper.assertValidJsonRpcResult(json, id); // Check result final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1353,7 +1353,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { final JsonObject json = new JsonObject(resp.body().string()); testHelper.assertValidJsonRpcResult(json, id); final String result = json.getString("result"); - assertThat(result).isEqualTo(CLIENT_VERSION); + assertThat(result).isEqualTo(CLIENT_NODE_NAME); } } @@ -1485,7 +1485,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { // Check result web3_clientVersion final JsonObject jsonClientVersion = responses.get(clientVersionRequestId); testHelper.assertValidJsonRpcResult(jsonClientVersion, clientVersionRequestId); - assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_VERSION); + assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_NODE_NAME); // Check result unknown method final JsonObject jsonError = responses.get(brokenRequestId); @@ -1540,7 +1540,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { // Check result web3_clientVersion final JsonObject jsonClientVersion = responses.get(clientVersionRequestId); testHelper.assertValidJsonRpcResult(jsonClientVersion, clientVersionRequestId); - assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_VERSION); + assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_NODE_NAME); // Check invalid request final JsonObject jsonError = responses.get(invalidId); @@ -1605,7 +1605,7 @@ public class JsonRpcHttpServiceTest extends JsonRpcHttpServiceTestBase { // Check result web3_clientVersion final JsonObject jsonClientVersion = responses.get(clientVersionRequestId); testHelper.assertValidJsonRpcResult(jsonClientVersion, clientVersionRequestId); - assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_VERSION); + assertThat(jsonClientVersion.getString("result")).isEqualTo(CLIENT_NODE_NAME); // Check result net_version final JsonObject jsonNetVersion = responses.get(netVersionRequestId); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index a2a856333..5e5dc36bb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -78,7 +78,9 @@ public class JsonRpcHttpServiceTestBase { protected static OkHttpClient client; protected static String baseUrl; protected static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - protected static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + protected static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + protected static final String CLIENT_VERSION = "0.1.0"; + protected static final String CLIENT_COMMIT = "12345678"; protected static final BigInteger CHAIN_ID = BigInteger.valueOf(123); protected static P2PNetwork peerDiscoveryMock; protected static EthPeers ethPeersMock; @@ -108,7 +110,9 @@ public class JsonRpcHttpServiceTestBase { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index 1d3a3a087..5cf13a457 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -85,7 +85,9 @@ public class JsonRpcHttpServiceTlsClientAuthTest { protected static final Vertx vertx = Vertx.vertx(); private static final String JSON_HEADER = "application/json; charset=utf-8"; - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger CHAIN_ID = BigInteger.valueOf(123); private static final NatService natService = new NatService(Optional.empty()); @@ -114,7 +116,9 @@ public class JsonRpcHttpServiceTlsClientAuthTest { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index 684f843d2..c2661141a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -75,7 +75,9 @@ class JsonRpcHttpServiceTlsMisconfigurationTest { protected static final Vertx vertx = Vertx.vertx(); - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger CHAIN_ID = BigInteger.valueOf(123); private static final NatService natService = new NatService(Optional.empty()); private final SelfSignedP12Certificate besuCertificate = SelfSignedP12Certificate.create(); @@ -102,7 +104,9 @@ class JsonRpcHttpServiceTlsMisconfigurationTest { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index b6d7fa67f..c0846ed9f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -81,7 +81,9 @@ public class JsonRpcHttpServiceTlsTest { protected static final Vertx vertx = Vertx.vertx(); private static final String JSON_HEADER = "application/json; charset=utf-8"; - private static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; private static final BigInteger CHAIN_ID = BigInteger.valueOf(123); private static final NatService natService = new NatService(Optional.empty()); private JsonRpcHttpService service; @@ -103,7 +105,9 @@ public class JsonRpcHttpServiceTlsTest { rpcMethods = new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, new StubGenesisConfigOptions(), peerDiscoveryMock, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index 5d6aba769..e42828644 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -328,7 +328,7 @@ public class EthGasPriceTest { } when(blockchain.getChainHeadBlock()).thenReturn(blocksByNumber.get(chainHeadBlockNumber)); - if (chainHeadBlockNumber > 1) { + if (chainHeadBlockNumber > 0) { when(blockchain.getBlockByNumber(anyLong())) .thenAnswer( invocation -> Optional.of(blocksByNumber.get(invocation.getArgument(0, Long.class)))); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java index 02d526107..886c8a1d0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthMaxPriorityFeePerGasTest.java @@ -15,29 +15,43 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.verify; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; 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.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.feemarket.CancunFeeMarket; +import org.hyperledger.besu.evm.log.LogsBloomFilter; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.List; import java.util.Optional; -import java.util.stream.Stream; +import java.util.stream.IntStream; +import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; -import org.mockito.internal.verification.VerificationModeFactory; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -45,13 +59,20 @@ public class EthMaxPriorityFeePerGasTest { private static final String JSON_RPC_VERSION = "2.0"; private static final String ETH_METHOD = RpcMethod.ETH_GET_MAX_PRIORITY_FEE_PER_GAS.getMethodName(); - private EthMaxPriorityFeePerGas method; + private static final Wei DEFAULT_MIN_PRIORITY_FEE_PER_GAS = Wei.ZERO; + private static final long DEFAULT_BLOCK_GAS_LIMIT = 100_000; + private static final long DEFAULT_BLOCK_GAS_USED = 21_000; + private static final Wei DEFAULT_BASE_FEE = Wei.of(100_000); - @Mock private BlockchainQueries blockchainQueries; - @Mock private MiningCoordinator miningCoordinator; + private EthMaxPriorityFeePerGas method; + @Mock private ProtocolSchedule protocolSchedule; + @Mock private Blockchain blockchain; + private MiningParameters miningParameters; @BeforeEach public void setUp() { + miningParameters = + MiningParameters.newDefault().setMinPriorityFeePerGas(DEFAULT_MIN_PRIORITY_FEE_PER_GAS); method = createEthMaxPriorityFeePerGasMethod(); } @@ -63,71 +84,156 @@ public class EthMaxPriorityFeePerGasTest { @Test public void whenNoTransactionsExistReturnMinPriorityFeePerGasPrice() { final JsonRpcRequestContext request = requestWithParams(); - final String expectedWei = Wei.ONE.toShortHexString(); + final Wei expectedWei = Wei.ONE; + miningParameters.setMinPriorityFeePerGas(expectedWei); final JsonRpcResponse expectedResponse = - new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei); - when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE); + new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString()); - mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty()); + mockBlockchain(10, 0); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); - verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas(); - } - - @ParameterizedTest - @MethodSource("minPriorityFeePerGasValues") - public void whenNoTransactionsExistReturnMinPriorityFeePerGasPriceExist( - final Wei minPriorityFeePerGasValue) { - final JsonRpcRequestContext request = requestWithParams(); - final String expectedWei = minPriorityFeePerGasValue.toShortHexString(); - final JsonRpcResponse expectedResponse = - new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei); - when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(minPriorityFeePerGasValue); - - mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty()); - final JsonRpcResponse actualResponse = method.response(request); - assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); - verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas(); } @Test - public void whenNoTransactionsExistReturnNullMinPriorityFeePerGasPriceExist() { + public void whenTransactionsExistReturnMedianMaxPriorityFeePerGasPrice() { final JsonRpcRequestContext request = requestWithParams(); + final Wei expectedWei = Wei.of(51_000); // max priority fee per gas prices are 1000-100000 wei. final JsonRpcResponse expectedResponse = - new JsonRpcSuccessResponse(request.getRequest().getId(), null); - when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(null); + new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString()); + + mockBlockchain(100, 1); - mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty()); final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); - verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas(); } @Test - public void whenTransactionsExistReturnMaxPriorityFeePerGasPrice() { + public void returnMinPriorityFeePerGasWhenMedianValueIsLower() { final JsonRpcRequestContext request = requestWithParams(); - final String expectedWei = Wei.of(2000000000).toShortHexString(); + final Wei expectedWei = Wei.of(100_000); + miningParameters.setMinPriorityFeePerGas(expectedWei); + + mockBlockchain(100, 1); + + // median value is 51000 wei, that is lower than the value this node is willing to accept, + // so the configured min priority fee per gas is returned. final JsonRpcResponse expectedResponse = - new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei); - mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.of(Wei.of(2000000000))); + new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString()); + final JsonRpcResponse actualResponse = method.response(request); assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); - verify(miningCoordinator, VerificationModeFactory.times(0)).getMinPriorityFeePerGas(); } - private static Stream minPriorityFeePerGasValues() { - return Stream.of(Arguments.of(Wei.ONE), Arguments.of(Wei.ZERO)); - } + @Test + public void atGenesisReturnMinPriorityFeePerGas() { + final JsonRpcRequestContext request = requestWithParams(); + final Wei expectedWei = Wei.ONE; + miningParameters.setMinPriorityFeePerGas(expectedWei); + final JsonRpcResponse expectedResponse = + new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString()); - private void mockBlockchainQueriesMaxPriorityFeePerGasPrice(final Optional result) { - when(blockchainQueries.gasPriorityFee()).thenReturn(result); + mockBlockchain(0, 0); + final JsonRpcResponse actualResponse = method.response(request); + assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse); } private JsonRpcRequestContext requestWithParams(final Object... params) { return new JsonRpcRequestContext(new JsonRpcRequest(JSON_RPC_VERSION, ETH_METHOD, params)); } + private void mockBlockchain(final long chainHeadBlockNumber, final int txsNum) { + final var genesisBaseFee = DEFAULT_BASE_FEE; + final var blocksByNumber = new HashMap(); + + final var genesisBlock = createFakeBlock(0, 0, genesisBaseFee); + blocksByNumber.put(0L, genesisBlock); + + final var baseFeeMarket = new CancunFeeMarket(0, Optional.empty()); + + var baseFee = genesisBaseFee; + for (long i = 1; i <= chainHeadBlockNumber; i++) { + final var parentHeader = blocksByNumber.get(i - 1).getHeader(); + baseFee = + baseFeeMarket.computeBaseFee( + i, + parentHeader.getBaseFee().get(), + parentHeader.getGasUsed(), + parentHeader.getGasLimit()); + blocksByNumber.put(i, createFakeBlock(i, txsNum, baseFee)); + } + + when(blockchain.getChainHeadBlock()).thenReturn(blocksByNumber.get(chainHeadBlockNumber)); + if (chainHeadBlockNumber > 0) { + when(blockchain.getBlockByNumber(anyLong())) + .thenAnswer( + invocation -> Optional.of(blocksByNumber.get(invocation.getArgument(0, Long.class)))); + } + lenient() + .when(blockchain.getChainHeadHeader()) + .thenReturn(blocksByNumber.get(chainHeadBlockNumber).getHeader()); + } + + private Block createFakeBlock(final long height, final int txsNum, final Wei baseFee) { + return createFakeBlock( + height, txsNum, baseFee, DEFAULT_BLOCK_GAS_LIMIT, DEFAULT_BLOCK_GAS_USED * txsNum); + } + + private Block createFakeBlock( + final long height, + final int txsNum, + final Wei baseFee, + final long gasLimit, + final long gasUsed) { + return new Block( + new BlockHeader( + Hash.EMPTY, + Hash.EMPTY_TRIE_HASH, + Address.ZERO, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY_TRIE_HASH, + LogsBloomFilter.builder().build(), + Difficulty.ONE, + height, + gasLimit, + gasUsed, + 0, + Bytes.EMPTY, + baseFee, + Hash.EMPTY, + 0, + null, + null, + null, + null, + null, + null), + new BlockBody( + IntStream.range(0, txsNum) + .mapToObj( + i -> + new Transaction.Builder() + .chainId(BigInteger.ONE) + .type(TransactionType.EIP1559) + .nonce(i) + .maxFeePerGas(Wei.of(height * 10_000L)) + .maxPriorityFeePerGas(Wei.of(height * 1_000L)) + .gasLimit(gasUsed) + .value(Wei.ZERO) + .build()) + .toList(), + List.of())); + } + private EthMaxPriorityFeePerGas createEthMaxPriorityFeePerGasMethod() { - return new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator); + return new EthMaxPriorityFeePerGas( + new BlockchainQueries( + protocolSchedule, + blockchain, + null, + Optional.empty(), + Optional.empty(), + ImmutableApiConfiguration.builder().build(), + miningParameters)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java new file mode 100644 index 000000000..1aa0def7e --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetClientVersionV1Test.java @@ -0,0 +1,72 @@ +/* + * 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.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.ProtocolContext; +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.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetClientVersionResultV1; + +import io.vertx.core.Vertx; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +class EngineGetClientVersionV1Test { + + private static final String ENGINE_CLIENT_CODE = "BU"; + private static final String ENGINE_CLIENT_NAME = "Besu"; + + private static final String CLIENT_VERSION = "v25.6.7-dev-abcdef12"; + private static final String COMMIT = "abcdef12"; + + private EngineGetClientVersionV1 getClientVersion; + + @BeforeEach + void before() { + getClientVersion = + new EngineGetClientVersionV1( + Mockito.mock(Vertx.class), + Mockito.mock(ProtocolContext.class), + Mockito.mock(EngineCallListener.class), + CLIENT_VERSION, + COMMIT); + } + + @Test + void testGetName() { + assertThat(getClientVersion.getName()).isEqualTo("engine_getClientVersionV1"); + } + + @Test + void testSyncResponse() { + JsonRpcRequestContext request = new JsonRpcRequestContext(new JsonRpcRequest("v", "m", null)); + JsonRpcResponse actualResult = getClientVersion.syncResponse(request); + + assertThat(actualResult).isInstanceOf(JsonRpcSuccessResponse.class); + JsonRpcSuccessResponse successResponse = (JsonRpcSuccessResponse) actualResult; + assertThat(successResponse.getResult()).isInstanceOf(EngineGetClientVersionResultV1.class); + EngineGetClientVersionResultV1 actualEngineGetClientVersionResultV1 = + (EngineGetClientVersionResultV1) successResponse.getResult(); + assertThat(actualEngineGetClientVersionResultV1.getName()).isEqualTo(ENGINE_CLIENT_NAME); + assertThat(actualEngineGetClientVersionResultV1.getCode()).isEqualTo(ENGINE_CLIENT_CODE); + assertThat(actualEngineGetClientVersionResultV1.getVersion()).isEqualTo(CLIENT_VERSION); + assertThat(actualEngineGetClientVersionResultV1.getCommit()).isEqualTo(COMMIT); + } +} diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 75927c451..342941d0e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -115,7 +115,9 @@ public class WebSocketServiceLoginTest { protected static OkHttpClient client; protected static String baseUrl; protected static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - protected static final String CLIENT_VERSION = "TestClientVersion/0.1.0"; + protected static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + protected static final String CLIENT_VERSION = "0.1.0"; + protected static final String CLIENT_COMMIT = "12345678"; protected static final BigInteger CHAIN_ID = BigInteger.valueOf(123); protected static P2PNetwork peerDiscoveryMock; protected static BlockchainQueries blockchainQueries; @@ -167,7 +169,9 @@ public class WebSocketServiceLoginTest { spy( new JsonRpcMethodsFactory() .methods( + CLIENT_NODE_NAME, CLIENT_VERSION, + CLIENT_COMMIT, CHAIN_ID, genesisConfigOptions, peerDiscoveryMock, diff --git a/ethereum/blockcreation/build.gradle b/ethereum/blockcreation/build.gradle index 5f426fd93..753cc12d1 100644 --- a/ethereum/blockcreation/build.gradle +++ b/ethereum/blockcreation/build.gradle @@ -7,7 +7,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 8e2f0ef6c..06c0eab41 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } from(sourceSets.testSupport.output) diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index b51088f4c..677783dfd 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/ethstats/build.gradle b/ethereum/ethstats/build.gradle index 2097f0f1b..8f10b73b3 100644 --- a/ethereum/ethstats/build.gradle +++ b/ethereum/ethstats/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index d9ddafb0c..1b96faf8b 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -29,7 +29,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/mock-p2p/build.gradle b/ethereum/mock-p2p/build.gradle index 373e25be3..a548d0cde 100644 --- a/ethereum/mock-p2p/build.gradle +++ b/ethereum/mock-p2p/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 2d0331503..971504a25 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/permissioning/build.gradle b/ethereum/permissioning/build.gradle index eaf36c8fd..f404d70ed 100644 --- a/ethereum/permissioning/build.gradle +++ b/ethereum/permissioning/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/retesteth/build.gradle b/ethereum/retesteth/build.gradle index 10b978b15..2fe2def43 100644 --- a/ethereum/retesteth/build.gradle +++ b/ethereum/retesteth/build.gradle @@ -20,7 +20,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/rlp/build.gradle b/ethereum/rlp/build.gradle index 9967669c6..a977de5f8 100644 --- a/ethereum/rlp/build.gradle +++ b/ethereum/rlp/build.gradle @@ -23,6 +23,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.internal.rlp' ) } diff --git a/ethereum/stratum/build.gradle b/ethereum/stratum/build.gradle index 5c7dfaed2..83de6a8a5 100644 --- a/ethereum/stratum/build.gradle +++ b/ethereum/stratum/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/trie/build.gradle b/ethereum/trie/build.gradle index e8ce5cb9b..080b9e8f5 100644 --- a/ethereum/trie/build.gradle +++ b/ethereum/trie/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/ethereum/verkletrie/build.gradle b/ethereum/verkletrie/build.gradle index 166b02efe..00c7016fb 100644 --- a/ethereum/verkletrie/build.gradle +++ b/ethereum/verkletrie/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/evm/build.gradle b/evm/build.gradle index 142cd63bc..445408bb2 100644 --- a/evm/build.gradle +++ b/evm/build.gradle @@ -25,6 +25,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.evm' ) } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java index e44c0e7f9..7b58e956f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java @@ -95,6 +95,11 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { @Override public OperationResult execute(final MessageFrame frame, final EVM evm) { + Code callingCode = frame.getCode(); + if (callingCode.getEofVersion() == 0) { + return InvalidOperation.INVALID_RESULT; + } + final Bytes toBytes = frame.getStackItem(STACK_TO).trimLeadingZeros(); final Wei value = value(frame); final boolean zeroValue = value.isZero(); @@ -141,7 +146,7 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { frame.clearReturnData(); // delegate calls to prior EOF versions are prohibited - if (isDelegate() && frame.getCode().getEofVersion() != code.getEofVersion()) { + if (isDelegate() && callingCode.getEofVersion() != code.getEofVersion()) { return softFailure(frame, cost); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCallOperation.java index 5914f0e96..7fc41ac85 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtCallOperation.java @@ -24,6 +24,9 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; /** The Call operation. */ public class ExtCallOperation extends AbstractExtCallOperation { + /** The constant OPCODE. */ + public static final int OPCODE = 0xF8; + static final int STACK_VALUE = 3; /** @@ -32,7 +35,7 @@ public class ExtCallOperation extends AbstractExtCallOperation { * @param gasCalculator the gas calculator */ public ExtCallOperation(final GasCalculator gasCalculator) { - super(0xF8, "EXTCALL", 4, 1, gasCalculator); + super(OPCODE, "EXTCALL", 4, 1, gasCalculator); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperation.java index db851ee5a..49b0a2a54 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperation.java @@ -24,13 +24,16 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; /** The Delegate call operation. */ public class ExtDelegateCallOperation extends AbstractExtCallOperation { + /** The constant OPCODE. */ + public static final int OPCODE = 0xF9; + /** * Instantiates a new Delegate call operation. * * @param gasCalculator the gas calculator */ public ExtDelegateCallOperation(final GasCalculator gasCalculator) { - super(0xF9, "EXTDELEGATECALL", 3, 1, gasCalculator); + super(OPCODE, "EXTDELEGATECALL", 3, 1, gasCalculator); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperation.java index ef3dc042d..741321377 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperation.java @@ -24,13 +24,16 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; /** The Static call operation. */ public class ExtStaticCallOperation extends AbstractExtCallOperation { + /** The constant OPCODE. */ + public static final int OPCODE = 0xFB; + /** * Instantiates a new Static call operation. * * @param gasCalculator the gas calculator */ public ExtStaticCallOperation(final GasCalculator gasCalculator) { - super(0xFB, "EXTSTATICCALL", 3, 1, gasCalculator); + super(OPCODE, "EXTSTATICCALL", 3, 1, gasCalculator); } @Override diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java index c43893a54..93b101150 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java @@ -45,6 +45,8 @@ public class ExtCallOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + public static final Code LEGACY_CODE = + EOF_EVM.getCodeUncached(Bytes.of(ExtCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000")); public static final Code INVALID_EOF = @@ -118,6 +120,7 @@ public class ExtCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(parentGas) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(Bytes.EMPTY) .pushStackItem(Bytes.EMPTY) @@ -208,6 +211,7 @@ public class ExtCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(parentGas) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(valueSent) .pushStackItem(Bytes.EMPTY) @@ -243,6 +247,7 @@ public class ExtCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(400000) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(Bytes.EMPTY) .pushStackItem(Bytes.EMPTY) @@ -273,4 +278,33 @@ public class ExtCallOperationTest { assertThat(parentFrame.getStackItem(0)) .isEqualTo(AbstractExtCallOperation.EOF1_EXCEPTION_STACK_ITEM); } + + @Test + void legacyTest() { + final ExtCallOperation operation = new ExtCallOperation(new PragueEOFGasCalculator()); + + final var messageFrame = + new TestMessageFrameBuilder() + .initialGas(400000) + .code(LEGACY_CODE) + .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(CONTRACT_ADDRESS) + .worldUpdater(worldUpdater) + .build(); + messageFrame.warmUpAddress(CONTRACT_ADDRESS); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash()); + when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes()); + when(worldUpdater.get(any())).thenReturn(account); + when(worldUpdater.getAccount(any())).thenReturn(account); + when(worldUpdater.updater()).thenReturn(worldUpdater); + + var result = operation.execute(messageFrame, EOF_EVM); + + assertThat(result.getGasCost()).isZero(); + assertThat(result.getHaltReason()).isEqualTo(ExceptionalHaltReason.INVALID_OPERATION); + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java index e1881892d..62a10dcc2 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java @@ -46,6 +46,8 @@ public class ExtDelegateCallOperationTest { private final MutableAccount account = mock(MutableAccount.class); // private final MutableAccount targetAccount = mock(MutableAccount.class); private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + public static final Code LEGACY_CODE = + EOF_EVM.getCodeUncached(Bytes.of(ExtDelegateCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000")); public static final Code SIMPLE_LEGACY = EOF_EVM.getCodeUncached(Bytes.fromHexString("0x00")); @@ -229,6 +231,7 @@ public class ExtDelegateCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(400000) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(Bytes.EMPTY) .pushStackItem(Bytes.EMPTY) @@ -258,4 +261,34 @@ public class ExtDelegateCallOperationTest { assertThat(parentFrame.getStackItem(0)) .isEqualTo(AbstractExtCallOperation.EOF1_EXCEPTION_STACK_ITEM); } + + @Test + void legacyTest() { + final ExtDelegateCallOperation operation = + new ExtDelegateCallOperation(new PragueEOFGasCalculator()); + + final var messageFrame = + new TestMessageFrameBuilder() + .initialGas(400000) + .code(LEGACY_CODE) + .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(CONTRACT_ADDRESS) + .worldUpdater(worldUpdater) + .build(); + messageFrame.warmUpAddress(CONTRACT_ADDRESS); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash()); + when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes()); + when(worldUpdater.get(any())).thenReturn(account); + when(worldUpdater.getAccount(any())).thenReturn(account); + when(worldUpdater.updater()).thenReturn(worldUpdater); + + var result = operation.execute(messageFrame, EOF_EVM); + + assertThat(result.getGasCost()).isZero(); + assertThat(result.getHaltReason()).isEqualTo(ExceptionalHaltReason.INVALID_OPERATION); + } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java index 90f2d3008..ed306e89c 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java @@ -45,6 +45,8 @@ public class ExtStaticCallOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + public static final Code LEGACY_CODE = + EOF_EVM.getCodeUncached(Bytes.of(ExtStaticCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = EOF_EVM.getCodeUncached(Bytes.fromHexString("0xEF00010100040200010001040000000080000000")); public static final Code INVALID_EOF = @@ -119,6 +121,7 @@ public class ExtStaticCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(parentGas) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(Bytes.EMPTY) .pushStackItem(Bytes.EMPTY) @@ -154,6 +157,7 @@ public class ExtStaticCallOperationTest { final var messageFrame = new TestMessageFrameBuilder() .initialGas(400000) + .code(SIMPLE_EOF) .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning .pushStackItem(Bytes.EMPTY) .pushStackItem(Bytes.EMPTY) @@ -183,4 +187,34 @@ public class ExtStaticCallOperationTest { assertThat(parentFrame.getStackItem(0)) .isEqualTo(AbstractExtCallOperation.EOF1_EXCEPTION_STACK_ITEM); } + + @Test + void legacyTest() { + final ExtStaticCallOperation operation = + new ExtStaticCallOperation(new PragueEOFGasCalculator()); + + final var messageFrame = + new TestMessageFrameBuilder() + .initialGas(400000) + .code(LEGACY_CODE) + .pushStackItem(CONTRACT_ADDRESS) // canary for non-returning + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(Bytes.EMPTY) + .pushStackItem(CONTRACT_ADDRESS) + .worldUpdater(worldUpdater) + .build(); + messageFrame.warmUpAddress(CONTRACT_ADDRESS); + when(account.getBalance()).thenReturn(Wei.ZERO); + when(account.getCodeHash()).thenReturn(SIMPLE_EOF.getCodeHash()); + when(account.getCode()).thenReturn(SIMPLE_EOF.getBytes()); + when(worldUpdater.get(any())).thenReturn(account); + when(worldUpdater.getAccount(any())).thenReturn(account); + when(worldUpdater.updater()).thenReturn(worldUpdater); + + var result = operation.execute(messageFrame, EOF_EVM); + + assertThat(result.getGasCost()).isZero(); + assertThat(result.getHaltReason()).isEqualTo(ExceptionalHaltReason.INVALID_OPERATION); + } } diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b745b13f6..62efb721a 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -546,19 +546,6 @@ - - - - - - - - - - - - - diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 587b464ee..f7599a849 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -41,8 +41,6 @@ dependencyManagement { dependency 'org.hyperledger.besu:besu-errorprone-checks:1.0.0' - dependency 'com.gitlab.javafuzz:core:1.26' - dependency 'com.google.guava:guava:33.0.0-jre' dependency 'com.graphql-java:graphql-java:21.5' diff --git a/metrics/core/build.gradle b/metrics/core/build.gradle index bc92cb6b5..1438a198a 100644 --- a/metrics/core/build.gradle +++ b/metrics/core/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/metrics/rocksdb/build.gradle b/metrics/rocksdb/build.gradle index 292909565..d46488daf 100644 --- a/metrics/rocksdb/build.gradle +++ b/metrics/rocksdb/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/nat/build.gradle b/nat/build.gradle index ec2fd3a3f..b0a859717 100644 --- a/nat/build.gradle +++ b/nat/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/pki/build.gradle b/pki/build.gradle index cb6aaf8b8..15f1e8c7d 100644 --- a/pki/build.gradle +++ b/pki/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 731cba9e2..548d43e91 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -22,6 +22,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.plugin.api' ) } diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index 6af582bf3..e5ca78250 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -20,7 +20,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/services/kvstore/build.gradle b/services/kvstore/build.gradle index 0415f6702..5f379b60a 100644 --- a/services/kvstore/build.gradle +++ b/services/kvstore/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/services/pipeline/build.gradle b/services/pipeline/build.gradle index b86edbf34..af9f065fe 100644 --- a/services/pipeline/build.gradle +++ b/services/pipeline/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/services/tasks/build.gradle b/services/tasks/build.gradle index 5cfa2411f..c584c6987 100644 --- a/services/tasks/build.gradle +++ b/services/tasks/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/testfuzz/build.gradle b/testfuzz/build.gradle index 83bf621ac..3346f3e56 100644 --- a/testfuzz/build.gradle +++ b/testfuzz/build.gradle @@ -24,7 +24,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } @@ -38,7 +39,6 @@ dependencies { implementation project(':util') implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'com.gitlab.javafuzz:core' implementation 'com.google.guava:guava' implementation 'info.picocli:picocli' implementation 'io.tmio:tuweni-bytes' @@ -71,6 +71,15 @@ tasks.register("runFuzzer", JavaExec) { } } +// Adds guidance to the fuzzer but with a 90% performance drop. +tasks.register("fuzzGuided") { + doLast { + runFuzzer.args += "--guidance-regexp=org/(hyperledger/besu|apache/tuweni)" + runFuzzer.args += "--new-corpus-dir=${corpusDir}/.." + } + finalizedBy("runFuzzer") +} + // This fuzzes besu as an external client. Besu fuzzing as a local client is enabled by default. tasks.register("fuzzBesu") { dependsOn(":installDist") @@ -110,7 +119,7 @@ tasks.register("fuzzNethermind") { tasks.register("fuzzReth") { doLast { - runFuzzer.args += "--client=revm=revme bytecode" + runFuzzer.args += "--client=revm=revme bytecode --eof-runtime" } finalizedBy("runFuzzer") } diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java index c2b518f18..27c4547d2 100644 --- a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.referencetests.EOFTestCaseSpec; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.testfuzz.javafuzz.Fuzzer; import java.io.File; import java.io.FileOutputStream; @@ -48,7 +49,6 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.gitlab.javafuzz.core.AbstractFuzzTarget; import com.google.common.base.Stopwatch; import org.apache.tuweni.bytes.Bytes; import picocli.CommandLine; @@ -61,7 +61,7 @@ import picocli.CommandLine.Option; description = "Fuzzes EOF container parsing and validation", mixinStandardHelpOptions = true, versionProvider = VersionProvider.class) -public class EofContainerSubCommand extends AbstractFuzzTarget implements Runnable { +public class EofContainerSubCommand implements Runnable { static final String COMMAND_NAME = "eof-container"; @@ -100,6 +100,16 @@ public class EofContainerSubCommand extends AbstractFuzzTarget implements Runnab description = "Minimum number of fuzz tests before a time limit fuzz error can occur") private long timeThresholdIterations = 2_000; + @Option( + names = {"--guidance-regexp"}, + description = "Regexp for classes that matter for guidance metric") + private String guidanceRegexp; + + @Option( + names = {"--new-corpus-dir"}, + description = "Directory to write hex versions of guidance added contracts") + private File newCorpusDir = null; + @CommandLine.ParentCommand private final BesuFuzzCommand parentCommand; static final ObjectMapper eofTestMapper = createObjectMapper(); @@ -174,7 +184,13 @@ public class EofContainerSubCommand extends AbstractFuzzTarget implements Runnab System.out.println("Fuzzing client set: " + clients.keySet()); try { - new Fuzzer(this, corpusDir.toString(), this::fuzzStats).start(); + new Fuzzer( + this::parseEOFContainers, + corpusDir.toString(), + this::fuzzStats, + guidanceRegexp, + newCorpusDir) + .start(); } catch (NoSuchAlgorithmException | ClassNotFoundException | InvocationTargetException @@ -212,8 +228,7 @@ public class EofContainerSubCommand extends AbstractFuzzTarget implements Runnab } } - @Override - public void fuzz(final byte[] bytes) { + void parseEOFContainers(final byte[] bytes) { Bytes eofUnderTest = Bytes.wrap(bytes); String eofUnderTestHexString = eofUnderTest.toHexString(); @@ -236,7 +251,7 @@ public class EofContainerSubCommand extends AbstractFuzzTarget implements Runnab "%s: slow validation %d µs%n", client.getName(), elapsedMicros); try { Files.writeString( - Path.of("slow-" + client.getName() + "-" + name + ".hex"), + Path.of("slow-" + name + "-" + client.getName() + ".hex"), eofUnderTestHexString); } catch (IOException e) { throw new RuntimeException(e); diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Corpus.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Corpus.java new file mode 100644 index 000000000..56eba76d3 --- /dev/null +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Corpus.java @@ -0,0 +1,449 @@ +/* + * 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.testfuzz.javafuzz; + +import org.hyperledger.besu.crypto.MessageDigestFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * Ported from ... because + * fields like max input size were not configurable. + */ +@SuppressWarnings("CatchAndPrintStackTrace") +public class Corpus { + private final ArrayList inputs; + private final int maxInputSize; + private static final int[] INTERESTING8 = {-128, -1, 0, 1, 16, 32, 64, 100, 127}; + private static final int[] INTERESTING16 = { + -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767, -128, -1, 0, 1, 16, 32, 64, 100, 127 + }; + private static final int[] INTERESTING32 = { + -2147483648, + -100663046, + -32769, + 32768, + 65535, + 65536, + 100663045, + 2147483647, + -32768, + -129, + 128, + 255, + 256, + 512, + 1000, + 1024, + 4096, + 32767, + -128, + -1, + 0, + 1, + 16, + 32, + 64, + 100, + 127 + }; + private String corpusPath; + private int seedLength; + + /** + * Create a corpus + * + * @param dirs The directory to store the corpus files + */ + public Corpus(final String dirs) { + this.maxInputSize = 0xc001; // 48k+1 + this.corpusPath = null; + this.inputs = new ArrayList<>(); + if (dirs != null) { + String[] arr = dirs.split(",", -1); + for (String s : arr) { + File f = new File(s); + if (!f.exists()) { + f.mkdirs(); + } + if (f.isDirectory()) { + if (this.corpusPath == null) { + this.corpusPath = f.getPath(); + } + this.loadDir(f); + } else { + try { + this.inputs.add(Files.readAllBytes(f.toPath())); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + this.seedLength = this.inputs.size(); + } + + int getLength() { + return this.inputs.size(); + } + + private boolean randBool() { + return ThreadLocalRandom.current().nextBoolean(); + } + + private int rand(final int max) { + return ThreadLocalRandom.current().nextInt(0, max); + } + + private void loadDir(final File dir) { + for (final File f : dir.listFiles()) { + if (f.isFile()) { + try { + this.inputs.add(Files.readAllBytes(f.toPath())); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + byte[] generateInput() throws NoSuchAlgorithmException { + if (this.seedLength != 0) { + this.seedLength--; + return this.inputs.get(this.seedLength); + } + if (this.inputs.isEmpty()) { + byte[] buf = new byte[] {}; + this.putBuffer(buf); + return buf; + } + byte[] buf = this.inputs.get(this.rand(this.inputs.size())); + return this.mutate(buf); + } + + void putBuffer(final byte[] buf) throws NoSuchAlgorithmException { + if (this.inputs.contains(buf)) { + return; + } + + this.inputs.add(buf); + + writeCorpusFile(buf); + } + + private void writeCorpusFile(final byte[] buf) throws NoSuchAlgorithmException { + if (this.corpusPath != null) { + MessageDigest md = MessageDigestFactory.create("SHA-256"); + md.update(buf); + byte[] digest = md.digest(); + String hex = String.format("%064x", new BigInteger(1, digest)); + try (FileOutputStream fos = new FileOutputStream(this.corpusPath + "/" + hex)) { + fos.write(buf); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private String dec2bin(final int dec) { + String bin = Integer.toBinaryString(dec); + String padding = new String(new char[32 - bin.length()]).replace("\0", "0"); + return padding + bin; + } + + private int exp2() { + String bin = dec2bin(this.rand((int) Math.pow(2, 32))); + int count = 0; + for (int i = 0; i < 32; i++) { + if (bin.charAt(i) == '0') { + count++; + } else { + break; + } + } + return count; + } + + int chooseLen(final int n) { + int x = this.rand(100); + if (x < 90) { + return this.rand(Math.min(8, n)) + 1; + } else if (x < 99) { + return this.rand(Math.min(32, n)) + 1; + } else { + return this.rand(n) + 1; + } + } + + static void copy( + final byte[] src, final int srcPos, final byte[] dst, final int dstPos, final int length) { + System.arraycopy(src, srcPos, dst, dstPos, Math.min(length, src.length - srcPos)); + } + + static void copy(final byte[] src, final int srcPos, final byte[] dst, final int dstPos) { + System.arraycopy(src, srcPos, dst, dstPos, Math.min(src.length - srcPos, dst.length - dstPos)); + } + + static byte[] concatZeros(final byte[] a, final int n) { + byte[] c = new byte[a.length + n]; + Arrays.fill(c, (byte) 0); + System.arraycopy(a, 0, c, 0, a.length); + return c; + } + + byte[] mutate(final byte[] buf) { + byte[] res = buf.clone(); + int nm = 1 + this.exp2(); + for (int i = 0; i < nm; i++) { + int x = this.rand(16); + if (x == 0) { + // Remove a range of bytes. + if (res.length <= 1) { + i--; + continue; + } + int pos0 = this.rand(res.length); + int pos1 = pos0 + this.chooseLen(res.length - pos0); + copy(res, pos1, res, pos0, res.length - pos0); + res = Arrays.copyOfRange(res, 0, res.length - (pos1 - pos0)); + } else if (x == 1) { + // Insert a range of random bytes. + int pos = this.rand(res.length + 1); + int n = this.chooseLen(10); + res = concatZeros(res, n); + copy(res, pos, res, pos + n); + for (int k = 0; k < n; k++) { + res[pos + k] = (byte) this.rand(256); + } + } else if (x == 2) { + // Duplicate a range of bytes. + if (res.length <= 1) { + i--; + continue; + } + int src = this.rand(res.length); + int dst = this.rand(res.length); + while (src == dst) { + dst = this.rand(res.length); + } + int n = this.chooseLen(res.length - src); + byte[] tmp = new byte[n]; + Arrays.fill(tmp, (byte) 0); + copy(res, src, tmp, 0); + res = concatZeros(res, n); + copy(res, dst, res, dst + n); + System.arraycopy(tmp, 0, res, dst, n); + } else if (x == 3) { + // Copy a range of bytes. + if (res.length <= 1) { + i--; + continue; + } + int src = this.rand(res.length); + int dst = this.rand(res.length); + while (src == dst) { + dst = this.rand(res.length); + } + int n = this.chooseLen(res.length - src); + copy(res, src + n, res, dst); + } else if (x == 4) { + // Bit flip. Spooky! + if (res.length <= 1) { + i--; + continue; + } + int pos = this.rand(res.length); + res[pos] ^= (byte) (1 << (byte) this.rand(8)); + } else if (x == 5) { + // Set a byte to a random value. + if (res.length <= 1) { + i--; + continue; + } + int pos = this.rand(res.length); + res[pos] ^= (byte) (this.rand(255) + 1); + } else if (x == 6) { + // Swap 2 bytes. + if (res.length <= 1) { + i--; + continue; + } + int src = this.rand(res.length); + int dst = this.rand(res.length); + while (src == dst) { + dst = this.rand(res.length); + } + byte tmp1 = res[src]; + res[src] = res[dst]; + res[dst] = tmp1; + } else if (x == 7) { + // Add/subtract from a byte. + if (res.length == 0) { + i--; + continue; + } + int pos = this.rand(res.length); + int v = this.rand(35) + 1; + if (this.randBool()) { + res[pos] += (byte) v; + } else { + res[pos] -= (byte) v; + } + } else if (x == 8) { + // Add/subtract from a uint16. + i--; + // if (res.length < 2) { + // i--; + // continue; + // } + // int pos = this.rand(res.length - 1); + // int v = this.rand(35) + 1; + // if (this.randBool()) { + // v = 0 - v; + // } + // + // if (this.randBool()) { + // res[pos] = + // } else { + // + // } + + } else if (x == 9) { + i--; + // Add/subtract from a uint32. + } else if (x == 10) { + // Replace a byte with an interesting value. + if (res.length == 0) { + i--; + continue; + } + int pos = this.rand(res.length); + res[pos] = (byte) INTERESTING8[this.rand(INTERESTING8.length)]; + } else if (x == 11) { + // Replace an uint16 with an interesting value. + if (res.length < 2) { + i--; + continue; + } + int pos = this.rand(res.length - 1); + if (this.randBool()) { + res[pos] = (byte) (INTERESTING16[this.rand(INTERESTING16.length)] & 0xFF); + res[pos + 1] = (byte) ((INTERESTING16[this.rand(INTERESTING16.length)] >> 8) & 0xFF); + } else { + res[pos + 1] = (byte) (INTERESTING16[this.rand(INTERESTING16.length)] & 0xFF); + res[pos] = (byte) ((INTERESTING16[this.rand(INTERESTING16.length)] >> 8) & 0xFF); + } + } else if (x == 12) { + // Replace an uint32 with an interesting value. + if (res.length < 4) { + i--; + continue; + } + int pos = this.rand(res.length - 3); + if (this.randBool()) { + res[pos] = (byte) (INTERESTING32[this.rand(INTERESTING32.length)] & 0xFF); + res[pos + 1] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 8) & 0xFF); + res[pos + 2] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 16) & 0xFF); + res[pos + 3] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 24) & 0xFF); + } else { + res[pos + 3] = (byte) (INTERESTING32[this.rand(INTERESTING32.length)] & 0xFF); + res[pos + 2] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 8) & 0xFF); + res[pos + 1] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 16) & 0xFF); + res[pos] = (byte) ((INTERESTING32[this.rand(INTERESTING32.length)] >> 24) & 0xFF); + } + } else if (x == 13) { + // Replace an ascii digit with another digit. + List digits = new ArrayList<>(); + for (int k = 0; k < res.length; k++) { + if (res[k] >= 48 && res[k] <= 57) { + digits.add(k); + } + } + if (digits.isEmpty()) { + i--; + continue; + } + int pos = this.rand(digits.size()); + int was = res[digits.get(pos)]; + int now = was; + while (now == was) { + now = this.rand(10) + 48; + } + res[digits.get(pos)] = (byte) now; + } else if (x == 14) { + // Splice another input. + if (res.length < 4 || this.inputs.size() < 2) { + i--; + continue; + } + byte[] other = this.inputs.get(this.rand(this.inputs.size())); + if (other.length < 4) { + i--; + continue; + } + // Find common prefix and suffix. + int idx0 = 0; + while (idx0 < res.length && idx0 < other.length && res[idx0] == other[idx0]) { + idx0++; + } + int idx1 = 0; + while (idx1 < res.length + && idx1 < other.length + && res[res.length - idx1 - 1] == other[other.length - idx1 - 1]) { + idx1++; + } + int diff = Math.min(res.length - idx0 - idx1, other.length - idx0 - idx1); + if (diff < 4) { + i--; + continue; + } + copy(other, idx0, res, idx0, Math.min(other.length, idx0 + this.rand(diff - 2) + 1) - idx0); + } else if (x == 15) { + // Insert a part of another input. + if (res.length < 4 || this.inputs.size() < 2) { + i--; + continue; + } + byte[] other = this.inputs.get(this.rand(this.inputs.size())); + if (other.length < 4) { + i--; + continue; + } + int pos0 = this.rand(res.length + 1); + int pos1 = this.rand(other.length - 2); + int n = this.chooseLen(other.length - pos1 - 2) + 2; + res = concatZeros(res, n); + copy(res, pos0, res, pos0 + n); + if (n >= 0) System.arraycopy(other, pos1, res, pos0, n); + } + } + + if (res.length > this.maxInputSize) { + res = Arrays.copyOfRange(res, 0, this.maxInputSize); + } + return res; + } +} diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/FuzzTarget.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/FuzzTarget.java new file mode 100644 index 000000000..26f3522e1 --- /dev/null +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/FuzzTarget.java @@ -0,0 +1,31 @@ +/* + * 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.testfuzz.javafuzz; + +/** + * Adapted from ... because + * I wanted it to be a functional interface + */ +@FunctionalInterface +public interface FuzzTarget { + + /** + * The target to fuzz + * + * @param data data proviced by the fuzzer + */ + void fuzz(byte[] data); +} diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/Fuzzer.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Fuzzer.java similarity index 71% rename from testfuzz/src/main/java/org/hyperledger/besu/testfuzz/Fuzzer.java rename to testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Fuzzer.java index e4ebb68cc..f5d7f537a 100644 --- a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/Fuzzer.java +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/Fuzzer.java @@ -12,14 +12,20 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.testfuzz; +package org.hyperledger.besu.testfuzz.javafuzz; + +import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.crypto.MessageDigestFactory; +import java.io.BufferedWriter; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigInteger; @@ -28,9 +34,9 @@ import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import com.gitlab.javafuzz.core.AbstractFuzzTarget; -import com.gitlab.javafuzz.core.Corpus; import org.apache.tuweni.bytes.Bytes; import org.jacoco.core.data.ExecutionData; import org.jacoco.core.data.ExecutionDataReader; @@ -38,13 +44,19 @@ import org.jacoco.core.data.IExecutionDataVisitor; import org.jacoco.core.data.ISessionInfoVisitor; import org.jacoco.core.data.SessionInfo; -/** Ported from javafuzz because JaCoCo APIs changed. */ +/** + * Ported from ... because + * JaCoCo APIs changed. + */ @SuppressWarnings({"java:S106", "CallToPrintStackTrace"}) // we use lots the console, on purpose public class Fuzzer { - private final AbstractFuzzTarget target; + private final FuzzTarget target; private final Corpus corpus; private final Object agent; private final Method getExecutionDataMethod; + private final Pattern guidanceRegexp; + private final File newCorpusDir; private long executionsInSample; private long lastSampleTime; private long totalExecutions; @@ -58,6 +70,8 @@ public class Fuzzer { * @param target The target to fuzz * @param dirs the list of corpus dirs and files, comma separated. * @param fuzzStats additional fuzzing data from the client + * @param guidanceRegexp Regexp of (slash delimited) class names to check for guidance. + * @param newCorpusDir Direcroty to dump hex encoded versions of guidance discovered tests. * @throws ClassNotFoundException If Jacoco RT is not found (because jacocoagent.jar is not * loaded) * @throws NoSuchMethodException If the wrong version of Jacoco is loaded @@ -66,7 +80,11 @@ public class Fuzzer { * @throws NoSuchAlgorithmException If the SHA-256 crypto algo cannot be loaded. */ public Fuzzer( - final AbstractFuzzTarget target, final String dirs, final Supplier fuzzStats) + final FuzzTarget target, + final String dirs, + final Supplier fuzzStats, + final String guidanceRegexp, + final File newCorpusDir) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, @@ -75,6 +93,15 @@ public class Fuzzer { this.target = target; this.corpus = new Corpus(dirs); this.fuzzStats = fuzzStats; + this.newCorpusDir = newCorpusDir; + if (newCorpusDir != null) { + if (newCorpusDir.exists() && newCorpusDir.isFile()) { + throw new IllegalArgumentException("New corpus directory already exists as a file"); + } + newCorpusDir.mkdirs(); + } + this.guidanceRegexp = + guidanceRegexp == null || guidanceRegexp.isBlank() ? null : Pattern.compile(guidanceRegexp); Class c = Class.forName("org.jacoco.agent.rt.RT"); Method getAgentMethod = c.getMethod("getAgent"); this.agent = getAgentMethod.invoke(null); @@ -132,6 +159,11 @@ public class Fuzzer { this.lastSampleTime = System.currentTimeMillis(); Map hitMap = new HashMap<>(); + // preload some values so we don't get false hits in coverage we don't care about. + hitMap.put("org/hyperledger/besu/testfuzz/EofContainerSubCommand", 100); + hitMap.put("org/hyperledger/besu/testfuzz/Fuzzer", 100); + hitMap.put("org/hyperledger/besu/testfuzz/Fuzzer$HitCounter", 100); + hitMap.put("org/hyperledger/besu/testfuzz/InternalClient", 100); while (true) { byte[] buf = this.corpus.generateInput(); @@ -152,19 +184,22 @@ public class Fuzzer { if (newCoverage > this.totalCoverage) { this.totalCoverage = newCoverage; this.corpus.putBuffer(buf); - this.logStats("NEW"); + if (totalExecutions > corpus.getLength()) { + this.logStats("NEW"); + if (newCorpusDir != null) { - // If you want hex strings of new hits, uncomment the following. - // String filename = fileNameForBuffer(buf); - // try (var pw = - // new PrintWriter( - // new BufferedWriter( - // new OutputStreamWriter(new FileOutputStream(filename), UTF_8)))) { - // pw.println(Bytes.wrap(buf).toHexString()); - // System.out.println(filename); - // } catch (IOException e) { - // e.printStackTrace(System.out); - // } + String filename = fileNameForBuffer(buf); + try (var pw = + new PrintWriter( + new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(new File(newCorpusDir, filename)), UTF_8)))) { + pw.println(Bytes.wrap(buf).toHexString()); + } catch (IOException e) { + e.printStackTrace(System.out); + } + } + } } else if ((System.currentTimeMillis() - this.lastSampleTime) > 30000) { this.logStats("PULSE"); } @@ -175,14 +210,17 @@ public class Fuzzer { MessageDigest md = MessageDigestFactory.create(MessageDigestFactory.SHA256_ALG); md.update(buf); byte[] digest = md.digest(); - return String.format("./new-%064x.hex", new BigInteger(1, digest)); + return String.format("new-%064x.hex", new BigInteger(1, digest)); } private long getHitCount(final Map hitMap) throws IllegalAccessException, InvocationTargetException { + if (guidanceRegexp == null) { + return 1; + } byte[] dumpData = (byte[]) this.getExecutionDataMethod.invoke(this.agent, false); ExecutionDataReader edr = new ExecutionDataReader(new ByteArrayInputStream(dumpData)); - HitCounter hc = new HitCounter(hitMap); + HitCounter hc = new HitCounter(hitMap, guidanceRegexp); edr.setExecutionDataVisitor(hc); edr.setSessionInfoVisitor(hc); try { @@ -198,28 +236,35 @@ public class Fuzzer { static class HitCounter implements IExecutionDataVisitor, ISessionInfoVisitor { long hits = 0; Map hitMap; + Pattern guidanceRegexp; - public HitCounter(final Map hitMap) { + public HitCounter(final Map hitMap, final Pattern guidanceRegexp) { this.hitMap = hitMap; + this.guidanceRegexp = guidanceRegexp; } @Override public void visitClassExecution(final ExecutionData executionData) { + String name = executionData.getName(); + Matcher matcher = guidanceRegexp.matcher(name); int hit = 0; + if (!matcher.find()) { + return; + } + if (matcher.start() != 0) { + return; + } for (boolean b : executionData.getProbes()) { - if (executionData.getName().startsWith("org/hyperledger/besu/testfuzz/") - || executionData.getName().startsWith("org/bouncycastle/") - || executionData.getName().startsWith("com/gitlab/javafuzz/")) { - continue; - } if (b) { hit++; } } - String name = executionData.getName(); if (hitMap.containsKey(name)) { - if (hitMap.get(name) < hit) { + int theHits = hitMap.get(name); + if (theHits < hit) { hitMap.put(name, hit); + } else { + hit = theHits; } } else { hitMap.put(name, hit); diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/README.md b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/README.md new file mode 100644 index 000000000..276e404fa --- /dev/null +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/javafuzz/README.md @@ -0,0 +1,14 @@ +## Credits & Acknowledgments + +These classes were ported from [Javafuzz](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/javafuzz/). +Javafuzz is a port of [fuzzitdev/jsfuzz](https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/jsfuzz). + +Which in turn based based on [go-fuzz](https://github.com/dvyukov/go-fuzz) originally developed by [Dmitry Vyukov's](https://twitter.com/dvyukov). +Which is in turn heavily based on [Michal Zalewski](https://twitter.com/lcamtuf) [AFL](http://lcamtuf.coredump.cx/afl/). + +## Changes + +* Increased max binary size to 48k+1 +* ported AbstractFuzzTarget to a functional interface FuzzTarget +* Fixed some incompatibilities with JaCoCo +* Besu style required changes (formatting, final params, etc.) \ No newline at end of file diff --git a/testutil/build.gradle b/testutil/build.gradle index 491c21320..5b4f06e7a 100644 --- a/testutil/build.gradle +++ b/testutil/build.gradle @@ -22,7 +22,8 @@ jar { 'Specification-Title': archiveBaseName, 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion() + 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash ) } } diff --git a/util/build.gradle b/util/build.gradle index 339c1e2c3..28e1d83d4 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -23,6 +23,7 @@ jar { 'Specification-Version': project.version, 'Implementation-Title': archiveBaseName, 'Implementation-Version': calculateVersion(), + 'Commit-Hash': getGitCommitDetails(40).hash, 'Automatic-Module-Name': 'io.consensys.linea-besu.internal.util' ) }