use super::{
scheme::Scheme,
types::{Certificate, Vote},
};
use commonware_codec::MaxEncodeSize;
use commonware_cryptography::Digest;
use commonware_resolver::p2p::max_message_size;
use commonware_utils::sequence::U64;
pub fn max_payload_size<S: Scheme<D>, D: Digest>(participants: u32) -> usize {
let certificate = Certificate::<S, D>::max_encode_size(participants);
let resolver = max_message_size::<U64>(certificate);
Vote::<S, D>::MAX_ENCODE_SIZE.max(certificate).max(resolver)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
simplex::{
scheme::{bls12381_multisig, bls12381_threshold, ed25519, secp256r1},
types::{
Certificate, Finalization, Finalize, Notarization, Notarize, Nullification,
Nullify, Proposal, Vote,
},
},
types::{Epoch, Participant, Round, View},
};
use commonware_codec::{Encode, FixedSize, MaxEncodeSize};
use commonware_cryptography::{
bls12381::primitives::variant::{MinPk, MinSig},
certificate::{Attestation, mocks::Fixture},
sha256::Digest as Sha256Digest,
};
use commonware_math::algebra::Random;
use commonware_parallel::Sequential;
use commonware_resolver::p2p::{MAX_RESPONSE_OVERHEAD, REQUEST_OVERHEAD};
use commonware_utils::{non_empty, test_rng};
const NAMESPACE: &[u8] = b"_COMMONWARE_CONSENSUS_SIMPLEX_LIMITS";
const PARTICIPANTS: [u32; 4] = [1, 4, 127, 128];
fn check<S: Scheme<Sha256Digest>>(fixture: Fixture<S>) {
let schemes = fixture.schemes;
let participants = u32::try_from(schemes.len()).unwrap();
let bound = max_payload_size::<S, Sha256Digest>(participants);
let round = Round::new(Epoch::new(u64::MAX), View::new(u64::MAX));
let proposal = Proposal::new(
round,
View::new(u64::MAX - 1),
Sha256Digest::random(test_rng()),
);
let widest = |attestation: &Attestation<S>| Attestation::<S> {
signer: Participant::new(u32::MAX),
signature: attestation.signature.clone(),
};
let notarizes: Vec<_> = schemes
.iter()
.map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap())
.collect();
let nullifies: Vec<_> = schemes
.iter()
.map(|scheme| Nullify::sign::<Sha256Digest>(scheme, round).unwrap())
.collect();
let finalizes: Vec<_> = schemes
.iter()
.map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap())
.collect();
let votes = [
Vote::Notarize(Notarize {
proposal: proposal.clone(),
attestation: widest(¬arizes[0].attestation),
}),
Vote::Nullify(Nullify {
round,
attestation: widest(&nullifies[0].attestation),
}),
Vote::Finalize(Finalize {
proposal,
attestation: widest(&finalizes[0].attestation),
}),
];
let sizes = votes.map(|vote| vote.encode().len());
let vote = sizes.into_iter().max().unwrap();
assert_eq!(vote, Vote::<S, Sha256Digest>::MAX_ENCODE_SIZE);
let certificates = [
Certificate::Notarization(
Notarization::from_notarizes(&schemes[0], non_empty![@¬arizes], &Sequential)
.unwrap(),
),
Certificate::Nullification(
Nullification::from_nullifies(&schemes[0], non_empty![@&nullifies], &Sequential)
.unwrap(),
),
Certificate::Finalization(
Finalization::from_finalizes(&schemes[0], non_empty![@&finalizes], &Sequential)
.unwrap(),
),
];
let sizes = certificates.map(|certificate| certificate.encode().len());
let encoded_certificate = sizes.into_iter().max().unwrap();
let certificate = Certificate::<S, Sha256Digest>::max_encode_size(participants);
assert!(encoded_certificate <= certificate);
assert_eq!(
certificate,
u8::SIZE
+ Proposal::<Sha256Digest>::MAX_ENCODE_SIZE
+ S::max_certificate_size(participants)
);
let request = U64::from(u64::MAX).encode().len() + REQUEST_OVERHEAD;
let response = certificate + MAX_RESPONSE_OVERHEAD;
assert!(vote < response && request < response);
assert!(encoded_certificate + MAX_RESPONSE_OVERHEAD <= bound);
assert_eq!(bound, response);
}
#[test]
fn widest_encodings_ed25519() {
for participants in PARTICIPANTS {
check(ed25519::fixture(&mut test_rng(), NAMESPACE, participants));
}
}
#[test]
fn widest_encodings_secp256r1() {
for participants in PARTICIPANTS {
check(secp256r1::fixture(&mut test_rng(), NAMESPACE, participants));
}
}
#[test]
fn widest_encodings_bls12381_multisig() {
for participants in PARTICIPANTS {
check(bls12381_multisig::fixture::<MinPk, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
check(bls12381_multisig::fixture::<MinSig, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
}
}
#[test]
fn widest_encodings_bls12381_threshold() {
for participants in [4, 33] {
check(bls12381_threshold::standard::fixture::<MinPk, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
check(bls12381_threshold::standard::fixture::<MinSig, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
check(bls12381_threshold::vrf::fixture::<MinPk, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
check(bls12381_threshold::vrf::fixture::<MinSig, _>(
&mut test_rng(),
NAMESPACE,
participants,
));
}
}
}