mirror of https://github.com/hyperledger/besu
Basic Ibft Json Acceptance tests (#634)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
5e8ecff6bc
commit
fd950378f9
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft.IbftTransactions; |
||||
|
||||
import java.util.Map; |
||||
|
||||
public class ExpectProposals implements Condition { |
||||
private final IbftTransactions ibft; |
||||
private final Map<Address, Boolean> proposers; |
||||
|
||||
public ExpectProposals(final IbftTransactions ibft, final Map<Address, Boolean> proposers) { |
||||
this.ibft = ibft; |
||||
this.proposers = proposers; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor(() -> assertThat(node.execute(ibft.createProposals())).isEqualTo(proposers)); |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft.IbftTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft.IbftTransactions; |
||||
|
||||
public class ExpectValidators implements Condition { |
||||
private final IbftTransactions ibft; |
||||
private final Address[] validators; |
||||
|
||||
public ExpectValidators(final IbftTransactions ibft, final Address... validators) { |
||||
this.ibft = ibft; |
||||
this.validators = validators; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
waitFor( |
||||
() -> |
||||
assertThat(node.execute(ibft.createGetValidators(LATEST))).containsExactly(validators)); |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import java.util.Collections; |
||||
|
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.Request; |
||||
import org.web3j.protocol.core.Response; |
||||
|
||||
public class AdminJsonRpcRequestFactory { |
||||
|
||||
public static class AdminAddPeerResponse extends Response<Boolean> {} |
||||
|
||||
private final Web3jService web3jService; |
||||
|
||||
public AdminJsonRpcRequestFactory(final Web3jService web3jService) { |
||||
this.web3jService = web3jService; |
||||
} |
||||
|
||||
public Request<?, AdminAddPeerResponse> adminAddPeer(final String enodeAddress) { |
||||
return new Request<>( |
||||
"admin_addPeer", |
||||
Collections.singletonList(enodeAddress), |
||||
web3jService, |
||||
AdminAddPeerResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,66 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static java.util.Collections.singletonList; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.DiscardResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposalsResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposeResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.SignersBlockResponse; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.Request; |
||||
|
||||
public class CliqueJsonRpcRequestFactory { |
||||
|
||||
private final Web3jService web3jService; |
||||
|
||||
public CliqueJsonRpcRequestFactory(final Web3jService web3jService) { |
||||
this.web3jService = web3jService; |
||||
} |
||||
|
||||
public Request<?, ProposeResponse> cliquePropose(final String address, final Boolean auth) { |
||||
return new Request<>( |
||||
"clique_propose", |
||||
Arrays.asList(address, auth.toString()), |
||||
web3jService, |
||||
ProposeResponse.class); |
||||
} |
||||
|
||||
public Request<?, DiscardResponse> cliqueDiscard(final String address) { |
||||
return new Request<>( |
||||
"clique_discard", singletonList(address), web3jService, DiscardResponse.class); |
||||
} |
||||
|
||||
public Request<?, ProposalsResponse> cliqueProposals() { |
||||
return new Request<>("clique_proposals", emptyList(), web3jService, ProposalsResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSigners(final String blockNumber) { |
||||
return new Request<>( |
||||
"clique_getSigners", singletonList(blockNumber), web3jService, SignersBlockResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSignersAtHash(final Hash hash) { |
||||
return new Request<>( |
||||
"clique_getSignersAtHash", |
||||
singletonList(hash.toString()), |
||||
web3jService, |
||||
SignersBlockResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,70 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static java.util.Collections.singletonList; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.DiscardResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposalsResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposeResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.SignersBlockResponse; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.Request; |
||||
|
||||
public class IbftJsonRpcRequestFactory { |
||||
|
||||
private final Web3jService web3jService; |
||||
|
||||
public IbftJsonRpcRequestFactory(final Web3jService web3jService) { |
||||
this.web3jService = web3jService; |
||||
} |
||||
|
||||
public Request<?, ProposeResponse> ibftPropose(final String address, final Boolean auth) { |
||||
return new Request<>( |
||||
"ibft_proposeValidatorVote", |
||||
Arrays.asList(address, auth.toString()), |
||||
web3jService, |
||||
ProposeResponse.class); |
||||
} |
||||
|
||||
public Request<?, DiscardResponse> ibftDiscard(final String address) { |
||||
return new Request<>( |
||||
"ibft_discardValidatorVote", singletonList(address), web3jService, DiscardResponse.class); |
||||
} |
||||
|
||||
public Request<?, ProposalsResponse> ibftProposals() { |
||||
return new Request<>( |
||||
"ibft_getPendingVotes", emptyList(), web3jService, ProposalsResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> ibftGetValidators(final String blockNumber) { |
||||
return new Request<>( |
||||
"ibft_getValidatorsByBlockNumber", |
||||
singletonList(blockNumber), |
||||
web3jService, |
||||
SignersBlockResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> ibftGetSignersAtHash(final Hash hash) { |
||||
return new Request<>( |
||||
"ibft_getValidatorsByBlockHash", |
||||
singletonList(hash.toString()), |
||||
web3jService, |
||||
SignersBlockResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,65 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import org.web3j.protocol.core.JsonRpc2_0Web3j; |
||||
|
||||
public class JsonRequestFactories { |
||||
|
||||
private final JsonRpc2_0Web3j netEth; |
||||
private final CliqueJsonRpcRequestFactory clique; |
||||
private final IbftJsonRpcRequestFactory ibft; |
||||
private final PermissioningJsonRpcRequestFactory perm; |
||||
private final AdminJsonRpcRequestFactory admin; |
||||
|
||||
public JsonRequestFactories( |
||||
final JsonRpc2_0Web3j netEth, |
||||
final CliqueJsonRpcRequestFactory clique, |
||||
final IbftJsonRpcRequestFactory ibft, |
||||
final PermissioningJsonRpcRequestFactory perm, |
||||
final AdminJsonRpcRequestFactory admin) { |
||||
this.netEth = netEth; |
||||
this.clique = clique; |
||||
this.ibft = ibft; |
||||
this.perm = perm; |
||||
this.admin = admin; |
||||
} |
||||
|
||||
public JsonRpc2_0Web3j eth() { |
||||
return netEth; |
||||
} |
||||
|
||||
public JsonRpc2_0Web3j net() { |
||||
return netEth; |
||||
} |
||||
|
||||
public CliqueJsonRpcRequestFactory clique() { |
||||
return clique; |
||||
} |
||||
|
||||
public IbftJsonRpcRequestFactory ibft() { |
||||
return ibft; |
||||
} |
||||
|
||||
public PermissioningJsonRpcRequestFactory perm() { |
||||
return perm; |
||||
} |
||||
|
||||
public AdminJsonRpcRequestFactory admin() { |
||||
return admin; |
||||
} |
||||
|
||||
public void shutdown() { |
||||
netEth.shutdown(); |
||||
} |
||||
} |
@ -1,149 +0,0 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import static java.util.Collections.emptyList; |
||||
import static java.util.Collections.singletonList; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
|
||||
import org.assertj.core.util.Lists; |
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.JsonRpc2_0Web3j; |
||||
import org.web3j.protocol.core.Request; |
||||
import org.web3j.protocol.core.Response; |
||||
|
||||
public class PantheonWeb3j extends JsonRpc2_0Web3j { |
||||
|
||||
public PantheonWeb3j(final Web3jService web3jService) { |
||||
super(web3jService); |
||||
} |
||||
|
||||
public PantheonWeb3j( |
||||
final Web3jService web3jService, |
||||
final long pollingInterval, |
||||
final ScheduledExecutorService scheduledExecutorService) { |
||||
super(web3jService, pollingInterval, scheduledExecutorService); |
||||
} |
||||
|
||||
public Request<?, ProposeResponse> cliquePropose(final String address, final Boolean auth) { |
||||
return new Request<>( |
||||
"clique_propose", |
||||
Arrays.asList(address, auth.toString()), |
||||
web3jService, |
||||
ProposeResponse.class); |
||||
} |
||||
|
||||
public Request<?, DiscardResponse> cliqueDiscard(final String address) { |
||||
return new Request<>( |
||||
"clique_discard", singletonList(address), web3jService, DiscardResponse.class); |
||||
} |
||||
|
||||
public Request<?, ProposalsResponse> cliqueProposals() { |
||||
return new Request<>("clique_proposals", emptyList(), web3jService, ProposalsResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSigners(final String blockNumber) { |
||||
return new Request<>( |
||||
"clique_getSigners", singletonList(blockNumber), web3jService, SignersBlockResponse.class); |
||||
} |
||||
|
||||
public Request<?, SignersBlockResponse> cliqueGetSignersAtHash(final Hash hash) { |
||||
return new Request<>( |
||||
"clique_getSignersAtHash", |
||||
singletonList(hash.toString()), |
||||
web3jService, |
||||
SignersBlockResponse.class); |
||||
} |
||||
|
||||
public static class ProposeResponse extends Response<Boolean> {} |
||||
|
||||
public static class DiscardResponse extends Response<Boolean> {} |
||||
|
||||
public static class SignersBlockResponse extends Response<List<Address>> {} |
||||
|
||||
public static class ProposalsResponse extends Response<Map<Address, Boolean>> {} |
||||
|
||||
public Request<?, AddAccountsToWhitelistResponse> addAccountsToWhitelist( |
||||
final List<String> accounts) { |
||||
return new Request<>( |
||||
"perm_addAccountsToWhitelist", |
||||
Collections.singletonList(accounts), |
||||
web3jService, |
||||
AddAccountsToWhitelistResponse.class); |
||||
} |
||||
|
||||
public Request<?, RemoveAccountsFromWhitelistResponse> removeAccountsFromWhitelist( |
||||
final List<String> accounts) { |
||||
return new Request<>( |
||||
"perm_removeAccountsFromWhitelist", |
||||
Collections.singletonList(accounts), |
||||
web3jService, |
||||
RemoveAccountsFromWhitelistResponse.class); |
||||
} |
||||
|
||||
public Request<?, GetAccountsWhitelistResponse> getAccountsWhitelist() { |
||||
return new Request<>( |
||||
"perm_getAccountsWhitelist", null, web3jService, GetAccountsWhitelistResponse.class); |
||||
} |
||||
|
||||
public static class AddAccountsToWhitelistResponse extends Response<Boolean> {} |
||||
|
||||
public static class RemoveAccountsFromWhitelistResponse extends Response<Boolean> {} |
||||
|
||||
public static class GetAccountsWhitelistResponse extends Response<List<String>> {} |
||||
|
||||
public Request<?, AddNodeResponse> addNodesToWhitelist(final List<String> enodeList) { |
||||
return new Request<>( |
||||
"perm_addNodesToWhitelist", |
||||
Collections.singletonList(enodeList), |
||||
web3jService, |
||||
AddNodeResponse.class); |
||||
} |
||||
|
||||
public Request<?, RemoveNodeResponse> removeNodesFromWhitelist(final List<String> enodeList) { |
||||
return new Request<>( |
||||
"perm_removeNodesFromWhitelist", |
||||
Collections.singletonList(enodeList), |
||||
web3jService, |
||||
RemoveNodeResponse.class); |
||||
} |
||||
|
||||
public Request<?, GetNodesWhitelistResponse> getNodesWhitelist() { |
||||
return new Request<>( |
||||
"perm_getNodesWhitelist", Lists.emptyList(), web3jService, GetNodesWhitelistResponse.class); |
||||
} |
||||
|
||||
public static class AddNodeResponse extends Response<Boolean> {} |
||||
|
||||
public static class RemoveNodeResponse extends Response<Boolean> {} |
||||
|
||||
public static class GetNodesWhitelistResponse extends Response<List<String>> {} |
||||
|
||||
public static class AdminAddPeerResponse extends Response<Boolean> {} |
||||
|
||||
public Request<?, AdminAddPeerResponse> adminAddPeer(final String enodeAddress) { |
||||
return new Request<>( |
||||
"admin_addPeer", |
||||
Collections.singletonList(enodeAddress), |
||||
web3jService, |
||||
AdminAddPeerResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,79 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.AddAccountsToWhitelistResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.AddNodeResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.GetAccountsWhitelistResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.GetNodesWhitelistResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.RemoveAccountsFromWhitelistResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.RemoveNodeResponse; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.assertj.core.util.Lists; |
||||
import org.web3j.protocol.Web3jService; |
||||
import org.web3j.protocol.core.Request; |
||||
|
||||
public class PermissioningJsonRpcRequestFactory { |
||||
private final Web3jService web3jService; |
||||
|
||||
public PermissioningJsonRpcRequestFactory(final Web3jService web3jService) { |
||||
this.web3jService = web3jService; |
||||
} |
||||
|
||||
public Request<?, AddNodeResponse> addNodesToWhitelist(final List<String> enodeList) { |
||||
return new Request<>( |
||||
"perm_addNodesToWhitelist", |
||||
Collections.singletonList(enodeList), |
||||
web3jService, |
||||
AddNodeResponse.class); |
||||
} |
||||
|
||||
public Request<?, RemoveNodeResponse> removeNodesFromWhitelist(final List<String> enodeList) { |
||||
return new Request<>( |
||||
"perm_removeNodesFromWhitelist", |
||||
Collections.singletonList(enodeList), |
||||
web3jService, |
||||
RemoveNodeResponse.class); |
||||
} |
||||
|
||||
public Request<?, GetNodesWhitelistResponse> getNodesWhitelist() { |
||||
return new Request<>( |
||||
"perm_getNodesWhitelist", Lists.emptyList(), web3jService, GetNodesWhitelistResponse.class); |
||||
} |
||||
|
||||
public Request<?, GetAccountsWhitelistResponse> getAccountsWhitelist() { |
||||
return new Request<>( |
||||
"perm_getAccountsWhitelist", null, web3jService, GetAccountsWhitelistResponse.class); |
||||
} |
||||
|
||||
public Request<?, AddAccountsToWhitelistResponse> addAccountsToWhitelist( |
||||
final List<String> accounts) { |
||||
return new Request<>( |
||||
"perm_addAccountsToWhitelist", |
||||
Collections.singletonList(accounts), |
||||
web3jService, |
||||
AddAccountsToWhitelistResponse.class); |
||||
} |
||||
|
||||
public Request<?, RemoveAccountsFromWhitelistResponse> removeAccountsFromWhitelist( |
||||
final List<String> accounts) { |
||||
return new Request<>( |
||||
"perm_removeAccountsFromWhitelist", |
||||
Collections.singletonList(accounts), |
||||
web3jService, |
||||
RemoveAccountsFromWhitelistResponse.class); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.web3j.protocol.core.Response; |
||||
|
||||
public class ResponseTypes { |
||||
public static class ProposeResponse extends Response<Boolean> {} |
||||
|
||||
public static class DiscardResponse extends Response<Boolean> {} |
||||
|
||||
public static class SignersBlockResponse extends Response<List<Address>> {} |
||||
|
||||
public static class ProposalsResponse extends Response<Map<Address, Boolean>> {} |
||||
|
||||
public static class AddAccountsToWhitelistResponse extends Response<Boolean> {} |
||||
|
||||
public static class RemoveAccountsFromWhitelistResponse extends Response<Boolean> {} |
||||
|
||||
public static class GetAccountsWhitelistResponse extends Response<List<String>> {} |
||||
|
||||
public static class AddNodeResponse extends Response<Boolean> {} |
||||
|
||||
public static class RemoveNodeResponse extends Response<Boolean> {} |
||||
|
||||
public static class GetNodesWhitelistResponse extends Response<List<String>> {} |
||||
} |
@ -0,0 +1,41 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.DiscardResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class IbftDiscard implements Transaction<Boolean> { |
||||
private final String address; |
||||
|
||||
public IbftDiscard(final String address) { |
||||
this.address = address; |
||||
} |
||||
|
||||
@Override |
||||
public Boolean execute(final JsonRequestFactories node) { |
||||
try { |
||||
final DiscardResponse result = node.ibft().ibftDiscard(address).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.SignersBlockResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
public class IbftGetValidators implements Transaction<List<Address>> { |
||||
private final String blockNumber; |
||||
|
||||
public IbftGetValidators(final String blockNumber) { |
||||
this.blockNumber = blockNumber; |
||||
} |
||||
|
||||
@Override |
||||
public List<Address> execute(final JsonRequestFactories node) { |
||||
try { |
||||
final SignersBlockResponse result = node.ibft().ibftGetValidators(blockNumber).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.SignersBlockResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
|
||||
public class IbftGetValidatorsAtHash implements Transaction<List<Address>> { |
||||
private final Hash hash; |
||||
|
||||
public IbftGetValidatorsAtHash(final Hash hash) { |
||||
this.hash = hash; |
||||
} |
||||
|
||||
@Override |
||||
public List<Address> execute(final JsonRequestFactories node) { |
||||
try { |
||||
final SignersBlockResponse result = node.ibft().ibftGetSignersAtHash(hash).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposalsResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
public class IbftProposals implements Transaction<Map<Address, Boolean>> { |
||||
|
||||
@Override |
||||
public Map<Address, Boolean> execute(final JsonRequestFactories node) { |
||||
try { |
||||
final ProposalsResponse result = node.ibft().ibftProposals().send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.JsonRequestFactories; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ResponseTypes.ProposeResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class IbftPropose implements Transaction<Boolean> { |
||||
private final String address; |
||||
private final boolean auth; |
||||
|
||||
public IbftPropose(final String address, final boolean auth) { |
||||
this.address = address; |
||||
this.auth = auth; |
||||
} |
||||
|
||||
@Override |
||||
public Boolean execute(final JsonRequestFactories node) { |
||||
try { |
||||
final ProposeResponse result = node.ibft().ibftPropose(address, auth).send(); |
||||
assertThat(result).isNotNull(); |
||||
assertThat(result.hasError()).isFalse(); |
||||
return result.getResult(); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
public class IbftTransactions { |
||||
public static final String LATEST = "latest"; |
||||
|
||||
public IbftPropose createRemoveProposal(final PantheonNode node) { |
||||
return propose(node.getAddress().toString(), false); |
||||
} |
||||
|
||||
public IbftPropose createAddProposal(final PantheonNode node) { |
||||
return propose(node.getAddress().toString(), true); |
||||
} |
||||
|
||||
private IbftPropose propose(final String address, final boolean auth) { |
||||
return new IbftPropose(address, auth); |
||||
} |
||||
|
||||
public IbftProposals createProposals() { |
||||
return new IbftProposals(); |
||||
} |
||||
|
||||
public IbftGetValidators createGetValidators(final String blockNumber) { |
||||
return new IbftGetValidators(blockNumber); |
||||
} |
||||
|
||||
public IbftGetValidatorsAtHash createGetValidatorsAtHash(final Hash blockHash) { |
||||
return new IbftGetValidatorsAtHash(blockHash); |
||||
} |
||||
|
||||
public IbftDiscard createDiscardProposal(final PantheonNode node) { |
||||
return new IbftDiscard(node.getAddress().toString()); |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils.waitFor; |
||||
import static tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions.LATEST; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.ibft.IbftTransactions; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class WaitUntilValidatorsChanged implements WaitCondition { |
||||
|
||||
private final IbftTransactions ibft; |
||||
private final List<Address> initialSigners; |
||||
|
||||
public WaitUntilValidatorsChanged( |
||||
final List<Address> initialSigners, final IbftTransactions ibft) { |
||||
this.initialSigners = initialSigners; |
||||
this.ibft = ibft; |
||||
} |
||||
|
||||
@Override |
||||
public void waitUntil(final Node node) { |
||||
waitFor( |
||||
60, |
||||
() -> |
||||
assertThat(node.execute(ibft.createGetValidators(LATEST))) |
||||
.isNotEqualTo(initialSigners)); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.ibft; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class IbftDiscardRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldDiscardVotes() throws IOException { |
||||
final String[] validators = {"validator1", "validator2"}; |
||||
final PantheonNode validator1 = pantheon.createIbftNodeWithValidators("validator1", validators); |
||||
final PantheonNode validator2 = pantheon.createIbftNodeWithValidators("validator2", validators); |
||||
final PantheonNode validator3 = pantheon.createIbftNodeWithValidators("validator3", validators); |
||||
cluster.start(validator1, validator2, validator3); |
||||
|
||||
validator1.execute(ibftTransactions.createRemoveProposal(validator2)); |
||||
validator1.execute(ibftTransactions.createAddProposal(validator3)); |
||||
|
||||
validator2.execute(ibftTransactions.createRemoveProposal(validator2)); |
||||
validator2.execute(ibftTransactions.createAddProposal(validator3)); |
||||
|
||||
validator1.execute(ibftTransactions.createDiscardProposal(validator2)); |
||||
validator1.execute(ibftTransactions.createDiscardProposal(validator3)); |
||||
|
||||
validator1.waitUntil(wait.chainHeadHasProgressed(validator1, 2)); |
||||
|
||||
cluster.verify(ibft.validatorsEqual(validator1, validator2)); |
||||
validator1.verify(ibft.noProposals()); |
||||
validator2.verify( |
||||
ibft.pendingVotesEqual().removeProposal(validator2).addProposal(validator3).build()); |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
/* |
||||
* Copyright 2018 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.ibft; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class IbftProposalRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void shouldReturnProposals() throws IOException { |
||||
final String[] validators = {"validator1", "validator2", "validator3"}; |
||||
final PantheonNode validator1 = pantheon.createIbftNodeWithValidators("validator1", validators); |
||||
final PantheonNode validator2 = pantheon.createIbftNodeWithValidators("validator2", validators); |
||||
final PantheonNode validator3 = pantheon.createIbftNodeWithValidators("validator3", validators); |
||||
cluster.start(validator1, validator2, validator3); |
||||
|
||||
cluster.verify(ibft.noProposals()); |
||||
validator1.execute(ibftTransactions.createAddProposal(validator3)); |
||||
validator1.execute(ibftTransactions.createRemoveProposal(validator2)); |
||||
validator2.execute(ibftTransactions.createRemoveProposal(validator3)); |
||||
|
||||
validator1.verify( |
||||
ibft.pendingVotesEqual().addProposal(validator3).removeProposal(validator2).build()); |
||||
validator2.verify(ibft.pendingVotesEqual().removeProposal(validator3).build()); |
||||
validator3.verify(ibft.noProposals()); |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
/* |
||||
* Copyright 2019 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.ibft; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition.WaitCondition; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
// These tests prove the ibft_proposeValidatorVote and ibft_getValidatorsByBlockNumber (implicitly)
|
||||
// JSON RPC calls.
|
||||
public class IbftProposeRpcAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
@Test |
||||
public void validatorsCanBeAddedAndThenRemoved() throws IOException { |
||||
final String[] validators = {"validator1", "validator2", "validator3"}; |
||||
final PantheonNode validator1 = pantheon.createIbftNodeWithValidators("validator1", validators); |
||||
final PantheonNode validator2 = pantheon.createIbftNodeWithValidators("validator2", validators); |
||||
final PantheonNode validator3 = pantheon.createIbftNodeWithValidators("validator3", validators); |
||||
final PantheonNode nonValidatorNode = |
||||
pantheon.createIbftNodeWithValidators("non-validator", validators); |
||||
cluster.start(validator1, validator2, validator3, nonValidatorNode); |
||||
|
||||
cluster.verify(ibft.validatorsEqual(validator1, validator2, validator3)); |
||||
final WaitCondition addedCondition = wait.ibftValidatorsChanged(validator1); |
||||
validator1.execute(ibftTransactions.createAddProposal(nonValidatorNode)); |
||||
validator2.execute(ibftTransactions.createAddProposal(nonValidatorNode)); |
||||
|
||||
cluster.waitUntil(addedCondition); |
||||
cluster.verify(ibft.validatorsEqual(validator1, validator2, validator3, nonValidatorNode)); |
||||
|
||||
final WaitCondition removedCondition = wait.ibftValidatorsChanged(validator1); |
||||
validator2.execute(ibftTransactions.createRemoveProposal(nonValidatorNode)); |
||||
validator3.execute(ibftTransactions.createRemoveProposal(nonValidatorNode)); |
||||
nonValidatorNode.execute(ibftTransactions.createRemoveProposal(nonValidatorNode)); |
||||
cluster.waitUntil(removedCondition); |
||||
cluster.verify(ibft.validatorsEqual(validator1, validator2, validator3)); |
||||
} |
||||
} |
Loading…
Reference in new issue