mirror of https://github.com/hyperledger/besu
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
parent
6aef70b275
commit
21ac9fe310
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
Loading…
Reference in new issue