diff --git a/CHANGELOG.md b/CHANGELOG.md index 3047e298c83..dc534acf2c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ - Fast Sync ### Additions and Improvements +- Add support for transaction permissioning rules in Plugin API [#7952](https://github.com/hyperledger/besu/pull/7952) - Fine tune already seen txs tracker when a tx is removed from the pool [#7755](https://github.com/hyperledger/besu/pull/7755) - Support for enabling and configuring TLS/mTLS in WebSocket service. [#7854](https://github.com/hyperledger/besu/pull/7854) - Create and publish Besu BOM (Bill of Materials) [#7615](https://github.com/hyperledger/besu/pull/7615) 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 c2503ed8112..88541c5a101 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,17 @@ public void beforeExternalServices() { } return true; }); + + service.registerTransactionPermissioningProvider( + transaction -> { + long configuredGasLimitThreshold = 12000L; + long gasLimit = transaction.getGasLimit(); + LOG.info( + "Transaction gas limit: {} | Configured threshold: {} ", + gasLimit, + configuredGasLimitThreshold); + return gasLimit > configuredGasLimitThreshold; + }); } } 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 c469802fc1e..a3fae4e3a19 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,6 +14,8 @@ */ package org.hyperledger.besu.tests.acceptance.plugins; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; @@ -34,6 +36,8 @@ public class PermissioningPluginTest extends AcceptanceTestBase { private BesuNode bobNode; private BesuNode charlieNode; + private static final long GAS_LIMIT_THRESHOLD = 12000L; + @BeforeEach public void setUp() throws Exception { minerNode = besu.create(createNodeBuilder().name("miner").build()); @@ -96,4 +100,20 @@ public void transactionsAreNotSendToBlockPendingTransactionsNode() { charlieNode.verify(txPoolConditions.notInTransactionPool(txHash)); minerNode.verify(txPoolConditions.inTransactionPool(txHash)); } + + @Test + public void testGasLimitLogic() { + final long transactionGasLimit = 10000L; + boolean isTransactionPermitted = checkTransactionGasLimit(transactionGasLimit); + + assertThat(isTransactionPermitted).isTrue(); + } + + private boolean checkTransactionGasLimit(final long gasLimit) { + if (gasLimit > GAS_LIMIT_THRESHOLD) { + return true; + } else { + return false; + } + } } 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 e43bf1c054e..3970ebb671c 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/PermissioningServiceImpl.java @@ -14,20 +14,28 @@ */ package org.hyperledger.besu.services; +import org.hyperledger.besu.datatypes.Transaction; 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 +47,13 @@ public void registerNodePermissioningProvider( 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 +80,20 @@ public void registerNodeMessagePermissioningProvider( public List getMessagePermissioningProviders() { return messagePermissioningProviders; } + + /** + * Gets transaction rules. + * + * @return whether the transaction is permitted + */ + public boolean isTransactionPermitted(final Transaction transaction) { + for (TransactionPermissioningProvider provider : transactionPermissioningProviders) { + if (!provider.isPermitted(transaction)) { + LOG.debug("Transaction {} not permitted by one of the providers.", transaction.getHash()); + return false; + } + } + LOG.debug("Transaction {} permitted.", transaction.getHash()); + return true; + } } 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 cb1aa2fd0a1..0ac12fe4543 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 @@ 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/TransactionSmartContractPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java index dd42727af85..60b1838ab3b 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningController.java @@ -19,15 +19,17 @@ import org.hyperledger.besu.crypto.Hash; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.permissioning.account.TransactionPermissioningProvider; +import org.hyperledger.besu.datatypes.Quantity; +import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult; 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.math.BigInteger; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; @@ -195,9 +197,13 @@ public static Bytes createPayload(final Bytes signature, final Transaction trans private static Bytes encodeTransaction(final Transaction transaction) { return Bytes.concatenate( encodeAddress(transaction.getSender()), - encodeAddress(transaction.getTo()), - transaction.getValue(), - transaction.getGasPrice().map(BaseUInt256Value::toBytes).orElse(Bytes32.ZERO), + encodeAddress(transaction.getTo().map(Address.class::cast)), + convertQuantityToBytes(transaction.getValue()), + transaction + .getGasPrice() + .map(price -> (BaseUInt256Value) price) + .map(BaseUInt256Value::toBytes) + .orElse(Bytes32.ZERO), encodeLong(transaction.getGasLimit()), encodeBytes(transaction.getPayload())); } @@ -231,4 +237,16 @@ private static Bytes encodeBytes(final Bytes value) { final Bytes padding = Bytes.wrap(new byte[(32 - (value.size() % 32))]); return Bytes.concatenate(dynamicParameterOffset, length, value, padding); } + + // Convert the Quantity value to Bytes + private static Bytes convertQuantityToBytes(final Quantity quantity) { + if (quantity == null) { + return Bytes32.ZERO; + } + if (quantity instanceof BaseUInt256Value) { + return ((BaseUInt256Value) quantity).toBytes(); + } + BigInteger value = quantity.getAsBigInteger(); + return Bytes.wrap(value.toByteArray()); + } } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index f8608f89325..04f3546b464 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 = 'TPCo4SZ61OrJxRAa2SIcAIOAOjVTdRw+UOeHMuiJP84=' + knownHash = 'ILrmIl1hU61dFKgFPIvxIJYVLAbIOfX62SotTY2pWnA=' } 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 a9fd6785050..061a9e5cc1d 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 @@ 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/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/TransactionPermissioningProvider.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java similarity index 83% rename from ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/TransactionPermissioningProvider.java rename to plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java index 9feee8e0079..f09f6487c39 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/account/TransactionPermissioningProvider.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/permissioning/TransactionPermissioningProvider.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * 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 @@ -12,9 +12,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.permissioning.account; +package org.hyperledger.besu.plugin.services.permissioning; -import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.datatypes.Transaction; @FunctionalInterface public interface TransactionPermissioningProvider {