pub fn process_new_vote_state(
        &mut self,
        new_state: VecDeque<Lockout>,
        new_root: Option<Slot>,
        timestamp: Option<i64>,
        epoch: Epoch,
    ) -> Result<(), VoteError> {
        assert!(!new_state.is_empty());
        if new_state.len() > MAX_LOCKOUT_HISTORY {
            return Err(VoteError::TooManyVotes);
        }

        // check_slots_are_valid()` ensures we don't process any states
        // that are older than the current state
        if !self.votes.is_empty() {
            assert!(new_state.back().unwrap().slot > self.votes.back().unwrap().slot);
        }

        match (new_root, self.root_slot) {
            (Some(new_root), Some(current_root)) => {
                if new_root < current_root {
                    return Err(VoteError::RootRollBack);
                }
            }
            (None, Some(_)) => {
                return Err(VoteError::RootRollBack);
            }
            _ => (),
        }

        let mut previous_vote: Option<&Lockout> = None;

        // Check that all the votes in the new proposed state are:
        // 1) Strictly sorted from oldest to newest vote
        // 2) The confirmations are strictly decreasing
        // 3) Not zero confirmation votes
        for vote in &new_state {
            if vote.confirmation_count == 0 {
                return Err(VoteError::ZeroConfirmations);
            } else if vote.confirmation_count > MAX_LOCKOUT_HISTORY as u32 {
                return Err(VoteError::ConfirmationTooLarge);
            } else if let Some(new_root) = new_root {
                if vote.slot <= new_root
                &&
                // This check is necessary because
                // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L120
                // always sets a root for even empty towers, which is then hard unwrapped here
                // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L776
                new_root != Slot::default()
                {
                    return Err(VoteError::SlotSmallerThanRoot);
                }
            }

            if let Some(previous_vote) = previous_vote {
                if previous_vote.slot >= vote.slot {
                    return Err(VoteError::SlotsNotOrdered);
                } else if previous_vote.confirmation_count <= vote.confirmation_count {
                    return Err(VoteError::ConfirmationsNotOrdered);
                } else if vote.slot > previous_vote.last_locked_out_slot() {
                    return Err(VoteError::NewVoteStateLockoutMismatch);
                }
            }
            previous_vote = Some(vote);
        }

        // Find the first vote in the current vote state for a slot greater
        // than the new proposed root
        let mut current_vote_state_index = 0;
        let mut new_vote_state_index = 0;

        for current_vote in &self.votes {
            // Find the first vote in the current vote state for a slot greater
            // than the new proposed root
            if let Some(new_root) = new_root {
                if current_vote.slot <= new_root {
                    current_vote_state_index += 1;
                    continue;
                }
            }

            break;
        }

        // All the votes in our current vote state that are missing from the new vote state
        // must have been expired by later votes. Check that the lockouts match this assumption.
        while current_vote_state_index < self.votes.len() && new_vote_state_index < new_state.len()
        {
            let current_vote = &self.votes[current_vote_state_index];
            let new_vote = &new_state[new_vote_state_index];

            // If the current slot is less than the new proposed slot, then the
            // new slot must have popped off the old slot, so check that the
            // lockouts are corrects.
            match current_vote.slot.cmp(&new_vote.slot) {
                Ordering::Less => {
                    if current_vote.last_locked_out_slot() >= new_vote.slot {
                        return Err(VoteError::LockoutConflict);
                    }
                    current_vote_state_index += 1;
                }
                Ordering::Equal => {
                    // The new vote state should never have less lockout than
                    // the previous vote state for the same slot
                    if new_vote.confirmation_count < current_vote.confirmation_count {
                        return Err(VoteError::ConfirmationRollBack);
                    }

                    current_vote_state_index += 1;
                    new_vote_state_index += 1;
                }
                Ordering::Greater => {
                    new_vote_state_index += 1;
                }
            }
        }

        // `new_vote_state` passed all the checks, finalize the change by rewriting
        // our state.
        if self.root_slot != new_root {
            // TODO to think about: Note, people may be incentivized to set more
            // roots to get more credits, but I think they can already do this...
            self.increment_credits(epoch);
        }
        if let Some(timestamp) = timestamp {
            let last_slot = new_state.back().unwrap().slot;
            self.process_timestamp(last_slot, timestamp)?;
        }
        self.root_slot = new_root;
        self.votes = new_state;
        Ok(())
    }
// Note these two above checks do not guarantee that the vote state being submitted
// is a vote state that could have been created by iteratively building a tower
// by processing one vote at a time. For instance, the tower:
//
// { slot 0, confirmations: 31 }
// { slot 1, confirmations: 30 }
//
// is a legal tower that could be submitted on top of a previously empty tower. However,
// there is no way to create this tower from the iterative process, because slot 1 would
// have to have at least one other slot on top of it, even if the first 30 votes were all
// popped off.
Note these two above checks do not guarantee that the vote state being submitted
is a vote state that could have been created by iteratively building a tower
by processing one vote at a time. For instance, the tower.

{ slot 0, confirmations: 31 }
{ slot 1, confirmations: 30 }


Note these two above checks do not guarantee that the vote state being submitted is a vote state that could have been created by iteratively building a tower by processing one vote at a time . For instance the tower . { slot 0 confirmations : 31 } { slot 1 confirmations : 30 }
pub fn process_new_vote_state(
        &mut self,
        new_state: VecDeque<Lockout>,
        new_root: Option<Slot>,
        timestamp: Option<i64>,
        epoch: Epoch,
    ) -> Result<(), VoteError> {
        assert!(!new_state.is_empty());
        if new_state.len() > MAX_LOCKOUT_HISTORY {
            return Err(VoteError::TooManyVotes);
        }
        // check_slots_are_valid()` ensures we don't process any states
        // that are older than the current state
        if !self.votes.is_empty() {
            assert!(new_state.back().unwrap().slot > self.votes.back().unwrap().slot);
        }
        match (new_root, self.root_slot) {
            (Some(new_root), Some(current_root)) => {
                if new_root < current_root {
                    return Err(VoteError::RootRollBack);
                }
            }
            (None, Some(_)) => {
                return Err(VoteError::RootRollBack);
            }
            _ => (),
        }
        let mut previous_vote: Option<&Lockout> = None;
        // Check that all the votes in the new proposed state are:
        // 1) Strictly sorted from oldest to newest vote
        // 2) The confirmations are strictly decreasing
        // 3) Not zero confirmation votes
        for vote in &new_state {
            if vote.confirmation_count == 0 {
                return Err(VoteError::ZeroConfirmations);
            } else if vote.confirmation_count > MAX_LOCKOUT_HISTORY as u32 {
                return Err(VoteError::ConfirmationTooLarge);
            } else if let Some(new_root) = new_root {
                if vote.slot <= new_root
                &&
                // This check is necessary because
                // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L120
                // always sets a root for even empty towers, which is then hard unwrapped here
                // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L776
                new_root != Slot::default()
                {
                    return Err(VoteError::SlotSmallerThanRoot);
                }
            }
            if let Some(previous_vote) = previous_vote {
                if previous_vote.slot >= vote.slot {
                    return Err(VoteError::SlotsNotOrdered);
                } else if previous_vote.confirmation_count <= vote.confirmation_count {
                    return Err(VoteError::ConfirmationsNotOrdered);
                } else if vote.slot > previous_vote.last_locked_out_slot() {
                    return Err(VoteError::NewVoteStateLockoutMismatch);
                }
            }
            previous_vote = Some(vote);
        }
        // Find the first vote in the current vote state for a slot greater
        // than the new proposed root
        let mut current_vote_state_index = 0;
        let mut new_vote_state_index = 0;
        for current_vote in &self.votes {
            // Find the first vote in the current vote state for a slot greater
            // than the new proposed root
            if let Some(new_root) = new_root {
                if current_vote.slot <= new_root {
                    current_vote_state_index += 1;
                    continue;
                }
            }
            break;
        }
        // All the votes in our current vote state that are missing from the new vote state
        // must have been expired by later votes. Check that the lockouts match this assumption.
        while current_vote_state_index < self.votes.len() && new_vote_state_index < new_state.len()
        {
            let current_vote = &self.votes[current_vote_state_index];
            let new_vote = &new_state[new_vote_state_index];
            // If the current slot is less than the new proposed slot, then the
            // new slot must have popped off the old slot, so check that the
            // lockouts are corrects.
            match current_vote.slot.cmp(&new_vote.slot) {
                Ordering::Less => {
                    if current_vote.last_locked_out_slot() >= new_vote.slot {
                        return Err(VoteError::LockoutConflict);
                    }
                    current_vote_state_index += 1;
                }
                Ordering::Equal => {
                    // The new vote state should never have less lockout than
                    // the previous vote state for the same slot
                    if new_vote.confirmation_count < current_vote.confirmation_count {
                        return Err(VoteError::ConfirmationRollBack);
                    }
                    current_vote_state_index += 1;
                    new_vote_state_index += 1;
                }
                Ordering::Greater => {
                    new_vote_state_index += 1;
                }
            }
        }
        // `new_vote_state` passed all the checks, finalize the change by rewriting
        // our state.
        if self.root_slot != new_root {
            // TODO to think about: Note, people may be incentivized to set more
            // roots to get more credits, but I think they can already do this...
            self.increment_credits(epoch);
        }
        if let Some(timestamp) = timestamp {
            let last_slot = new_state.back().unwrap().slot;
            self.process_timestamp(last_slot, timestamp)?;
        }
        self.root_slot = new_root;
        self.votes = new_state;
        Ok(())
    }
pub fn process_new_vote_state ( & mut self , new_state : VecDeque < Lockout > , new_root : Option < Slot > , timestamp : Option < i64 > , epoch : Epoch , ) -> Result < ( ) , VoteError > { assert ! ( new_state is_empty ( ) ) ; if new_state . len ( ) > MAX_LOCKOUT_HISTORY { return Err ( VoteError :: TooManyVotes ) ; } // check_slots_are_valid()` ensures we don't process any states // that are older than the current state if ! self . votes . is_empty ( ) { assert ! ( new_state back ( ) unwrap ( ) slot self votes back ( ) unwrap ( ) slot ) ; } match ( new_root , self . root_slot ) { ( Some ( new_root ) , Some ( current_root ) ) => { if new_root < current_root { return Err ( VoteError :: RootRollBack ) ; } } ( None , Some ( _ ) ) => { return Err ( VoteError :: RootRollBack ) ; } _ => ( ) , } let mut previous_vote : Option < & Lockout > = None ; // Check that all the votes in the new proposed state are: // 1) Strictly sorted from oldest to newest vote // 2) The confirmations are strictly decreasing // 3) Not zero confirmation votes for vote in & new_state { if vote . confirmation_count == 0 { return Err ( VoteError :: ZeroConfirmations ) ; } else if vote . confirmation_count > MAX_LOCKOUT_HISTORY as u32 { return Err ( VoteError :: ConfirmationTooLarge ) ; } else if let Some ( new_root ) = new_root { if vote . slot <= new_root && // This check is necessary because // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L120 // always sets a root for even empty towers, which is then hard unwrapped here // https://github.com/ryoqun/solana/blob/df55bfb46af039cbc597cd60042d49b9d90b5961/core/src/consensus.rs#L776 new_root != Slot :: default ( ) { return Err ( VoteError :: SlotSmallerThanRoot ) ; } } if let Some ( previous_vote ) = previous_vote { if previous_vote . slot >= vote . slot { return Err ( VoteError :: SlotsNotOrdered ) ; } else if previous_vote . confirmation_count <= vote . confirmation_count { return Err ( VoteError :: ConfirmationsNotOrdered ) ; } else if vote . slot > previous_vote . last_locked_out_slot ( ) { return Err ( VoteError :: NewVoteStateLockoutMismatch ) ; } } previous_vote = Some ( vote ) ; } // Find the first vote in the current vote state for a slot greater // than the new proposed root let mut current_vote_state_index = 0 ; let mut new_vote_state_index = 0 ; for current_vote in & self . votes { // Find the first vote in the current vote state for a slot greater // than the new proposed root if let Some ( new_root ) = new_root { if current_vote . slot <= new_root { current_vote_state_index += 1 ; continue ; } } break ; } // All the votes in our current vote state that are missing from the new vote state // must have been expired by later votes. Check that the lockouts match this assumption. while current_vote_state_index < self . votes . len ( ) && new_vote_state_index < new_state . len ( ) { let current_vote = & self . votes [ current_vote_state_index ] ; let new_vote = & new_state [ new_vote_state_index ] ; // If the current slot is less than the new proposed slot, then the // new slot must have popped off the old slot, so check that the // lockouts are corrects. match current_vote . slot . cmp ( & new_vote . slot ) { Ordering :: Less => { if current_vote . last_locked_out_slot ( ) >= new_vote . slot { return Err ( VoteError :: LockoutConflict ) ; } current_vote_state_index += 1 ; } Ordering :: Equal => { // The new vote state should never have less lockout than // the previous vote state for the same slot if new_vote . confirmation_count < current_vote . confirmation_count { return Err ( VoteError :: ConfirmationRollBack ) ; } current_vote_state_index += 1 ; new_vote_state_index += 1 ; } Ordering :: Greater => { new_vote_state_index += 1 ; } } } // `new_vote_state` passed all the checks, finalize the change by rewriting // our state. if self . root_slot != new_root { // TODO to think about: Note, people may be incentivized to set more // roots to get more credits, but I think they can already do this... self . increment_credits ( epoch ) ; } if let Some ( timestamp ) = timestamp { let last_slot = new_state . back ( ) . unwrap ( ) . slot ; self . process_timestamp ( last_slot , timestamp ) ? ; } self . root_slot = new_root ; self . votes = new_state ; Ok ( ( ) ) }
Note these two above checks do not guarantee that the vote state being submitted
is a vote state that could have been created by iteratively building a tower
by processing one vote at a time.
Note these two above checks do not guarantee that the vote state being submitted is a vote state that could have been created by iteratively building a tower by processing one vote at a time .
&mut self
new_state
VecDeque<Lockout>
new_root
Option<Slot>
timestamp
Option<i64>
epoch
Epoch