/// Votes on a pending root proposal to change the governance canister
///
/// Votes are only accepted if:
/// - There is one proposal outstanding matching the sha and the proposer.
/// - The latest registry version for the subnet record matches the version when
///   the proposal was submitted. (if it doesn't it clears the proposal and the
///   votes and a new one must be submitted).
/// - The caller's principal is among the principals of the node operators
///   running the nns subnetwork at the time the proposal was submitted.
/// - The caller must pass the sha256 of the wasm that they expect to be on the
///   proposal and this must match the sha256 of the wasm on the current
///   outstanding proposal.
///
/// If the votes are accepted, the caller casts however many ballots as the
/// number of nodes they control on the nns subnetwork.
Votes on a pending root proposal to change the governance canister
Votes are only accepted if:
There is one proposal outstanding matching the sha and the proposer.
The latest registry version for the subnet record matches the version when
the proposal was submitted. (if it doesn't it clears the proposal and the
votes and a new one must be submitted).
The caller's principal is among the principals of the node operators
running the nns subnetwork at the time the proposal was submitted.
The caller must pass the sha256 of the wasm that they expect to be on the
proposal and this must match the sha256 of the wasm on the current
outstanding proposal.

If the votes are accepted, the caller casts however many ballots as the
number of nodes they control on the nns subnetwork.
Votes on a pending root proposal to change the governance canister Votes are only accepted if : There is one proposal outstanding matching the sha and the proposer . The latest registry version for the subnet record matches the version when the proposal was submitted . ( if it doesn ' t it clears the proposal and the votes and a new one must be submitted ) . The caller ' s principal is among the principals of the node operators running the nns subnetwork at the time the proposal was submitted . The caller must pass the sha256 of the wasm that they expect to be on the proposal and this must match the sha256 of the wasm on the current outstanding proposal . If the votes are accepted the caller casts however many ballots as the number of nodes they control on the nns subnetwork .
pub async fn vote_on_root_proposal_to_upgrade_governance_canister(
    caller: PrincipalId,
    proposer: PrincipalId,
    wasm_sha256: Vec<u8>,
    ballot: RootProposalBallot,
) -> Result<(), String> {
    let proposal = get_proposal_clone(&proposer)?;
    let (_, version) = get_nns_membership(&proposal.nns_subnet_id)
        .await
        .map_err(|e| format!("Error executing proposal: {:?}", e))?;
    // Check all the constraints and vote (without any async calls in between).
    PROPOSALS.with(|proposals| {
        let mut proposals = proposals.borrow_mut();
        let proposal = proposals.get_mut(&proposer);
        if proposal.is_none() {
            let message = format!(
                "No root governance upgrade proposal from {} is pending",
                proposer
            );
            println!("{}", message);
            return Err(message);
        }
        let proposal = proposal.unwrap();
        let now = now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .expect("Could not get the current time.")
            .as_secs();
        // Check the submission time, if it has elapsed without a majority
        // we can delete it.
        if now
            > (proposal.submission_timestamp_seconds + MAX_TIME_FOR_GOVERNANCE_UPGRADE_ROOT_PROPOSAL)
        {
            proposals.remove(&proposer);
            let message = format!(
                "{}Current root governance upgrade proposal from {} is too old.\
                 Deleting.",
                LOG_PREFIX, proposer,
            );
            println!("{}", message);
            return Err(message);
        }
        // Check that the version of the record on the registry is still the same.
        if version != proposal.subnet_membership_registry_version {
            proposals.remove(&proposer);
            let message = format!(
                "{}Registry version of the subnet record changed since the\
                 proposal from {} was submitted. Deleting.",
                LOG_PREFIX, proposer,
            );
            println!("{}", message);
            return Err(message);
        }
        if wasm_sha256 != proposal.proposed_wasm_sha {
            let message = format!(
                "{}The sha of the wasm in the governance upgrade proposal that the voter intends to vote on: {:?}\
                 is not the same as the sha of the wasm: {:?} proposed by: {}", LOG_PREFIX, wasm_sha256,
                proposal.proposed_wasm_sha, proposer);
            println!("{}", message);
            return Err(message);
        }
        // Add the ballots for this node operator.
        let mut voted_on: i32 = 0;
        for (p, b) in &mut proposal.node_operator_ballots {
            if p == &caller {
                *b = ballot.clone();
                voted_on += 1;
            }
        }
        if voted_on == 0 {
            let message = format!(
                "{}Caller: {} is not eligible to vote on root proposal.",
                LOG_PREFIX, caller,
            );
            println!("{}", message);
            return Err(message);
        }
        Ok(())
    })?;
    // Get the proposal once more. Once the proposal is accepted or rejected it's
    // state is final, so it's ok to clone and execute from the clone.
    let proposal = get_proposal_clone(&proposer)?;
    let mut votes_yes: i32 = 0;
    let mut votes_no: i32 = 0;
    let mut votes_undecided: i32 = 0;
    for (_, b) in &proposal.node_operator_ballots {
        match b {
            RootProposalBallot::Yes => votes_yes += 1,
            RootProposalBallot::No => votes_no += 1,
            RootProposalBallot::Undecided => votes_undecided += 1,
        }
    }
    println!(
        "{}Vote(s) on root proposal to upgrade the governance canister to sha {:?} \
         from: {:?} were accepted. Current tally: {} Yes, {} No, {} Undecided.",
        LOG_PREFIX, wasm_sha256, proposer, votes_yes, votes_no, votes_undecided
    );
    if proposal.is_byzantine_majority_yes() {
        println!(
            "{}Root proposal from {} to upgrade the governance canister to sha: {:?} \
             was accepted. Votes: {} Yes, {} No, {} Undecided. Upgrading.",
            LOG_PREFIX, proposer, wasm_sha256, votes_yes, votes_no, votes_undecided
        );
        let payload = proposal.payload.clone();
        PROPOSALS.with(|proposals| proposals.borrow_mut().remove(&proposer));
        // Check that the wasm of the governance canister is still the same.
        let current_governance_wasm_sha = get_current_governance_canister_wasm().await;
        if current_governance_wasm_sha != proposal.current_wasm_sha {
            let message = format!(
                "{}Invalid proposal. Expected governance wasm sha must match \
             the currently running governance wasm's sha. Current: {:?}. Expected: {:?}",
                LOG_PREFIX, current_governance_wasm_sha, proposal.current_wasm_sha
            );
            println!("{}", message);
            return Err(message);
        }
        do_change_nns_canister(payload).await;
        Ok(())
    } else if proposal.is_byzantine_majority_no() {
        PROPOSALS.with(|proposals| proposals.borrow_mut().remove(&proposer));
        let message = format!(
            "{}Root proposal from {} to upgrade the governance canister to sha: {:?} \
             was rejected. Votes: {} Yes, {} No, {} Undecided. Deleting.",
            LOG_PREFIX, proposer, wasm_sha256, votes_yes, votes_no, votes_undecided
        );
        println!("{}", message);
        Ok(())
    } else {
        Ok(())
    }
}
pub async fn vote_on_root_proposal_to_upgrade_governance_canister ( caller : PrincipalId , proposer : PrincipalId , wasm_sha256 : Vec < u8 > , ballot : RootProposalBallot , ) -> Result < ( ) , String > { let proposal = get_proposal_clone ( & proposer ) ? ; let ( _ , version ) = get_nns_membership ( & proposal . nns_subnet_id ) . await . map_err ( | e | format ! ( " " e ) ) ? ; // Check all the constraints and vote (without any async calls in between). PROPOSALS . with ( | proposals | { let mut proposals = proposals . borrow_mut ( ) ; let proposal = proposals . get_mut ( & proposer ) ; if proposal . is_none ( ) { let message = format ! ( " " proposer ) ; println ! ( " " message ) ; return Err ( message ) ; } let proposal = proposal . unwrap ( ) ; let now = now ( ) . duration_since ( SystemTime :: UNIX_EPOCH ) . expect ( " " ) . as_secs ( ) ; // Check the submission time, if it has elapsed without a majority // we can delete it. if now > ( proposal . submission_timestamp_seconds + MAX_TIME_FOR_GOVERNANCE_UPGRADE_ROOT_PROPOSAL ) { proposals . remove ( & proposer ) ; let message = format ! ( " \
 " LOG_PREFIX proposer ) ; println ! ( " " message ) ; return Err ( message ) ; } // Check that the version of the record on the registry is still the same. if version != proposal . subnet_membership_registry_version { proposals . remove ( & proposer ) ; let message = format ! ( " \
 " LOG_PREFIX proposer ) ; println ! ( " " message ) ; return Err ( message ) ; } if wasm_sha256 != proposal . proposed_wasm_sha { let message = format ! ( " \
 " LOG_PREFIX wasm_sha256 proposal proposed_wasm_sha proposer ) ; println ! ( " " message ) ; return Err ( message ) ; } // Add the ballots for this node operator. let mut voted_on : i32 = 0 ; for ( p , b ) in & mut proposal . node_operator_ballots { if p == & caller { * b = ballot . clone ( ) ; voted_on += 1 ; } } if voted_on == 0 { let message = format ! ( " " LOG_PREFIX caller ) ; println ! ( " " message ) ; return Err ( message ) ; } Ok ( ( ) ) } ) ? ; // Get the proposal once more. Once the proposal is accepted or rejected it's // state is final, so it's ok to clone and execute from the clone. let proposal = get_proposal_clone ( & proposer ) ? ; let mut votes_yes : i32 = 0 ; let mut votes_no : i32 = 0 ; let mut votes_undecided : i32 = 0 ; for ( _ , b ) in & proposal . node_operator_ballots { match b { RootProposalBallot :: Yes => votes_yes += 1 , RootProposalBallot :: No => votes_no += 1 , RootProposalBallot :: Undecided => votes_undecided += 1 , } } println ! ( " \
 " LOG_PREFIX wasm_sha256 proposer votes_yes votes_no votes_undecided ) ; if proposal . is_byzantine_majority_yes ( ) { println ! ( " \
 " LOG_PREFIX proposer wasm_sha256 votes_yes votes_no votes_undecided ) ; let payload = proposal . payload . clone ( ) ; PROPOSALS . with ( | proposals | proposals . borrow_mut ( ) . remove ( & proposer ) ) ; // Check that the wasm of the governance canister is still the same. let current_governance_wasm_sha = get_current_governance_canister_wasm ( ) . await ; if current_governance_wasm_sha != proposal . current_wasm_sha { let message = format ! ( " \
 " LOG_PREFIX current_governance_wasm_sha proposal current_wasm_sha ) ; println ! ( " " message ) ; return Err ( message ) ; } do_change_nns_canister ( payload ) . await ; Ok ( ( ) ) } else if proposal . is_byzantine_majority_no ( ) { PROPOSALS . with ( | proposals | proposals . borrow_mut ( ) . remove ( & proposer ) ) ; let message = format ! ( " \
 " LOG_PREFIX proposer wasm_sha256 votes_yes votes_no votes_undecided ) ; println ! ( " " message ) ; Ok ( ( ) ) } else { Ok ( ( ) ) } }
Votes on a pending root proposal to change the governance canister
Votes are only accepted if:
 There is one proposal outstanding matching the sha and the proposer.
Votes on a pending root proposal to change the governance canister Votes are only accepted if : There is one proposal outstanding matching the sha and the proposer .
caller
PrincipalId
proposer
PrincipalId
wasm_sha256
Vec<u8>
ballot
RootProposalBallot