Updated permissioning controller to handle both DNS and IP rules. (#2667)

* Updated permissioning controller to handle both DNS and IP rules.

Signed-off-by: Mark Terry <mark.terry@consensys.net>
pull/2675/head
mark-terry 3 years ago committed by GitHub
parent 6aef70b275
commit 21ac9fe310
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 9
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/condition/perm/NodeSmartContractPermissioningV2Conditions.java
  3. 95
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/perm/NodeSmartContractPermissioningAllowNodeByURLV2Transaction.java
  4. 80
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/perm/NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction.java
  5. 95
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/perm/NodeSmartContractPermissioningForbidNodeByURLV2Transaction.java
  6. 17
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/transaction/perm/NodeSmartContractPermissioningV2Transactions.java
  7. 1
      acceptance-tests/tests/build.gradle
  8. 19
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningV2AcceptanceTestBase.java
  9. 106
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/NodeSmartContractPermissioningV2DNSAcceptanceTest.java
  10. 2
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImpl.java
  11. 4
      ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURLImplTest.java
  12. 28
      ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningController.java
  13. 52
      ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractV2PermissioningControllerTest.java

@ -15,7 +15,7 @@
- Added Labelled gauges for metrics [#2646](https://github.com/hyperledger/besu/pull/2646)
- support for `eth/66` networking protocol [#2365](https://github.com/hyperledger/besu/pull/2365)
- update RPC methods for post london 1559 transaction [#2535](https://github.com/hyperledger/besu/pull/2535)
- \[EXPERIMENTAL\] Added support for using DNS host name in place of IP address in onchain node permissioning rules [#2667](https://github.com/hyperledger/besu/pull/2667)
### Bug Fixes
- Consider effective price and effective priority fee in transaction replacement rules [\#2529](https://github.com/hyperledger/besu/issues/2529)

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.tests.acceptance.dsl.condition.perm;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.NodeSmartContractPermissioningV2Transactions;
@ -31,7 +32,15 @@ public class NodeSmartContractPermissioningV2Conditions {
return new WaitForTrueResponse(transactions.isConnectionAllowed(address, node));
}
public Condition connectionIsAllowed(final String address, final EnodeURL enodeURL) {
return new WaitForTrueResponse(transactions.isConnectionAllowed(address, enodeURL));
}
public Condition connectionIsForbidden(final String address, final Node node) {
return new WaitForFalseResponse(transactions.isConnectionAllowed(address, node));
}
public Condition connectionIsForbidden(final String address, final EnodeURL enodeURL) {
return new WaitForFalseResponse(transactions.isConnectionAllowed(address, enodeURL));
}
}

@ -0,0 +1,95 @@
/*
* 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.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningAllowNodeByURLV2Transaction
implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningAllowNodeByURLV2Transaction(
final Account sender, final Address contractAddress, final EnodeURL enodeUrl) {
this.sender = sender;
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload = createPayload(enodeUrl);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1_000L),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function addNodeFunction =
FunctionEncoder.makeFunction(
"addEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(addNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error adding node to allowlist", e);
}
}
}

@ -0,0 +1,80 @@
/*
* 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.transaction.perm;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.permissioning.NodeSmartContractV2PermissioningController;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.protocol.core.DefaultBlockParameterName;
public class NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction
implements Transaction<Boolean> {
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction(
final Address contractAddress, final EnodeURL enodeUrl) {
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Boolean execute(final NodeRequests node) {
try {
final String value =
node.eth().ethCall(payload(), DefaultBlockParameterName.LATEST).send().getValue();
return Bytes.fromHexString(value)
.equals(NodeSmartContractV2PermissioningController.TRUE_RESPONSE);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private org.web3j.protocol.core.methods.request.Transaction payload() {
final Bytes payload = createPayload(this.enodeUrl);
return org.web3j.protocol.core.methods.request.Transaction.createFunctionCallTransaction(
null, null, null, null, contractAddress.toString(), payload.toString());
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function connectionAllowedFunction =
FunctionEncoder.makeFunction(
"connectionAllowed",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(connectionAllowedFunction));
} catch (Exception e) {
throw new RuntimeException("Error calling connectionAllowed", e);
}
}
}

@ -0,0 +1,95 @@
/*
* 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.transaction.perm;
import static org.web3j.utils.Numeric.toHexString;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.NodeRequests;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
public class NodeSmartContractPermissioningForbidNodeByURLV2Transaction
implements Transaction<Hash> {
private final Account sender;
private final Address contractAddress;
private final EnodeURL enodeUrl;
public NodeSmartContractPermissioningForbidNodeByURLV2Transaction(
final Account sender, final Address contractAddress, final EnodeURL enodeUrl) {
this.sender = sender;
this.contractAddress = contractAddress;
this.enodeUrl = enodeUrl;
}
@Override
public Hash execute(final NodeRequests node) {
final String signedTransactionData = signedTransactionData();
try {
String hash =
node.eth().ethSendRawTransaction(signedTransactionData).send().getTransactionHash();
return Hash.fromHexString(hash);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private String signedTransactionData() {
final Bytes payload = createPayload(this.enodeUrl);
RawTransaction transaction =
RawTransaction.createTransaction(
sender.getNextNonce(),
BigInteger.valueOf(1000),
BigInteger.valueOf(3_000_000L),
contractAddress.toString(),
payload.toString());
return toHexString(
TransactionEncoder.signMessage(transaction, sender.web3jCredentialsOrThrow()));
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function removeNodeFunction =
FunctionEncoder.makeFunction(
"removeEnode",
List.of("string", "string", "uint16"),
List.of(hexNodeIdString, address, port),
Collections.emptyList());
return Bytes.fromHexString(FunctionEncoder.encode(removeNodeFunction));
} catch (Exception e) {
throw new RuntimeException("Error removing node from allowlist", e);
}
}
}

@ -16,6 +16,7 @@ package org.hyperledger.besu.tests.acceptance.dsl.transaction.perm;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.Transaction;
@ -33,13 +34,29 @@ public class NodeSmartContractPermissioningV2Transactions {
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Hash> allowNode(final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningAllowNodeByURLV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), enodeURL);
}
public Transaction<Hash> forbidNode(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningForbidNodeV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), node);
}
public Transaction<Hash> forbidNode(final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningForbidNodeByURLV2Transaction(
accounts.getPrimaryBenefactor(), Address.fromHexString(contractAddress), enodeURL);
}
public Transaction<Boolean> isConnectionAllowed(final String contractAddress, final Node node) {
return new NodeSmartContractPermissioningConnectionIsAllowedV2Transaction(
Address.fromHexString(contractAddress), node);
}
public Transaction<Boolean> isConnectionAllowed(
final String contractAddress, final EnodeURL enodeURL) {
return new NodeSmartContractPermissioningConnectionIsAllowedByURLV2Transaction(
Address.fromHexString(contractAddress), enodeURL);
}
}

@ -23,6 +23,7 @@ dependencies {
testImplementation project(':ethereum:api')
testImplementation project(':ethereum:core')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':ethereum:p2p')
testImplementation project(':ethereum:permissioning')
testImplementation project(':ethereum:rlp')
testImplementation project(':metrics:core')

@ -15,6 +15,7 @@
package org.hyperledger.besu.tests.acceptance.permissioning;
import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase;
import org.hyperledger.besu.tests.acceptance.dsl.condition.Condition;
import org.hyperledger.besu.tests.acceptance.dsl.condition.perm.NodeSmartContractPermissioningV2Conditions;
@ -110,15 +111,33 @@ class NodeSmartContractPermissioningV2AcceptanceTestBase extends AcceptanceTestB
return smartContractNodePermissioningV2.allowNode(CONTRACT_ADDRESS, node);
}
protected Transaction<Hash> allowNode(final EnodeURL enodeURL) {
return smartContractNodePermissioningV2.allowNode(CONTRACT_ADDRESS, enodeURL);
}
protected Transaction<Hash> forbidNode(final Node node) {
return smartContractNodePermissioningV2.forbidNode(CONTRACT_ADDRESS, node);
}
protected Transaction<Hash> forbidNode(final EnodeURL enodeURL) {
return smartContractNodePermissioningV2.forbidNode(CONTRACT_ADDRESS, enodeURL);
}
protected Condition connectionIsForbidden(final Node node) {
return nodeSmartContractPermissioningConditionsV2.connectionIsForbidden(CONTRACT_ADDRESS, node);
}
protected Condition connectionIsForbidden(final EnodeURL enodeURL) {
return nodeSmartContractPermissioningConditionsV2.connectionIsForbidden(
CONTRACT_ADDRESS, enodeURL);
}
protected Condition connectionIsAllowed(final Node node) {
return nodeSmartContractPermissioningConditionsV2.connectionIsAllowed(CONTRACT_ADDRESS, node);
}
protected Condition connectionIsAllowed(final EnodeURL enodeURL) {
return nodeSmartContractPermissioningConditionsV2.connectionIsAllowed(
CONTRACT_ADDRESS, enodeURL);
}
}

@ -0,0 +1,106 @@
/*
* 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.permissioning;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import org.hyperledger.besu.tests.acceptance.dsl.node.Node;
import org.hyperledger.besu.tests.acceptance.dsl.node.RunnableNode;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
public class NodeSmartContractPermissioningV2DNSAcceptanceTest
extends NodeSmartContractPermissioningV2AcceptanceTestBase {
private Node bootnode;
private Node permissionedNode;
private Node allowedNode;
private Node forbiddenNode;
final ImmutableEnodeDnsConfiguration enodeDnsConfiguration =
ImmutableEnodeDnsConfiguration.builder().dnsEnabled(true).updateEnabled(true).build();
@Before
public void setUp() {
bootnode = bootnode("bootnode");
forbiddenNode = node("forbidden-node");
allowedNode = node("allowed-node");
permissionedNode = permissionedNode("permissioned-node");
permissionedCluster.start(bootnode, forbiddenNode, allowedNode, permissionedNode);
// updating permissioning smart contract with allowed nodes
permissionedNode.execute(allowNode(bootnode));
permissionedNode.verify(connectionIsAllowed(bootnode));
permissionedNode.execute(allowNode(allowedNode));
permissionedNode.verify(connectionIsAllowed(allowedNode));
permissionedNode.execute(allowNode(permissionedNode));
permissionedNode.verify(connectionIsAllowed(permissionedNode));
// Verify initial configuration
bootnode.verify(net.awaitPeerCount(3));
allowedNode.verify(net.awaitPeerCount(3));
forbiddenNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(net.awaitPeerCount(2));
}
@Test
public void permissionedNodeShouldAddDnsRuleAndAllowNode() {
final EnodeURL forbiddenEnodeURL = getForbiddenEnodeURL();
Assertions.assertThat(forbiddenEnodeURL.toURI().getHost()).isEqualTo("127.0.0.1");
final EnodeURL forbiddenDnsEnodeURL = buildDnsEnodeUrl(forbiddenEnodeURL);
Assertions.assertThat(forbiddenDnsEnodeURL.toURI().getHost()).isEqualTo("localhost");
permissionedNode.verify(connectionIsForbidden(forbiddenNode));
permissionedNode.verify(connectionIsForbidden(forbiddenDnsEnodeURL));
permissionedNode.execute(allowNode(forbiddenDnsEnodeURL));
permissionedNode.verify(connectionIsAllowed(forbiddenDnsEnodeURL));
permissionedNode.execute(forbidNode(forbiddenEnodeURL));
}
@Test
public void permissionedNodeShouldAddDNSRuleAndConnectToNewPeer() {
final EnodeURL forbiddenEnodeURL = getForbiddenEnodeURL();
Assertions.assertThat(forbiddenEnodeURL.toURI().getHost()).isEqualTo("127.0.0.1");
final EnodeURL forbiddenDnsEnodeURL = buildDnsEnodeUrl(forbiddenEnodeURL);
Assertions.assertThat(forbiddenDnsEnodeURL.toURI().getHost()).isEqualTo("localhost");
permissionedNode.verify(net.awaitPeerCount(2));
permissionedNode.verify(connectionIsForbidden(forbiddenNode));
permissionedNode.verify(connectionIsForbidden(forbiddenDnsEnodeURL));
permissionedNode.execute(allowNode(forbiddenDnsEnodeURL));
permissionedNode.verify(connectionIsAllowed(forbiddenDnsEnodeURL));
permissionedNode.verify(admin.addPeer(forbiddenNode));
permissionedNode.verify(net.awaitPeerCount(3));
permissionedNode.execute(forbidNode(forbiddenEnodeURL));
}
private EnodeURL getForbiddenEnodeURL() {
return EnodeURLImpl.fromURI(((RunnableNode) forbiddenNode).enodeUrl());
}
private EnodeURL buildDnsEnodeUrl(final EnodeURL forbiddenEnodeURL) {
return EnodeURLImpl.builder()
.configureFromEnode(forbiddenEnodeURL)
.ipAddress("localhost", enodeDnsConfiguration)
.build();
}
}

@ -96,7 +96,7 @@ public class EnodeURLImpl implements EnodeURL {
public static EnodeURL fromURI(final URI uri, final EnodeDnsConfiguration enodeDnsConfiguration) {
checkArgument(uri != null, "URI cannot be null");
checkStringArgumentNotEmpty(uri.getScheme(), "Missing 'enode' scheme.");
checkStringArgumentNotEmpty(uri.getHost(), "Missing or invalid ip address.");
checkStringArgumentNotEmpty(uri.getHost(), "Missing or invalid host or ip address.");
checkStringArgumentNotEmpty(uri.getUserInfo(), "Missing node ID.");
checkArgument(

@ -238,7 +238,7 @@ public class EnodeURLImplTest {
assertThat(thrown)
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Missing or invalid ip address.");
.hasMessageContaining("Missing or invalid host or ip address.");
}
@Test
@ -248,7 +248,7 @@ public class EnodeURLImplTest {
assertThat(thrown)
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Missing or invalid ip address.");
.hasMessageContaining("Missing or invalid host or ip address.");
}
@Test

@ -15,7 +15,8 @@
package org.hyperledger.besu.ethereum.permissioning;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.plugin.data.EnodeURL;
@ -23,7 +24,9 @@ import org.hyperledger.besu.plugin.services.MetricsSystem;
import java.util.List;
import com.google.common.net.InetAddresses;
import org.apache.tuweni.bytes.Bytes;
import org.jetbrains.annotations.NotNull;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeEncoder;
import org.web3j.abi.datatypes.Bool;
@ -53,16 +56,31 @@ public class NodeSmartContractV2PermissioningController
}
private boolean isPermitted(final EnodeURL enode) {
final Bytes payload = createPayload(enode);
final CallParameter callParams = buildCallParameters(payload);
return getCallResult(enode) || (boolean) getCallResult(ipToDNS(enode));
}
@NotNull
private Boolean getCallResult(final EnodeURL enode) {
return transactionSimulator
.processAtHead(buildCallParameters(createPayload(enode)))
.map(this::parseResult)
.orElse(false);
}
return transactionSimulator.processAtHead(callParams).map(this::parseResult).orElse(false);
private EnodeURL ipToDNS(final EnodeURL enodeURL) {
final String dnsHost = InetAddresses.forString(enodeURL.getIpAsString()).getHostName();
final ImmutableEnodeDnsConfiguration dnsConfig =
ImmutableEnodeDnsConfiguration.builder().dnsEnabled(true).updateEnabled(true).build();
return EnodeURLImpl.builder()
.configureFromEnode(enodeURL)
.ipAddress(dnsHost, dnsConfig)
.build();
}
private Bytes createPayload(final EnodeURL enodeUrl) {
try {
final String hexNodeIdString = enodeUrl.getNodeId().toUnprefixedHexString();
final String address = enodeUrl.getIp().getHostAddress();
final String address = enodeUrl.toURI().getHost();
final int port = enodeUrl.getListeningPortOrZero();
final Function connectionAllowedFunction =

@ -47,13 +47,20 @@ public class NodeSmartContractV2PermissioningControllerTest {
/*
Payloads created using Remix to call method connectionAllowed(string, string, uint16)
*/
private static final Bytes SOURCE_ENODE_EXPECTED_PAYLOAD =
private static final Bytes SOURCE_ENODE_EXPECTED_PAYLOAD_IP =
Bytes.fromHexString(
"0x45a59e5b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000765f0000000000000000000000000000000000000000000000000000000000000080666362653966383332313834383762336330623530383738313933383830653663323563666438363730386330613062663063613931663063653633333734366138393266653234306166613562396138383062386263613438653861323237303465663933376664646132643763633633653464343165643162343137616500000000000000000000000000000000000000000000000000000000000000093132372e302e302e310000000000000000000000000000000000000000000000");
private static final Bytes DESTINATION_ENODE_EXPECTED_PAYLOAD =
private static final Bytes DESTINATION_ENODE_EXPECTED_PAYLOAD_IP =
Bytes.fromHexString(
"0x45a59e5b000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000009dd40000000000000000000000000000000000000000000000000000000000000080333534386338376239393230666631366161346264636630316338356632353131376132396165313537346437353962616434386363393436336438653966376333633164316539666230643238653733383938393531663930653032373134616262373730666436643232653930333731383832613435363538383030653900000000000000000000000000000000000000000000000000000000000000093132372e302e302e310000000000000000000000000000000000000000000000");
private static final Bytes SOURCE_ENODE_EXPECTED_PAYLOAD_DNS =
Bytes.fromHexString(
"0x45a59e5b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000765f0000000000000000000000000000000000000000000000000000000000000080666362653966383332313834383762336330623530383738313933383830653663323563666438363730386330613062663063613931663063653633333734366138393266653234306166613562396138383062386263613438653861323237303465663933376664646132643763633633653464343165643162343137616500000000000000000000000000000000000000000000000000000000000000096c6f63616c686f73740000000000000000000000000000000000000000000000");
private static final Bytes DESTINATION_ENODE_EXPECTED_PAYLOAD_DNS =
Bytes.fromHexString(
"0x45a59e5b000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000009dd40000000000000000000000000000000000000000000000000000000000000080333534386338376239393230666631366161346264636630316338356632353131376132396165313537346437353962616434386363393436336438653966376333633164316539666230643238653733383938393531663930653032373134616262373730666436643232653930333731383832613435363538383030653900000000000000000000000000000000000000000000000000000000000000096c6f63616c686f73740000000000000000000000000000000000000000000000");
private static final EnodeURL SOURCE_ENODE_IPV4 =
EnodeURLImpl.fromString(
"enode://fcbe9f83218487b3c0b50878193880e6c25cfd86708c0a0bf0ca91f0ce633746a892fe240afa5b9a880b8bca48e8a22704ef937fdda2d7cc63e4d41ed1b417ae@127.0.0.1:30303");
@ -86,7 +93,7 @@ public class NodeSmartContractV2PermissioningControllerTest {
final TransactionSimulatorResult txSimulatorResult =
transactionSimulatorResult(Bytes.random(10), ValidationResult.valid());
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
assertThatIllegalStateException()
@ -102,7 +109,7 @@ public class NodeSmartContractV2PermissioningControllerTest {
transactionSimulatorResult(
NodeSmartContractV2PermissioningController.FALSE_RESPONSE, ValidationResult.valid());
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
boolean isPermitted =
@ -117,7 +124,7 @@ public class NodeSmartContractV2PermissioningControllerTest {
NodeSmartContractV2PermissioningController.TRUE_RESPONSE,
ValidationResult.invalid(TransactionInvalidReason.INTERNAL_ERROR));
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
boolean isPermitted =
@ -131,9 +138,9 @@ public class NodeSmartContractV2PermissioningControllerTest {
transactionSimulatorResult(
NodeSmartContractV2PermissioningController.TRUE_RESPONSE, ValidationResult.valid());
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
boolean isPermitted =
@ -149,9 +156,9 @@ public class NodeSmartContractV2PermissioningControllerTest {
transactionSimulatorResult(
NodeSmartContractV2PermissioningController.TRUE_RESPONSE, ValidationResult.valid());
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD))))
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResult));
boolean isPermitted =
@ -161,6 +168,33 @@ public class NodeSmartContractV2PermissioningControllerTest {
verify(transactionSimulator, times(2)).processAtHead(any());
}
@Test
public void expectedPayloadWhenCheckingPermissioningWithAlternateDNS() {
final TransactionSimulatorResult txSimulatorResultFalse =
transactionSimulatorResult(
NodeSmartContractV2PermissioningController.FALSE_RESPONSE, ValidationResult.valid());
final TransactionSimulatorResult txSimulatorResultTrue =
transactionSimulatorResult(
NodeSmartContractV2PermissioningController.TRUE_RESPONSE, ValidationResult.valid());
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResultFalse));
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD_IP))))
.thenReturn(Optional.of(txSimulatorResultFalse));
when(transactionSimulator.processAtHead(eq(callParams(SOURCE_ENODE_EXPECTED_PAYLOAD_DNS))))
.thenReturn(Optional.of(txSimulatorResultTrue));
when(transactionSimulator.processAtHead(eq(callParams(DESTINATION_ENODE_EXPECTED_PAYLOAD_DNS))))
.thenReturn(Optional.of(txSimulatorResultTrue));
boolean isPermitted =
permissioningController.checkSmartContractRules(SOURCE_ENODE_IPV4, DESTINATION_ENODE_IPV4);
assertThat(isPermitted).isTrue();
verify(transactionSimulator, times(4)).processAtHead(any());
}
private CallParameter callParams(final Bytes payload) {
return new CallParameter(null, contractAddress, -1, null, null, payload);
}

Loading…
Cancel
Save