From 72ac7bdbe455f969d2b3fa793cc5556906835cb1 Mon Sep 17 00:00:00 2001 From: Cristiano Aguzzi Date: Wed, 12 Mar 2025 08:41:09 +0100 Subject: [PATCH] [Follow up] Add Transaction Permissioning Hook to PermissioningService Interface (#8365) * fixing the issue of implementing the permission service class in pr when it already exists Signed-off-by: vaidikcode * wiring transaction filtering for Permissioning Plugins * revert modify deprated code for TransactionSmartContractPermissioning * Improve logging for AccountPermissioningController Co-authored-by: Sally MacFarlane Signed-off-by: Cristiano Aguzzi * Improve logging messages for AccountPermissioningController * Allign AccountPermissioningControllerFactoryTest with the latest api Signed-off-by: reluc --------- Signed-off-by: Vaidik Signed-off-by: Sally MacFarlane Signed-off-by: reluc Signed-off-by: Cristiano Aguzzi Co-authored-by: vaidikcode Co-authored-by: Sally MacFarlane Co-authored-by: Justin Florentine --- CHANGELOG.md | 2 + .../plugins/TestPermissioningPlugin.java | 14 +++++ .../plugins/PermissioningPluginTest.java | 61 +++++++++++++++++++ .../org/hyperledger/besu/RunnerBuilder.java | 11 +++- .../services/PermissioningServiceImpl.java | 23 +++++++ ...untLocalConfigPermissioningController.java | 4 +- .../AccountPermissioningController.java | 19 +++++- ...AccountPermissioningControllerFactory.java | 11 +++- ...untPermissioningControllerFactoryTest.java | 34 ++++++++--- .../AccountPermissioningControllerTest.java | 5 +- plugin-api/build.gradle | 2 +- .../plugin/services/PermissioningService.java | 8 +++ .../TransactionPermissioningProvider.java | 43 +++++++++++++ 13 files changed, 219 insertions(+), 18 deletions(-) create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f091553c8..28862a6de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased + ### Breaking Changes - k8s (KUBERNETES) Nat method is removed. Use docker or none instead. [#8289](https://github.com/hyperledger/besu/pull/8289) - Change `Invalid block, unable to parse RLP` RPC error message to `Invalid block param (block not found)` [#8328](https://github.com/hyperledger/besu/pull/8328) @@ -27,6 +28,7 @@ - Update Holesky and Sepolia deposit contract addresses [#8346](https://github.com/hyperledger/besu/pull/8346) #### Plugins - Allow plugins to propose transactions during block creation [#8268](https://github.com/hyperledger/besu/pull/8268) +- Add support for transaction permissioning rules in Plugin API [#8365](https://github.com/hyperledger/besu/pull/8365) #### Parallelization - Improve conflict detection by considering slots to reduce false positives [#7923](https://github.com/hyperledger/besu/pull/7923) #### Dependencies diff --git a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestPermissioningPlugin.java b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestPermissioningPlugin.java index c2503ed81..6d59f2dfd 100644 --- a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestPermissioningPlugin.java +++ b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestPermissioningPlugin.java @@ -75,6 +75,20 @@ public class TestPermissioningPlugin implements BesuPlugin { } return true; }); + + service.registerTransactionPermissioningProvider( + transaction -> { + long configuredGasLimitThreshold = 22000L; + long gasLimit = transaction.getGasLimit(); + LOG.info( + "Transaction gas limit: {} | Configured threshold: {} ", + gasLimit, + configuredGasLimitThreshold); + // Sample logic to testing. If the gas limit is exactly 21000 (intrinsic gas limit) + // we let the transaction pass. This is helpful for not making additional configuration + // options in PermssioningPluginTest + return gasLimit > configuredGasLimitThreshold || gasLimit == 21000; + }); } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PermissioningPluginTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PermissioningPluginTest.java index c469802fc..6c3a8661c 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PermissioningPluginTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/PermissioningPluginTest.java @@ -14,18 +14,27 @@ */ package org.hyperledger.besu.tests.acceptance.plugins; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import org.hyperledger.besu.crypto.SECP256K1; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder; +import org.hyperledger.besu.tests.acceptance.dsl.transaction.SignUtil; import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransaction; +import java.math.BigInteger; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.web3j.crypto.RawTransaction; +import org.web3j.utils.Convert; +import org.web3j.utils.Numeric; public class PermissioningPluginTest extends AcceptanceTestBase { private BesuNode minerNode; @@ -34,6 +43,8 @@ public class PermissioningPluginTest extends AcceptanceTestBase { private BesuNode bobNode; private BesuNode charlieNode; + private static final long GAS_LIMIT_THRESHOLD = 22000L; + @BeforeEach public void setUp() throws Exception { minerNode = besu.create(createNodeBuilder().name("miner").build()); @@ -96,4 +107,54 @@ public class PermissioningPluginTest extends AcceptanceTestBase { charlieNode.verify(txPoolConditions.notInTransactionPool(txHash)); minerNode.verify(txPoolConditions.inTransactionPool(txHash)); } + + @Test + public void allowFilteredByGasLimit() { + + final Account sender = accounts.getPrimaryBenefactor(); + final Account recipient = accounts.createAccount("account-two"); + final BigInteger GAS_LIMIT = BigInteger.valueOf(GAS_LIMIT_THRESHOLD + 100); + final BigInteger GAS_PRICE = BigInteger.valueOf(1000); + final Amount amount = Amount.wei(BigInteger.valueOf(29)); + + final RawTransaction tx = + RawTransaction.createEtherTransaction( + sender.getNextNonce(), + GAS_PRICE, + GAS_LIMIT, + recipient.getAddress(), + Convert.toWei(amount.getValue(), amount.getUnit()).toBigIntegerExact()); + + final String rawSigned = + Numeric.toHexString( + SignUtil.signTransaction(tx, sender, new SECP256K1(), Optional.empty())); + final String txHash = aliceNode.execute(ethTransactions.sendRawTransaction(rawSigned)); + + aliceNode.verify(txPoolConditions.inTransactionPool(Hash.fromHexString(txHash))); + } + + @Test + public void blockedFilteredByGasLimit() { + final Account sender = accounts.getPrimaryBenefactor(); + final Account recipient = accounts.createAccount("account-two"); + final BigInteger GAS_LIMIT = BigInteger.valueOf(GAS_LIMIT_THRESHOLD - 100); + final BigInteger GAS_PRICE = BigInteger.valueOf(1000); + final Amount amount = Amount.wei(BigInteger.valueOf(29)); + + final RawTransaction tx = + RawTransaction.createEtherTransaction( + sender.getNextNonce(), + GAS_PRICE, + GAS_LIMIT, + recipient.getAddress(), + Convert.toWei(amount.getValue(), amount.getUnit()).toBigIntegerExact()); + + final String rawSigned = + Numeric.toHexString( + SignUtil.signTransaction(tx, sender, new SECP256K1(), Optional.empty())); + + assertThatThrownBy(() -> aliceNode.execute(ethTransactions.sendRawTransaction(rawSigned))) + .isInstanceOf(RuntimeException.class) + .hasMessageContaining("not authorized"); + } } diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index a417b439e..3dc01ed8b 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -1177,10 +1177,17 @@ public class RunnerBuilder { final BesuController besuController, final TransactionSimulator transactionSimulator) { - if (permissioningConfiguration.isPresent()) { + if (permissioningConfiguration.isPresent() + || permissioningService.getTransactionPermissioningProviders().size() > 0) { + final PermissioningConfiguration configuration = + permissioningConfiguration.orElse( + new PermissioningConfiguration(Optional.empty(), Optional.empty())); final Optional accountPermissioningController = AccountPermissioningControllerFactory.create( - permissioningConfiguration.get(), transactionSimulator, metricsSystem); + configuration, + transactionSimulator, + metricsSystem, + permissioningService.getTransactionPermissioningProviders()); accountPermissioningController.ifPresent( permissioningController -> diff --git a/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java index e43bf1c05..4e14f460f 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java @@ -17,17 +17,24 @@ package org.hyperledger.besu.services; import org.hyperledger.besu.plugin.services.PermissioningService; import org.hyperledger.besu.plugin.services.permissioning.NodeConnectionPermissioningProvider; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; +import org.hyperledger.besu.plugin.services.permissioning.TransactionPermissioningProvider; +import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import com.google.common.collect.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** The Permissioning service implementation. */ public class PermissioningServiceImpl implements PermissioningService { + private static final Logger LOG = LoggerFactory.getLogger(PermissioningServiceImpl.class); private final List connectionPermissioningProviders = Lists.newArrayList(); + private final List transactionPermissioningProviders = + new ArrayList<>(); /** Default Constructor. */ @Inject @@ -39,6 +46,13 @@ public class PermissioningServiceImpl implements PermissioningService { connectionPermissioningProviders.add(provider); } + @Override + public void registerTransactionPermissioningProvider( + final TransactionPermissioningProvider provider) { + transactionPermissioningProviders.add(provider); + LOG.info("Registered new transaction permissioning provider."); + } + /** * Gets connection permissioning providers. * @@ -65,4 +79,13 @@ public class PermissioningServiceImpl implements PermissioningService { public List getMessagePermissioningProviders() { return messagePermissioningProviders; } + + /** + * Gets transaction permissioning providers. + * + * @return the transaction permissioning providers + */ + public List getTransactionPermissioningProviders() { + return transactionPermissioningProviders; + } } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java index cb1aa2fd0..0ac12fe45 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java @@ -16,12 +16,12 @@ package org.hyperledger.besu.ethereum.permissioning; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.permissioning.AllowlistPersistor.ALLOWLIST_TYPE; -import org.hyperledger.besu.ethereum.permissioning.account.TransactionPermissioningProvider; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; +import org.hyperledger.besu.plugin.services.permissioning.TransactionPermissioningProvider; import java.io.IOException; import java.util.ArrayList; diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java index 7bd691d02..6ad45b8a9 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningController.java @@ -19,7 +19,9 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; +import org.hyperledger.besu.plugin.services.permissioning.TransactionPermissioningProvider; +import java.util.List; import java.util.Optional; import com.google.common.annotations.VisibleForTesting; @@ -34,15 +36,18 @@ public class AccountPermissioningController { accountLocalConfigPermissioningController; private final Optional transactionSmartContractPermissioningController; + private final List pluginProviders; public AccountPermissioningController( final Optional accountLocalConfigPermissioningController, final Optional - transactionSmartContractPermissioningController) { + transactionSmartContractPermissioningController, + final List pluginProviders) { this.accountLocalConfigPermissioningController = accountLocalConfigPermissioningController; this.transactionSmartContractPermissioningController = transactionSmartContractPermissioningController; + this.pluginProviders = pluginProviders; } public boolean isPermitted( @@ -53,7 +58,7 @@ public class AccountPermissioningController { final Hash transactionHash = transaction.getHash(); final Address sender = transaction.getSender(); - LOG.trace("Account permissioning: Checking transaction {}", transactionHash); + LOG.trace("Transaction Rejector: Checking transaction {}", transactionHash); boolean permittedLocal = true; boolean permittedOnchain = true; @@ -75,6 +80,16 @@ public class AccountPermissioningController { final boolean permitted = permittedLocal && permittedOnchain; if (permitted) { + for (TransactionPermissioningProvider provider : this.pluginProviders) { + if (!provider.isPermitted(transaction)) { + LOG.trace( + "Transaction Rejector - {}: Rejected transaction {} from {}", + provider.getClass().getSimpleName(), + transactionHash, + sender); + return false; + } + } LOG.trace("Account permissioning: Permitted transaction {} from {}", transactionHash, sender); } else { LOG.trace("Account permissioning: Rejected transaction {} from {}", transactionHash, sender); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java index 29e513ea5..124fa6f87 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactory.java @@ -28,7 +28,9 @@ import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningCon import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.permissioning.TransactionPermissioningProvider; +import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; @@ -43,7 +45,8 @@ public class AccountPermissioningControllerFactory { public static Optional create( final PermissioningConfiguration permissioningConfiguration, final TransactionSimulator transactionSimulator, - final MetricsSystem metricsSystem) { + final MetricsSystem metricsSystem, + final List pluginProviders) { if (permissioningConfiguration == null) { return Optional.empty(); @@ -59,12 +62,14 @@ public class AccountPermissioningControllerFactory { permissioningConfiguration, transactionSimulator, metricsSystem); if (accountLocalConfigPermissioningController.isPresent() - || transactionSmartContractPermissioningController.isPresent()) { + || transactionSmartContractPermissioningController.isPresent() + || pluginProviders.size() > 0) { final AccountPermissioningController controller = new AccountPermissioningController( accountLocalConfigPermissioningController, - transactionSmartContractPermissioningController); + transactionSmartContractPermissioningController, + pluginProviders); return Optional.of(controller); } else { diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java index 6e76725fb..4d6f0d068 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerFactoryTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.Collections; import java.util.Optional; import org.assertj.core.api.Assertions; @@ -49,7 +50,8 @@ public class AccountPermissioningControllerFactoryTest { @Test public void createWithNullPermissioningConfigShouldReturnEmpty() { Optional controller = - AccountPermissioningControllerFactory.create(null, transactionSimulator, metricsSystem); + AccountPermissioningControllerFactory.create( + null, transactionSimulator, metricsSystem, Collections.emptyList()); Assertions.assertThat(controller).isEmpty(); } @@ -64,7 +66,10 @@ public class AccountPermissioningControllerFactoryTest { Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList()); Assertions.assertThat(controller).isEmpty(); } @@ -79,7 +84,10 @@ public class AccountPermissioningControllerFactoryTest { Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList()); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isNotEmpty(); @@ -97,7 +105,10 @@ public class AccountPermissioningControllerFactoryTest { Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList()); Assertions.assertThat(controller).isEmpty(); } @@ -112,7 +123,10 @@ public class AccountPermissioningControllerFactoryTest { Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList()); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isEmpty(); @@ -133,7 +147,10 @@ public class AccountPermissioningControllerFactoryTest { catchThrowable( () -> AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem)); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList())); assertThat(thrown) .isInstanceOf(IllegalStateException.class) @@ -153,7 +170,10 @@ public class AccountPermissioningControllerFactoryTest { Optional controller = AccountPermissioningControllerFactory.create( - permissioningConfiguration, transactionSimulator, metricsSystem); + permissioningConfiguration, + transactionSimulator, + metricsSystem, + Collections.emptyList()); Assertions.assertThat(controller).isNotEmpty(); assertThat(controller.get().getAccountLocalConfigPermissioningController()).isNotEmpty(); diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java index 4e2e7b5e8..5707564f3 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/account/AccountPermissioningControllerTest.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; import org.hyperledger.besu.ethereum.permissioning.TransactionSmartContractPermissioningController; +import java.util.Collections; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; @@ -45,7 +46,9 @@ public class AccountPermissioningControllerTest { public void before() { permissioningController = new AccountPermissioningController( - Optional.of(localConfigController), Optional.of(smartContractController)); + Optional.of(localConfigController), + Optional.of(smartContractController), + Collections.emptyList()); } @Test diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 1862b5fcf..aaf1f6f44 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'lsoaojUhm38o4QxfJW2fky/eEkrtUyprNrwAkfwebe8=' + knownHash = 'Qq6tGiNFfAs1JVr7xXx07h/ANxPWcFKe3cBHER43FFQ=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/PermissioningService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/PermissioningService.java index a9fd67850..061a9e5cc 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/PermissioningService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/PermissioningService.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.plugin.services.permissioning.NodeConnectionPermissioningProvider; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; +import org.hyperledger.besu.plugin.services.permissioning.TransactionPermissioningProvider; /** * This service allows plugins to decide who you should connect to and what you should send them. @@ -38,6 +39,13 @@ public interface PermissioningService extends BesuService { */ void registerNodePermissioningProvider(NodeConnectionPermissioningProvider provider); + /** + * Registers a callback for transaction permission. + * + * @param provider The provider to register + */ + void registerTransactionPermissioningProvider(final TransactionPermissioningProvider provider); + /** * Registers a callback to allow the interception of a devp2p message sending request * diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java new file mode 100644 index 000000000..5f5017b54 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright contributors to 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.plugin.services.permissioning; + +import org.hyperledger.besu.datatypes.Transaction; + +/** + * Allows you to register a provider that will decide if a transaction is permitted.
+ *
+ * A simple implementation can look like: + * + *
{@code
+ * context
+ *    .getService(PermissioningService.class)
+ *    .get()
+ *    .registerTransactionPermissioningProvider((tx) -> {
+ *        // Your logic here
+ *        return true;
+ *    });
+ * }
+ */ +@FunctionalInterface +public interface TransactionPermissioningProvider { + /** + * Can be used to filter transactions according to an arbitrary criteria + * + * @param transaction current transaction to be added in the mempool + * @return if we can add transaction to the mempool + */ + boolean isPermitted(final Transaction transaction); +}