use exonum::{
blockchain::ConsensusConfig, crypto::Hash, helpers::ValidatorId,
runtime::SUPERVISOR_INSTANCE_ID,
};
use exonum_merkledb::ObjectHash;
use exonum_testkit::{ApiKind, TestKit, TestKitApi};
use crate::utils::*;
use exonum_supervisor::{ConfigProposalWithHash, ConfigPropose, ConfigVote, SupervisorInterface};
async fn actual_consensus_config(api: &TestKitApi) -> ConsensusConfig {
api.public(ApiKind::Service("supervisor"))
.get("consensus-config")
.await
.unwrap()
}
async fn current_config_proposal(api: &TestKitApi) -> Option<ConfigProposalWithHash> {
api.public(ApiKind::Service("supervisor"))
.get("config-proposal")
.await
.unwrap()
}
pub async fn create_proposal(api: &TestKitApi, proposal: ConfigPropose) -> Hash {
let hash: Hash = api
.private(ApiKind::Service("supervisor"))
.query(&proposal)
.post("propose-config")
.await
.unwrap();
hash
}
async fn confirm_config(api: &TestKitApi, confirm: ConfigVote) -> Hash {
let hash: Hash = api
.private(ApiKind::Service("supervisor"))
.query(&confirm)
.post("confirm-config")
.await
.unwrap();
hash
}
async fn configuration_number(api: &TestKitApi) -> u64 {
api.private(ApiKind::Service("supervisor"))
.get("configuration-number")
.await
.unwrap()
}
#[tokio::test]
async fn test_consensus_config_api() {
let mut testkit = testkit_with_supervisor(1);
let consensus_config = actual_consensus_config(&testkit.api()).await;
assert_eq!(testkit.consensus_config(), consensus_config);
}
#[tokio::test]
async fn test_config_proposal_api() {
let mut testkit = testkit_with_supervisor(1);
assert_eq!(current_config_proposal(&testkit.api()).await, None);
}
#[tokio::test]
async fn test_confirm_proposal_with_api() {
let mut testkit = testkit_with_supervisor(2);
let consensus_proposal = consensus_config_propose_first_variant(&testkit);
let config_proposal = ConfigProposeBuilder::new(CFG_CHANGE_HEIGHT)
.extend_consensus_config_propose(consensus_proposal.clone())
.build();
testkit
.create_block_with_transaction(sign_config_propose_transaction(
&testkit,
config_proposal.clone(),
ValidatorId(1),
))
.transactions[0]
.status()
.expect("Transaction with change propose discarded.");
let pending_config = current_config_proposal(&testkit.api())
.await
.expect("Config proposal was not registered.");
let proposal_hash = config_proposal.object_hash();
assert_eq!(proposal_hash, pending_config.propose_hash);
assert_eq!(config_proposal, pending_config.config_propose);
let tx_hash =
confirm_config(&testkit.api(), ConfigVote::new(pending_config.propose_hash)).await;
let block = testkit.create_block();
block[tx_hash].status().unwrap();
testkit.create_blocks_until(CFG_CHANGE_HEIGHT.next());
let consensus_config = actual_consensus_config(&testkit.api()).await;
assert_eq!(consensus_proposal, consensus_config);
}
#[tokio::test]
async fn test_send_proposal_with_api() {
let mut testkit = testkit_with_supervisor(2);
let consensus_proposal = consensus_config_propose_first_variant(&testkit);
let config_proposal = ConfigProposeBuilder::new(CFG_CHANGE_HEIGHT)
.extend_consensus_config_propose(consensus_proposal.clone())
.build();
let hash = create_proposal(&testkit.api(), config_proposal.clone()).await;
let block = testkit.create_block();
block[hash].status().unwrap();
let pending_config = current_config_proposal(&testkit.api())
.await
.expect("Config proposal was not registered.");
let proposal_hash = config_proposal.object_hash();
assert_eq!(proposal_hash, pending_config.propose_hash);
assert_eq!(config_proposal, pending_config.config_propose);
let keypair = testkit.network().validators()[1].service_keypair();
let signed_confirm = keypair.confirm_config_change(
SUPERVISOR_INSTANCE_ID,
ConfigVote::new(pending_config.propose_hash),
);
testkit
.create_block_with_transaction(signed_confirm)
.transactions[0]
.status()
.expect("Transaction with confirmations discarded.");
testkit.create_blocks_until(CFG_CHANGE_HEIGHT.next());
let consensus_config = actual_consensus_config(&testkit.api()).await;
assert_eq!(consensus_proposal, consensus_config);
}
async fn apply_config(testkit: &mut TestKit) {
let consensus_proposal = consensus_config_propose_first_variant(testkit);
let config_proposal = ConfigProposeBuilder::new(CFG_CHANGE_HEIGHT)
.extend_consensus_config_propose(consensus_proposal)
.build();
create_proposal(&testkit.api(), config_proposal).await;
testkit.create_block();
let pending_config = current_config_proposal(&testkit.api())
.await
.expect("Config proposal was not registered.");
let keypair = testkit.network().validators()[1].service_keypair();
let signed_confirm = keypair.confirm_config_change(
SUPERVISOR_INSTANCE_ID,
ConfigVote::new(pending_config.propose_hash),
);
testkit
.create_block_with_transaction(signed_confirm)
.transactions[0]
.status()
.expect("Transaction with confirmations discarded.");
testkit.create_blocks_until(CFG_CHANGE_HEIGHT.next());
}
#[tokio::test]
async fn test_configuration_number() {
let mut testkit = testkit_with_supervisor(2);
let initial_configuration_number = configuration_number(&testkit.api()).await;
assert_eq!(initial_configuration_number, 0);
apply_config(&mut testkit).await;
let new_configuration_number = configuration_number(&testkit.api()).await;
assert_eq!(new_configuration_number, 1);
}