Split old state_transition.rs into transition/ dir
This commit is contained in:
parent
6f0bbd47fa
commit
a8ef18c7e9
@ -13,6 +13,5 @@ pub mod block;
|
|||||||
pub mod crosslink_record;
|
pub mod crosslink_record;
|
||||||
pub mod partial_crosslink_record;
|
pub mod partial_crosslink_record;
|
||||||
pub mod recent_proposer_record;
|
pub mod recent_proposer_record;
|
||||||
pub mod state_transition;
|
|
||||||
pub mod transition;
|
pub mod transition;
|
||||||
pub mod validator_record;
|
pub mod validator_record;
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
use super::bytes::{ BytesMut, BufMut };
|
|
||||||
use super::crystallized_state::CrystallizedState;
|
|
||||||
use super::active_state::ActiveState;
|
|
||||||
use super::aggregate_vote::AggregateVote;
|
|
||||||
|
|
||||||
use super::transition::shuffling::get_shuffling;
|
|
||||||
use super::config::Config;
|
|
||||||
|
|
||||||
const AGG_VOTE_MSG_SIZE: i32 = 2 + 32 + 32 + 8 + 8;
|
|
||||||
|
|
||||||
// Given an aggregate_vote and a crystallized_state,
|
|
||||||
// return a byte array for signing or verification.
|
|
||||||
pub fn get_crosslink_aggvote_msg(
|
|
||||||
agg_vote: &AggregateVote,
|
|
||||||
cry_state: &CrystallizedState)
|
|
||||||
-> Vec<u8>
|
|
||||||
{
|
|
||||||
let mut buf = BytesMut::with_capacity(AGG_VOTE_MSG_SIZE as usize);
|
|
||||||
buf.put_u16_be(agg_vote.shard_id);
|
|
||||||
buf.extend_from_slice(&agg_vote.shard_block_hash.to_vec());
|
|
||||||
buf.extend_from_slice(&cry_state.current_checkpoint.to_vec());
|
|
||||||
buf.put_u64_be(cry_state.current_epoch);
|
|
||||||
buf.put_u64_be(cry_state.last_justified_epoch);
|
|
||||||
buf.to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
// For a given state set and skip_count, return a proposer and set
|
|
||||||
// of attestors.
|
|
||||||
pub fn get_attesters_and_proposer(
|
|
||||||
cry_state: &CrystallizedState,
|
|
||||||
act_state: &ActiveState,
|
|
||||||
skip_count: &u64,
|
|
||||||
config: &Config)
|
|
||||||
-> (Vec<usize>, usize)
|
|
||||||
{
|
|
||||||
let active_validator_count = cry_state.num_active_validators();
|
|
||||||
assert!(active_validator_count >= 2, "must be >=2 active validators");
|
|
||||||
let shuffled_validator_indicies = get_shuffling(
|
|
||||||
&act_state.randao,
|
|
||||||
&active_validator_count,
|
|
||||||
config);
|
|
||||||
let proposer_count: usize = 1;
|
|
||||||
let ideal_validator_count: usize = (config.attester_count as usize)
|
|
||||||
+ (*skip_count as usize) + proposer_count;
|
|
||||||
assert!(ideal_validator_count >= 2,
|
|
||||||
"ideal_validator_count must be >=2");
|
|
||||||
if ideal_validator_count > active_validator_count {
|
|
||||||
return (
|
|
||||||
shuffled_validator_indicies[0..active_validator_count - 1].to_vec(),
|
|
||||||
shuffled_validator_indicies[active_validator_count - 1]);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
shuffled_validator_indicies[0..ideal_validator_count - 1].to_vec(),
|
|
||||||
shuffled_validator_indicies[ideal_validator_count - 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use super::super::validator_record::ValidatorRecord;
|
|
||||||
use super::super::utils::types::{ Address, Sha256Digest, U256 };
|
|
||||||
use super::super::
|
|
||||||
utils::test_helpers::get_dangerous_test_keypair;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_crosslink_aggvote_msg() {
|
|
||||||
let mut cs_state = CrystallizedState::zero();
|
|
||||||
let mut agg_vote = AggregateVote::zero();
|
|
||||||
// All zeros
|
|
||||||
let m1 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
|
|
||||||
assert_eq!(m1,
|
|
||||||
vec![0_u8; AGG_VOTE_MSG_SIZE as usize],
|
|
||||||
"failed all zeros test");
|
|
||||||
// With some values
|
|
||||||
agg_vote.shard_id = 42;
|
|
||||||
cs_state.current_epoch = 99;
|
|
||||||
cs_state.last_justified_epoch = 123;
|
|
||||||
let m2 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
|
|
||||||
assert_eq!(m2[0..2], [0, 42]);
|
|
||||||
assert_eq!(m2[2..34], [0; 32]); // TODO: test with non-zero hash
|
|
||||||
assert_eq!(m2[34..66], [0; 32]); // TODO: test with non-zero hash
|
|
||||||
assert_eq!(m2[66..74], [0, 0, 0, 0, 0, 0, 0, 99]);
|
|
||||||
assert_eq!(m2[74..82], [0, 0, 0, 0, 0, 0, 0, 123]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_attester_and_proposer_selection() {
|
|
||||||
let mut cry_state = CrystallizedState::zero();
|
|
||||||
for _ in 0..10 {
|
|
||||||
cry_state.active_validators.push(ValidatorRecord {
|
|
||||||
pubkey: get_dangerous_test_keypair().public,
|
|
||||||
withdrawal_shard: 0,
|
|
||||||
withdrawal_address: Address::zero(),
|
|
||||||
randao_commitment: Sha256Digest::zero(),
|
|
||||||
balance: U256::zero(),
|
|
||||||
switch_dynasty: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let act_state = ActiveState::zero();
|
|
||||||
let (attestors, proposer) = get_attesters_and_proposer(
|
|
||||||
&cry_state,
|
|
||||||
&act_state,
|
|
||||||
&0,
|
|
||||||
&Config::standard());
|
|
||||||
assert_eq!(attestors, [0, 9, 7, 6, 4, 1, 8, 5, 2]);
|
|
||||||
assert_eq!(proposer, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic(expected = "must be >=2 active validators")]
|
|
||||||
fn test_attester_and_proposer_selection_with_zero_active_validators() {
|
|
||||||
let mut cry_state = CrystallizedState::zero();
|
|
||||||
cry_state.active_validators = Vec::new();
|
|
||||||
let act_state = ActiveState::zero();
|
|
||||||
let (_attestors, _proposer) = get_attesters_and_proposer(
|
|
||||||
&cry_state,
|
|
||||||
&act_state,
|
|
||||||
&0,
|
|
||||||
&Config::standard());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
use super::validator_record::ValidatorRecord;
|
|
||||||
use super::utils::types::Bitfield;
|
|
||||||
use super::utils::bls::{ AggregateSignature, PublicKey };
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
pub fn process_attestations(
|
|
||||||
validators: &Vec<ValidatorRecord>,
|
|
||||||
attestation_indicies: &Vec<usize>,
|
|
||||||
attestation_bitfield: &Bitfield,
|
|
||||||
msg: &Vec<u8>,
|
|
||||||
aggregate_sig: &AggregateSignature)
|
|
||||||
-> Option<Vec<usize>>
|
|
||||||
{
|
|
||||||
let mut key_msg_tuples: Vec<(&PublicKey, &[u8])> = vec![];
|
|
||||||
let mut attesters: Vec<usize> = vec![];
|
|
||||||
|
|
||||||
assert_eq!(attestation_indicies.len(), attestation_bitfield.len());
|
|
||||||
for (bitfield_bit, validators_index) in attestation_indicies.iter().enumerate() {
|
|
||||||
if attestation_bitfield.get_bit(&bitfield_bit) {
|
|
||||||
key_msg_tuples.push(
|
|
||||||
(&validators[*validators_index].pubkey,
|
|
||||||
&msg)
|
|
||||||
);
|
|
||||||
attesters.push(*validators_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: figure out why this assert exists in the Python impl.
|
|
||||||
assert!(attesters.len() <= 128, "Max attesters is 128.");
|
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO: ensure signature verification actually takes place.
|
|
||||||
// It is completely bypassed here.
|
|
||||||
match aggregate_sig.verify(&key_msg_tuples) {
|
|
||||||
false => None,
|
|
||||||
true => Some(attesters)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Some(attesters)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_attestation_processing() {
|
|
||||||
let validator_count = 10;
|
|
||||||
let mut validators: Vec<ValidatorRecord> = vec![];
|
|
||||||
let mut attestation_indicies: Vec<usize> = vec![];
|
|
||||||
let mut bitfield = Bitfield::new();
|
|
||||||
let mut agg_sig = AggregateSignature::new();
|
|
||||||
let msg = "Message that's longer than 16 chars".as_bytes();
|
|
||||||
|
|
||||||
for i in 0..validator_count {
|
|
||||||
let (v, keypair) =
|
|
||||||
ValidatorRecord::zero_with_thread_rand_keypair();
|
|
||||||
validators.push(v);
|
|
||||||
attestation_indicies.push(i);
|
|
||||||
bitfield.set_bit(&i, &true);
|
|
||||||
let sig = keypair.sign(&msg);
|
|
||||||
agg_sig.aggregate(&sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = process_attestations(
|
|
||||||
&validators,
|
|
||||||
&attestation_indicies,
|
|
||||||
&bitfield,
|
|
||||||
&msg.to_vec(),
|
|
||||||
&agg_sig);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
None => panic!("Verification failed."),
|
|
||||||
Some(x) => println!("{:?}", x)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
143
src/state/transition/attestors.rs
Normal file
143
src/state/transition/attestors.rs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
use super::validator_record::ValidatorRecord;
|
||||||
|
use super::utils::types::Bitfield;
|
||||||
|
use super::utils::bls::{ AggregateSignature, PublicKey };
|
||||||
|
use super::crystallized_state::CrystallizedState;
|
||||||
|
use super::active_state::ActiveState;
|
||||||
|
use super::config::Config;
|
||||||
|
use super::shuffling::get_shuffling;
|
||||||
|
|
||||||
|
// For a given state set and skip_count, return a proposer and set
|
||||||
|
// of attestors.
|
||||||
|
pub fn get_attesters_and_proposer(
|
||||||
|
cry_state: &CrystallizedState,
|
||||||
|
act_state: &ActiveState,
|
||||||
|
skip_count: &u64,
|
||||||
|
config: &Config)
|
||||||
|
-> (Vec<usize>, usize)
|
||||||
|
{
|
||||||
|
let active_validator_count = cry_state.num_active_validators();
|
||||||
|
assert!(active_validator_count >= 2, "must be >=2 active validators");
|
||||||
|
let shuffled_validator_indicies = get_shuffling(
|
||||||
|
&act_state.randao,
|
||||||
|
&active_validator_count,
|
||||||
|
config);
|
||||||
|
let proposer_count: usize = 1;
|
||||||
|
let ideal_validator_count: usize = (config.attester_count as usize)
|
||||||
|
+ (*skip_count as usize) + proposer_count;
|
||||||
|
assert!(ideal_validator_count >= 2,
|
||||||
|
"ideal_validator_count must be >=2");
|
||||||
|
if ideal_validator_count > active_validator_count {
|
||||||
|
return (
|
||||||
|
shuffled_validator_indicies[0..active_validator_count - 1].to_vec(),
|
||||||
|
shuffled_validator_indicies[active_validator_count - 1]);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
shuffled_validator_indicies[0..ideal_validator_count - 1].to_vec(),
|
||||||
|
shuffled_validator_indicies[ideal_validator_count - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn process_attestations(
|
||||||
|
validators: &Vec<ValidatorRecord>,
|
||||||
|
attestation_indicies: &Vec<usize>,
|
||||||
|
attestation_bitfield: &Bitfield,
|
||||||
|
msg: &Vec<u8>,
|
||||||
|
aggregate_sig: &AggregateSignature)
|
||||||
|
-> Option<Vec<usize>>
|
||||||
|
{
|
||||||
|
let mut key_msg_tuples: Vec<(&PublicKey, &[u8])> = vec![];
|
||||||
|
let mut attesters: Vec<usize> = vec![];
|
||||||
|
|
||||||
|
assert_eq!(attestation_indicies.len(), attestation_bitfield.len());
|
||||||
|
for (bitfield_bit, validators_index) in attestation_indicies.iter().enumerate() {
|
||||||
|
if attestation_bitfield.get_bit(&bitfield_bit) {
|
||||||
|
key_msg_tuples.push(
|
||||||
|
(&validators[*validators_index].pubkey,
|
||||||
|
&msg)
|
||||||
|
);
|
||||||
|
attesters.push(*validators_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: figure out why this assert exists in the Python impl.
|
||||||
|
assert!(attesters.len() <= 128, "Max attesters is 128.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: ensure signature verification actually takes place.
|
||||||
|
// It is completely bypassed here.
|
||||||
|
match aggregate_sig.verify(&key_msg_tuples) {
|
||||||
|
false => None,
|
||||||
|
true => Some(attesters)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Some(attesters)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_attester_and_proposer_selection() {
|
||||||
|
let mut cry_state = CrystallizedState::zero();
|
||||||
|
|
||||||
|
(0..10).for_each(
|
||||||
|
|_| cry_state.active_validators.push(
|
||||||
|
ValidatorRecord::zero_with_thread_rand_pub_key()));
|
||||||
|
|
||||||
|
let act_state = ActiveState::zero();
|
||||||
|
let (attestors, proposer) = get_attesters_and_proposer(
|
||||||
|
&cry_state,
|
||||||
|
&act_state,
|
||||||
|
&0,
|
||||||
|
&Config::standard());
|
||||||
|
assert_eq!(attestors, [0, 9, 7, 6, 4, 1, 8, 5, 2]);
|
||||||
|
assert_eq!(proposer, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "must be >=2 active validators")]
|
||||||
|
fn test_attester_and_proposer_selection_with_zero_active_validators() {
|
||||||
|
let mut cry_state = CrystallizedState::zero();
|
||||||
|
cry_state.active_validators = Vec::new();
|
||||||
|
let act_state = ActiveState::zero();
|
||||||
|
let (_attestors, _proposer) = get_attesters_and_proposer(
|
||||||
|
&cry_state,
|
||||||
|
&act_state,
|
||||||
|
&0,
|
||||||
|
&Config::standard());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_attestation_processing() {
|
||||||
|
let validator_count = 10;
|
||||||
|
let mut validators: Vec<ValidatorRecord> = vec![];
|
||||||
|
let mut attestation_indicies: Vec<usize> = vec![];
|
||||||
|
let mut bitfield = Bitfield::new();
|
||||||
|
let mut agg_sig = AggregateSignature::new();
|
||||||
|
let msg = "Message that's longer than 16 chars".as_bytes();
|
||||||
|
|
||||||
|
for i in 0..validator_count {
|
||||||
|
let (v, keypair) =
|
||||||
|
ValidatorRecord::zero_with_thread_rand_keypair();
|
||||||
|
validators.push(v);
|
||||||
|
attestation_indicies.push(i);
|
||||||
|
bitfield.set_bit(&i, &true);
|
||||||
|
let sig = keypair.sign(&msg);
|
||||||
|
agg_sig.aggregate(&sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = process_attestations(
|
||||||
|
&validators,
|
||||||
|
&attestation_indicies,
|
||||||
|
&bitfield,
|
||||||
|
&msg.to_vec(),
|
||||||
|
&agg_sig);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
None => panic!("Verification failed."),
|
||||||
|
Some(x) => println!("{:?}", x)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,31 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use super::bytes::{ BytesMut, BufMut };
|
||||||
|
use super::aggregate_vote::AggregateVote;
|
||||||
|
|
||||||
use super::crystallized_state::CrystallizedState;
|
use super::crystallized_state::CrystallizedState;
|
||||||
use super::crosslink_record::CrosslinkRecord;
|
use super::crosslink_record::CrosslinkRecord;
|
||||||
use super::partial_crosslink_record::PartialCrosslinkRecord;
|
use super::partial_crosslink_record::PartialCrosslinkRecord;
|
||||||
use super::config::Config;
|
use super::config::Config;
|
||||||
|
|
||||||
|
const AGG_VOTE_MSG_SIZE: i32 = 2 + 32 + 32 + 8 + 8;
|
||||||
|
|
||||||
|
// Given an aggregate_vote and a crystallized_state,
|
||||||
|
// return a byte array for signing or verification.
|
||||||
|
pub fn get_crosslink_aggvote_msg(
|
||||||
|
agg_vote: &AggregateVote,
|
||||||
|
cry_state: &CrystallizedState)
|
||||||
|
-> Vec<u8>
|
||||||
|
{
|
||||||
|
let mut buf = BytesMut::with_capacity(AGG_VOTE_MSG_SIZE as usize);
|
||||||
|
buf.put_u16_be(agg_vote.shard_id);
|
||||||
|
buf.extend_from_slice(&agg_vote.shard_block_hash.to_vec());
|
||||||
|
buf.extend_from_slice(&cry_state.current_checkpoint.to_vec());
|
||||||
|
buf.put_u64_be(cry_state.current_epoch);
|
||||||
|
buf.put_u64_be(cry_state.last_justified_epoch);
|
||||||
|
buf.to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the maximum possible shards for a given validator_count
|
// Returns the maximum possible shards for a given validator_count
|
||||||
// and configuration.
|
// and configuration.
|
||||||
pub fn get_crosslink_shards_count(
|
pub fn get_crosslink_shards_count(
|
||||||
@ -186,6 +206,27 @@ mod tests {
|
|||||||
use super::super::super::validator_record::ValidatorRecord;
|
use super::super::super::validator_record::ValidatorRecord;
|
||||||
use super::super::super::super::utils::types::{ Sha256Digest, Bitfield };
|
use super::super::super::super::utils::types::{ Sha256Digest, Bitfield };
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_crosslink_aggvote_msg() {
|
||||||
|
let mut cs_state = CrystallizedState::zero();
|
||||||
|
let mut agg_vote = AggregateVote::zero();
|
||||||
|
// All zeros
|
||||||
|
let m1 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
|
||||||
|
assert_eq!(m1,
|
||||||
|
vec![0_u8; AGG_VOTE_MSG_SIZE as usize],
|
||||||
|
"failed all zeros test");
|
||||||
|
// With some values
|
||||||
|
agg_vote.shard_id = 42;
|
||||||
|
cs_state.current_epoch = 99;
|
||||||
|
cs_state.last_justified_epoch = 123;
|
||||||
|
let m2 = get_crosslink_aggvote_msg(&agg_vote, &cs_state);
|
||||||
|
assert_eq!(m2[0..2], [0, 42]);
|
||||||
|
assert_eq!(m2[2..34], [0; 32]); // TODO: test with non-zero hash
|
||||||
|
assert_eq!(m2[34..66], [0; 32]); // TODO: test with non-zero hash
|
||||||
|
assert_eq!(m2[66..74], [0, 0, 0, 0, 0, 0, 0, 99]);
|
||||||
|
assert_eq!(m2[74..82], [0, 0, 0, 0, 0, 0, 0, 123]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_crosslink_shard_count_with_varying_active_vals() {
|
fn test_crosslink_shard_count_with_varying_active_vals() {
|
||||||
let mut config = Config::standard();
|
let mut config = Config::standard();
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
use super::bytes;
|
||||||
use super::config;
|
use super::config;
|
||||||
use super::utils;
|
use super::utils;
|
||||||
use super::blake2;
|
use super::blake2;
|
||||||
|
use super::active_state;
|
||||||
|
use super::aggregate_vote;
|
||||||
use super::crystallized_state;
|
use super::crystallized_state;
|
||||||
use super::crosslink_record;
|
use super::crosslink_record;
|
||||||
use super::partial_crosslink_record;
|
use super::partial_crosslink_record;
|
||||||
@ -10,4 +13,4 @@ pub mod crosslinks;
|
|||||||
pub mod deposits;
|
pub mod deposits;
|
||||||
pub mod shuffling;
|
pub mod shuffling;
|
||||||
pub mod validators;
|
pub mod validators;
|
||||||
pub mod attestations;
|
pub mod attestors;
|
||||||
|
Loading…
Reference in New Issue
Block a user