2018-12-07 19:16:27 -08:00
|
|
|
use crate::contact_info::ContactInfo;
|
2019-07-30 15:43:17 -07:00
|
|
|
use bincode::{serialize, serialized_size};
|
2020-02-18 08:46:11 -08:00
|
|
|
use solana_sdk::{
|
|
|
|
clock::Slot,
|
2020-02-20 11:46:13 -08:00
|
|
|
hash::Hash,
|
2020-02-18 08:46:11 -08:00
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{Keypair, Signable, Signature},
|
|
|
|
transaction::Transaction,
|
|
|
|
};
|
|
|
|
use std::{
|
|
|
|
borrow::{Borrow, Cow},
|
|
|
|
collections::{BTreeSet, HashSet},
|
|
|
|
fmt,
|
|
|
|
};
|
2018-11-15 13:23:26 -08:00
|
|
|
|
2019-11-04 16:19:54 -08:00
|
|
|
pub type VoteIndex = u8;
|
|
|
|
pub const MAX_VOTES: VoteIndex = 32;
|
|
|
|
|
2020-02-19 20:24:09 -08:00
|
|
|
pub type EpochSlotIndex = u8;
|
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
/// CrdsValue that is replicated across the cluster
|
2019-11-03 10:07:51 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
|
|
pub struct CrdsValue {
|
|
|
|
pub signature: Signature,
|
|
|
|
pub data: CrdsData,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Signable for CrdsValue {
|
|
|
|
fn pubkey(&self) -> Pubkey {
|
|
|
|
self.pubkey()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signable_data(&self) -> Cow<[u8]> {
|
|
|
|
Cow::Owned(serialize(&self.data).expect("failed to serialize CrdsData"))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_signature(&self) -> Signature {
|
|
|
|
self.signature
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_signature(&mut self, signature: Signature) {
|
|
|
|
self.signature = signature
|
|
|
|
}
|
2019-11-04 16:19:54 -08:00
|
|
|
|
|
|
|
fn verify(&self) -> bool {
|
|
|
|
let sig_check = self
|
|
|
|
.get_signature()
|
|
|
|
.verify(&self.pubkey().as_ref(), self.signable_data().borrow());
|
|
|
|
let data_check = match &self.data {
|
|
|
|
CrdsData::Vote(ix, _) => *ix < MAX_VOTES,
|
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
sig_check && data_check
|
|
|
|
}
|
2019-11-03 10:07:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// CrdsData that defines the different types of items CrdsValues can hold
|
2020-02-18 08:46:11 -08:00
|
|
|
/// * Merge Strategy - Latest wallclock is picked
|
2019-08-20 17:16:06 -07:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
2018-11-15 13:23:26 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
2019-11-03 10:07:51 -08:00
|
|
|
pub enum CrdsData {
|
2018-11-15 13:23:26 -08:00
|
|
|
ContactInfo(ContactInfo),
|
2019-11-04 16:19:54 -08:00
|
|
|
Vote(VoteIndex, Vote),
|
2020-02-19 20:24:09 -08:00
|
|
|
EpochSlots(EpochSlotIndex, EpochSlots),
|
2020-02-20 11:46:13 -08:00
|
|
|
SnapshotHash(SnapshotHash),
|
2020-02-19 20:24:09 -08:00
|
|
|
}
|
|
|
|
|
2020-02-20 09:48:39 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
|
|
pub enum CompressionType {
|
|
|
|
Uncompressed,
|
|
|
|
GZip,
|
|
|
|
BZip2,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for CompressionType {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Uncompressed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 20:24:09 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
|
|
|
|
pub struct EpochIncompleteSlots {
|
|
|
|
pub first: Slot,
|
2020-02-20 09:48:39 -08:00
|
|
|
pub compression: CompressionType,
|
2020-02-19 20:24:09 -08:00
|
|
|
pub compressed_list: Vec<u8>,
|
2019-05-08 13:50:32 -07:00
|
|
|
}
|
|
|
|
|
2020-02-20 11:46:13 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
|
|
pub struct SnapshotHash {
|
|
|
|
pub from: Pubkey,
|
|
|
|
pub hashes: Vec<(Slot, Hash)>,
|
|
|
|
pub wallclock: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SnapshotHash {
|
|
|
|
pub fn new(from: Pubkey, hashes: Vec<(Slot, Hash)>, wallclock: u64) -> Self {
|
|
|
|
Self {
|
|
|
|
from,
|
|
|
|
hashes,
|
|
|
|
wallclock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-08 13:50:32 -07:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
|
|
pub struct EpochSlots {
|
|
|
|
pub from: Pubkey,
|
2019-12-05 11:25:13 -08:00
|
|
|
pub root: Slot,
|
|
|
|
pub lowest: Slot,
|
|
|
|
pub slots: BTreeSet<Slot>,
|
2020-02-19 20:24:09 -08:00
|
|
|
pub stash: Vec<EpochIncompleteSlots>,
|
2019-05-08 13:50:32 -07:00
|
|
|
pub wallclock: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EpochSlots {
|
2019-12-05 11:25:13 -08:00
|
|
|
pub fn new(
|
|
|
|
from: Pubkey,
|
|
|
|
root: Slot,
|
|
|
|
lowest: Slot,
|
|
|
|
slots: BTreeSet<Slot>,
|
2020-02-19 20:24:09 -08:00
|
|
|
stash: Vec<EpochIncompleteSlots>,
|
2019-12-05 11:25:13 -08:00
|
|
|
wallclock: u64,
|
|
|
|
) -> Self {
|
2019-05-08 13:50:32 -07:00
|
|
|
Self {
|
|
|
|
from,
|
|
|
|
root,
|
2019-12-05 11:25:13 -08:00
|
|
|
lowest,
|
2019-05-08 13:50:32 -07:00
|
|
|
slots,
|
2020-02-17 12:39:30 -08:00
|
|
|
stash,
|
2019-05-08 13:50:32 -07:00
|
|
|
wallclock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
|
|
|
pub struct Vote {
|
2019-03-11 16:43:30 -07:00
|
|
|
pub from: Pubkey,
|
2018-11-15 13:23:26 -08:00
|
|
|
pub transaction: Transaction,
|
|
|
|
pub wallclock: u64,
|
|
|
|
}
|
|
|
|
|
2019-05-08 13:50:32 -07:00
|
|
|
impl Vote {
|
|
|
|
pub fn new(from: &Pubkey, transaction: Transaction, wallclock: u64) -> Self {
|
|
|
|
Self {
|
|
|
|
from: *from,
|
|
|
|
transaction,
|
|
|
|
wallclock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
/// Type of the replicated value
|
2018-12-01 12:00:30 -08:00
|
|
|
/// These are labels for values in a record that is associated with `Pubkey`
|
2018-11-15 13:23:26 -08:00
|
|
|
#[derive(PartialEq, Hash, Eq, Clone, Debug)]
|
|
|
|
pub enum CrdsValueLabel {
|
|
|
|
ContactInfo(Pubkey),
|
2019-11-04 16:19:54 -08:00
|
|
|
Vote(VoteIndex, Pubkey),
|
2019-05-08 13:50:32 -07:00
|
|
|
EpochSlots(Pubkey),
|
2020-02-20 11:46:13 -08:00
|
|
|
SnapshotHash(Pubkey),
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CrdsValueLabel {
|
2018-12-08 21:44:20 -08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2018-11-15 13:23:26 -08:00
|
|
|
match self {
|
|
|
|
CrdsValueLabel::ContactInfo(_) => write!(f, "ContactInfo({})", self.pubkey()),
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsValueLabel::Vote(ix, _) => write!(f, "Vote({}, {})", ix, self.pubkey()),
|
2019-05-08 13:50:32 -07:00
|
|
|
CrdsValueLabel::EpochSlots(_) => write!(f, "EpochSlots({})", self.pubkey()),
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsValueLabel::SnapshotHash(_) => write!(f, "SnapshotHash({})", self.pubkey()),
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CrdsValueLabel {
|
|
|
|
pub fn pubkey(&self) -> Pubkey {
|
|
|
|
match self {
|
|
|
|
CrdsValueLabel::ContactInfo(p) => *p,
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsValueLabel::Vote(_, p) => *p,
|
2019-05-08 13:50:32 -07:00
|
|
|
CrdsValueLabel::EpochSlots(p) => *p,
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsValueLabel::SnapshotHash(p) => *p,
|
2018-12-01 12:00:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
impl CrdsValue {
|
2019-11-03 10:07:51 -08:00
|
|
|
pub fn new_unsigned(data: CrdsData) -> Self {
|
|
|
|
Self {
|
|
|
|
signature: Signature::default(),
|
|
|
|
data,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_signed(data: CrdsData, keypair: &Keypair) -> Self {
|
|
|
|
let mut value = Self::new_unsigned(data);
|
|
|
|
value.sign(keypair);
|
|
|
|
value
|
|
|
|
}
|
2018-12-01 12:00:30 -08:00
|
|
|
/// Totally unsecure unverfiable wallclock of the node that generated this message
|
2018-11-15 13:23:26 -08:00
|
|
|
/// Latest wallclock is always picked.
|
|
|
|
/// This is used to time out push messages.
|
|
|
|
pub fn wallclock(&self) -> u64 {
|
2019-11-03 10:07:51 -08:00
|
|
|
match &self.data {
|
|
|
|
CrdsData::ContactInfo(contact_info) => contact_info.wallclock,
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsData::Vote(_, vote) => vote.wallclock,
|
2020-02-19 20:24:09 -08:00
|
|
|
CrdsData::EpochSlots(_, vote) => vote.wallclock,
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsData::SnapshotHash(hash) => hash.wallclock,
|
2019-11-03 10:07:51 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn pubkey(&self) -> Pubkey {
|
|
|
|
match &self.data {
|
|
|
|
CrdsData::ContactInfo(contact_info) => contact_info.id,
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsData::Vote(_, vote) => vote.from,
|
2020-02-19 20:24:09 -08:00
|
|
|
CrdsData::EpochSlots(_, slots) => slots.from,
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsData::SnapshotHash(hash) => hash.from,
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn label(&self) -> CrdsValueLabel {
|
2019-11-03 10:07:51 -08:00
|
|
|
match &self.data {
|
|
|
|
CrdsData::ContactInfo(_) => CrdsValueLabel::ContactInfo(self.pubkey()),
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsData::Vote(ix, _) => CrdsValueLabel::Vote(*ix, self.pubkey()),
|
2020-02-19 20:24:09 -08:00
|
|
|
CrdsData::EpochSlots(_, _) => CrdsValueLabel::EpochSlots(self.pubkey()),
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsData::SnapshotHash(_) => CrdsValueLabel::SnapshotHash(self.pubkey()),
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn contact_info(&self) -> Option<&ContactInfo> {
|
2019-11-03 10:07:51 -08:00
|
|
|
match &self.data {
|
|
|
|
CrdsData::ContactInfo(contact_info) => Some(contact_info),
|
2018-11-15 13:23:26 -08:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn vote(&self) -> Option<&Vote> {
|
2019-11-03 10:07:51 -08:00
|
|
|
match &self.data {
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsData::Vote(_, vote) => Some(vote),
|
2018-11-15 13:23:26 -08:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2019-11-04 16:19:54 -08:00
|
|
|
|
|
|
|
pub fn vote_index(&self) -> Option<VoteIndex> {
|
|
|
|
match &self.data {
|
|
|
|
CrdsData::Vote(ix, _) => Some(*ix),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-08 13:50:32 -07:00
|
|
|
pub fn epoch_slots(&self) -> Option<&EpochSlots> {
|
2019-11-03 10:07:51 -08:00
|
|
|
match &self.data {
|
2020-02-19 20:24:09 -08:00
|
|
|
CrdsData::EpochSlots(_, slots) => Some(slots),
|
2019-05-08 13:50:32 -07:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2020-02-20 11:46:13 -08:00
|
|
|
|
|
|
|
pub fn snapshot_hash(&self) -> Option<&SnapshotHash> {
|
|
|
|
match &self.data {
|
|
|
|
CrdsData::SnapshotHash(slots) => Some(slots),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
/// Return all the possible labels for a record identified by Pubkey.
|
2019-11-04 16:19:54 -08:00
|
|
|
pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> {
|
|
|
|
let mut labels = vec![
|
2019-03-09 19:28:43 -08:00
|
|
|
CrdsValueLabel::ContactInfo(*key),
|
2019-05-08 13:50:32 -07:00
|
|
|
CrdsValueLabel::EpochSlots(*key),
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsValueLabel::SnapshotHash(*key),
|
2019-11-04 16:19:54 -08:00
|
|
|
];
|
|
|
|
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
|
|
|
|
labels
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
2019-07-30 15:43:17 -07:00
|
|
|
|
|
|
|
/// Returns the size (in bytes) of a CrdsValue
|
|
|
|
pub fn size(&self) -> u64 {
|
|
|
|
serialized_size(&self).expect("unable to serialize contact info")
|
|
|
|
}
|
2019-11-04 16:19:54 -08:00
|
|
|
|
|
|
|
pub fn compute_vote_index(tower_index: usize, mut votes: Vec<&CrdsValue>) -> VoteIndex {
|
|
|
|
let mut available: HashSet<VoteIndex> = (0..MAX_VOTES).collect();
|
|
|
|
votes.iter().filter_map(|v| v.vote_index()).for_each(|ix| {
|
|
|
|
available.remove(&ix);
|
|
|
|
});
|
|
|
|
|
|
|
|
// free index
|
|
|
|
if !available.is_empty() {
|
|
|
|
return *available.iter().next().unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
assert!(votes.len() == MAX_VOTES as usize);
|
|
|
|
votes.sort_by_key(|v| v.vote().expect("all values must be votes").wallclock);
|
|
|
|
|
|
|
|
// If Tower is full, oldest removed first
|
|
|
|
if tower_index + 1 == MAX_VOTES as usize {
|
|
|
|
return votes[0].vote_index().expect("all values must be votes");
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Tower is not full, the early votes have expired
|
|
|
|
assert!(tower_index < MAX_VOTES as usize);
|
|
|
|
|
|
|
|
votes[tower_index]
|
|
|
|
.vote_index()
|
|
|
|
.expect("all values must be votes")
|
|
|
|
}
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
2018-12-01 12:00:30 -08:00
|
|
|
|
2018-11-15 13:23:26 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
2018-12-07 19:16:27 -08:00
|
|
|
use crate::contact_info::ContactInfo;
|
2019-05-23 03:50:41 -07:00
|
|
|
use bincode::deserialize;
|
2019-11-06 10:52:30 -08:00
|
|
|
use solana_perf::test_tx::test_tx;
|
2018-12-01 12:00:30 -08:00
|
|
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
|
|
|
use solana_sdk::timing::timestamp;
|
2018-11-15 13:23:26 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_labels() {
|
2020-02-20 11:46:13 -08:00
|
|
|
let mut hits = [false; 3 + MAX_VOTES as usize];
|
2018-11-15 13:23:26 -08:00
|
|
|
// this method should cover all the possible labels
|
2019-03-09 19:28:43 -08:00
|
|
|
for v in &CrdsValue::record_labels(&Pubkey::default()) {
|
2018-11-15 13:23:26 -08:00
|
|
|
match v {
|
|
|
|
CrdsValueLabel::ContactInfo(_) => hits[0] = true,
|
2019-11-04 16:19:54 -08:00
|
|
|
CrdsValueLabel::EpochSlots(_) => hits[1] = true,
|
2020-02-20 11:46:13 -08:00
|
|
|
CrdsValueLabel::SnapshotHash(_) => hits[2] = true,
|
|
|
|
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 3] = true,
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
assert!(hits.iter().all(|x| *x));
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_keys_and_values() {
|
2019-11-03 10:07:51 -08:00
|
|
|
let v = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::default()));
|
2018-11-15 13:23:26 -08:00
|
|
|
assert_eq!(v.wallclock(), 0);
|
|
|
|
let key = v.clone().contact_info().unwrap().id;
|
|
|
|
assert_eq!(v.label(), CrdsValueLabel::ContactInfo(key));
|
|
|
|
|
2019-11-04 16:19:54 -08:00
|
|
|
let v = CrdsValue::new_unsigned(CrdsData::Vote(
|
|
|
|
0,
|
|
|
|
Vote::new(&Pubkey::default(), test_tx(), 0),
|
|
|
|
));
|
2018-11-15 13:23:26 -08:00
|
|
|
assert_eq!(v.wallclock(), 0);
|
2019-03-11 16:43:30 -07:00
|
|
|
let key = v.clone().vote().unwrap().from;
|
2019-11-04 16:19:54 -08:00
|
|
|
assert_eq!(v.label(), CrdsValueLabel::Vote(0, key));
|
2019-05-08 13:50:32 -07:00
|
|
|
|
2020-02-19 20:24:09 -08:00
|
|
|
let v = CrdsValue::new_unsigned(CrdsData::EpochSlots(
|
2019-12-05 11:25:13 -08:00
|
|
|
0,
|
2020-02-19 20:24:09 -08:00
|
|
|
EpochSlots::new(Pubkey::default(), 0, 0, BTreeSet::new(), vec![], 0),
|
|
|
|
));
|
2019-05-08 13:50:32 -07:00
|
|
|
assert_eq!(v.wallclock(), 0);
|
|
|
|
let key = v.clone().epoch_slots().unwrap().from;
|
|
|
|
assert_eq!(v.label(), CrdsValueLabel::EpochSlots(key));
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|
2019-11-04 16:19:54 -08:00
|
|
|
|
2018-12-01 12:00:30 -08:00
|
|
|
#[test]
|
|
|
|
fn test_signature() {
|
|
|
|
let keypair = Keypair::new();
|
2019-03-11 16:43:30 -07:00
|
|
|
let wrong_keypair = Keypair::new();
|
2019-11-03 10:07:51 -08:00
|
|
|
let mut v = CrdsValue::new_unsigned(CrdsData::ContactInfo(ContactInfo::new_localhost(
|
|
|
|
&keypair.pubkey(),
|
|
|
|
timestamp(),
|
|
|
|
)));
|
2019-03-11 16:43:30 -07:00
|
|
|
verify_signatures(&mut v, &keypair, &wrong_keypair);
|
2019-11-04 16:19:54 -08:00
|
|
|
v = CrdsValue::new_unsigned(CrdsData::Vote(
|
|
|
|
0,
|
|
|
|
Vote::new(&keypair.pubkey(), test_tx(), timestamp()),
|
|
|
|
));
|
2019-03-11 16:43:30 -07:00
|
|
|
verify_signatures(&mut v, &keypair, &wrong_keypair);
|
2019-12-05 11:25:13 -08:00
|
|
|
let btreeset: BTreeSet<Slot> = vec![1, 2, 3, 6, 8].into_iter().collect();
|
2020-02-19 20:24:09 -08:00
|
|
|
v = CrdsValue::new_unsigned(CrdsData::EpochSlots(
|
2020-02-17 12:39:30 -08:00
|
|
|
0,
|
2020-02-19 20:24:09 -08:00
|
|
|
EpochSlots::new(keypair.pubkey(), 0, 0, btreeset, vec![], timestamp()),
|
|
|
|
));
|
2019-05-08 13:50:32 -07:00
|
|
|
verify_signatures(&mut v, &keypair, &wrong_keypair);
|
2019-03-11 16:43:30 -07:00
|
|
|
}
|
|
|
|
|
2019-11-04 16:19:54 -08:00
|
|
|
#[test]
|
|
|
|
fn test_max_vote_index() {
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
let vote = CrdsValue::new_signed(
|
|
|
|
CrdsData::Vote(
|
|
|
|
MAX_VOTES,
|
|
|
|
Vote::new(&keypair.pubkey(), test_tx(), timestamp()),
|
|
|
|
),
|
|
|
|
&keypair,
|
|
|
|
);
|
|
|
|
assert!(!vote.verify());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_compute_vote_index_empty() {
|
|
|
|
for i in 0..MAX_VOTES {
|
|
|
|
let votes = vec![];
|
|
|
|
assert!(CrdsValue::compute_vote_index(i as usize, votes) < MAX_VOTES);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_compute_vote_index_one() {
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
let vote = CrdsValue::new_unsigned(CrdsData::Vote(
|
|
|
|
0,
|
|
|
|
Vote::new(&keypair.pubkey(), test_tx(), 0),
|
|
|
|
));
|
|
|
|
for i in 0..MAX_VOTES {
|
|
|
|
let votes = vec![&vote];
|
|
|
|
assert!(CrdsValue::compute_vote_index(i as usize, votes) > 0);
|
|
|
|
let votes = vec![&vote];
|
|
|
|
assert!(CrdsValue::compute_vote_index(i as usize, votes) < MAX_VOTES);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_compute_vote_index_full() {
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
let votes: Vec<_> = (0..MAX_VOTES)
|
|
|
|
.map(|x| {
|
|
|
|
CrdsValue::new_unsigned(CrdsData::Vote(
|
|
|
|
x,
|
|
|
|
Vote::new(&keypair.pubkey(), test_tx(), x as u64),
|
|
|
|
))
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let vote_refs = votes.iter().collect();
|
|
|
|
//pick the oldest vote when full
|
|
|
|
assert_eq!(CrdsValue::compute_vote_index(31, vote_refs), 0);
|
|
|
|
//pick the index
|
|
|
|
let vote_refs = votes.iter().collect();
|
|
|
|
assert_eq!(CrdsValue::compute_vote_index(0, vote_refs), 0);
|
|
|
|
let vote_refs = votes.iter().collect();
|
|
|
|
assert_eq!(CrdsValue::compute_vote_index(30, vote_refs), 30);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn serialize_deserialize_value(value: &mut CrdsValue, keypair: &Keypair) {
|
2019-05-23 03:50:41 -07:00
|
|
|
let num_tries = 10;
|
|
|
|
value.sign(keypair);
|
|
|
|
let original_signature = value.get_signature();
|
|
|
|
for _ in 0..num_tries {
|
|
|
|
let serialized_value = serialize(value).unwrap();
|
|
|
|
let deserialized_value: CrdsValue = deserialize(&serialized_value).unwrap();
|
|
|
|
|
|
|
|
// Signatures shouldn't change
|
|
|
|
let deserialized_signature = deserialized_value.get_signature();
|
|
|
|
assert_eq!(original_signature, deserialized_signature);
|
|
|
|
|
|
|
|
// After deserializing, check that the signature is still the same
|
|
|
|
assert!(deserialized_value.verify());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-11 16:43:30 -07:00
|
|
|
fn verify_signatures(
|
|
|
|
value: &mut CrdsValue,
|
|
|
|
correct_keypair: &Keypair,
|
|
|
|
wrong_keypair: &Keypair,
|
|
|
|
) {
|
|
|
|
assert!(!value.verify());
|
|
|
|
value.sign(&correct_keypair);
|
|
|
|
assert!(value.verify());
|
|
|
|
value.sign(&wrong_keypair);
|
|
|
|
assert!(!value.verify());
|
2019-11-04 16:19:54 -08:00
|
|
|
serialize_deserialize_value(value, correct_keypair);
|
2018-12-01 12:00:30 -08:00
|
|
|
}
|
2018-11-15 13:23:26 -08:00
|
|
|
}
|