#![allow(clippy::integer_arithmetic)]
use crate::{
block::Block,
block_data::BlockData,
common::{Payload, Round},
quorum_cert::QuorumCert,
vote_data::VoteData,
};
use aptos_crypto::{
bls12381,
ed25519::Ed25519PrivateKey,
hash::{CryptoHash, HashValue},
PrivateKey, Uniform,
};
use aptos_types::{
account_address::AccountAddress,
block_info::BlockInfo,
ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
test_helpers::transaction_test_helpers::get_test_signed_txn,
validator_signer::{proptests, ValidatorSigner},
};
use proptest::prelude::*;
use std::collections::BTreeMap;
type LinearizedBlockForest = Vec<Block>;
prop_compose! {
pub fn new_proposal(
_ancestor_id: HashValue,
round_strategy: impl Strategy<Value = Round>,
signer_strategy: impl Strategy<Value = ValidatorSigner>,
parent_qc: QuorumCert,
)(
round in round_strategy,
signer in signer_strategy,
parent_qc in Just(parent_qc)
) -> Block {
Block::new_proposal(
Payload::new_empty(),
round,
aptos_infallible::duration_since_epoch().as_micros() as u64,
parent_qc,
&signer,
Vec::new(),
)
}
}
pub fn genesis_strategy() -> impl Strategy<Value = Block> {
Just(Block::make_genesis_block())
}
prop_compose! {
pub fn unmoored_block(ancestor_id_strategy: impl Strategy<Value = HashValue>)(
ancestor_id in ancestor_id_strategy,
)(
block in new_proposal(
ancestor_id,
Round::arbitrary(),
proptests::arb_signer(),
certificate_for_genesis(),
)
) -> Block {
block
}
}
pub fn leaf_strategy() -> impl Strategy<Value = Block> {
genesis_strategy().boxed()
}
prop_compose! {
pub fn fake_id(block_strategy: impl Strategy<Value = Block>)
(fake_id in HashValue::arbitrary(),
block in block_strategy) -> Block {
Block {
id: fake_id,
block_data: BlockData::new_proposal(
block.payload().unwrap().clone(),
block.author().unwrap(),
(*block.block_data().failed_authors().unwrap()).clone(),
block.round(),
aptos_infallible::duration_since_epoch().as_micros() as u64,
block.quorum_cert().clone(),
),
signature: Some(block.signature().unwrap().clone()),
}
}
}
prop_compose! {
fn bigger_round(initial_round: Round)(
increment in 2..8,
initial_round in Just(initial_round),
) -> Round {
initial_round + increment as u64
}
}
pub fn some_round(initial_round: Round) -> impl Strategy<Value = Round> {
prop_oneof![
9 => Just(1 + initial_round),
1 => bigger_round(initial_round),
]
}
prop_compose! {
fn child(
signer_strategy: impl Strategy<Value = ValidatorSigner>,
block_forest_strategy: impl Strategy<Value = LinearizedBlockForest>,
)(
signer in signer_strategy,
(forest_vec, parent_idx, qc_idx) in block_forest_strategy
.prop_flat_map(|forest_vec| {
let len = forest_vec.len();
(Just(forest_vec), 0..len)
})
.prop_flat_map(|(forest_vec, parent_idx)| {
(Just(forest_vec), Just(parent_idx), 0..=parent_idx)
}),
)( block in new_proposal(
forest_vec[qc_idx].id(),
some_round(forest_vec[parent_idx].round()),
Just(signer),
forest_vec[qc_idx].quorum_cert().clone(),
), mut forest in Just(forest_vec),
) -> LinearizedBlockForest {
forest.push(block);
forest
}
}
fn block_forest_from_keys(
depth: u32,
keypairs: Vec<bls12381::PrivateKey>,
) -> impl Strategy<Value = LinearizedBlockForest> {
let leaf = leaf_strategy().prop_map(|block| vec![block]);
leaf.prop_recursive(depth, depth, 2, move |inner| {
child(proptests::mostly_in_keypair_pool(keypairs.clone()), inner)
})
}
pub fn block_forest_and_its_keys(
quorum_size: usize,
depth: u32,
) -> impl Strategy<Value = (Vec<bls12381::PrivateKey>, LinearizedBlockForest)> {
proptest::collection::vec(proptests::arb_signing_key(), quorum_size).prop_flat_map(
move |private_key| {
(
Just(private_key.clone()),
block_forest_from_keys(depth, private_key),
)
},
)
}
pub fn placeholder_ledger_info() -> LedgerInfo {
LedgerInfo::new(BlockInfo::empty(), HashValue::zero())
}
pub fn gen_test_certificate(
signers: Vec<&ValidatorSigner>,
block: BlockInfo,
parent_block: BlockInfo,
committed_block: Option<BlockInfo>,
) -> QuorumCert {
let vote_data = VoteData::new(block, parent_block);
let ledger_info = match committed_block {
Some(info) => LedgerInfo::new(info, vote_data.hash()),
None => {
let mut placeholder = placeholder_ledger_info();
placeholder.set_consensus_data_hash(vote_data.hash());
placeholder
}
};
let mut signatures = BTreeMap::new();
for signer in signers {
let li_sig = signer.sign(&ledger_info);
signatures.insert(signer.author(), li_sig);
}
QuorumCert::new(
vote_data,
LedgerInfoWithSignatures::new(ledger_info, signatures),
)
}
pub fn placeholder_certificate_for_block(
signers: Vec<&ValidatorSigner>,
certified_block_id: HashValue,
certified_block_round: u64,
certified_parent_block_id: HashValue,
certified_parent_block_round: u64,
) -> QuorumCert {
let genesis_ledger_info = LedgerInfo::mock_genesis(None);
let vote_data = VoteData::new(
BlockInfo::new(
genesis_ledger_info.epoch() + 1,
certified_block_round,
certified_block_id,
genesis_ledger_info.transaction_accumulator_hash(),
genesis_ledger_info.version(),
genesis_ledger_info.timestamp_usecs(),
None,
),
BlockInfo::new(
genesis_ledger_info.epoch() + 1,
certified_parent_block_round,
certified_parent_block_id,
genesis_ledger_info.transaction_accumulator_hash(),
genesis_ledger_info.version(),
genesis_ledger_info.timestamp_usecs(),
None,
),
);
let mut ledger_info_placeholder = placeholder_ledger_info();
ledger_info_placeholder.set_consensus_data_hash(vote_data.hash());
let mut signatures = BTreeMap::new();
for signer in signers {
let li_sig = signer.sign(&ledger_info_placeholder);
signatures.insert(signer.author(), li_sig);
}
QuorumCert::new(
vote_data,
LedgerInfoWithSignatures::new(ledger_info_placeholder, signatures),
)
}
pub fn certificate_for_genesis() -> QuorumCert {
let ledger_info = LedgerInfo::mock_genesis(None);
QuorumCert::certificate_for_genesis_from_ledger_info(
&ledger_info,
Block::make_genesis_block_from_ledger_info(&ledger_info).id(),
)
}
pub fn random_payload(count: usize) -> Payload {
let address = AccountAddress::random();
let private_key = Ed25519PrivateKey::generate_for_testing();
let public_key = private_key.public_key();
Payload::DirectMempool(
(0..count)
.map(|i| get_test_signed_txn(address, i as u64, &private_key, public_key.clone(), None))
.collect(),
)
}