pub async fn submit_root_proposal_to_upgrade_governance_canister(
    caller: PrincipalId,
    expected_governance_wasm_sha: Vec<u8>,
    payload: ChangeNnsCanisterProposalPayload,
) -> Result<(), String> {
    let now = now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .expect("Could not get the duration.")
        .as_secs();

    // This is a new proposal and we're ready to prepare it.
    // Do some simple validation first:
    // - That the wasm has some bytes in it.
    // - That it targets the governance canister.
    // - That it is an upgrade (reinstall is not supported).
    if payload.wasm_module.is_empty()
        || payload.canister_id != GOVERNANCE_CANISTER_ID
        || payload.mode != CanisterInstallMode::Upgrade
    {
        let message = format!(
            "{}Invalid proposal. Proposal must be an upgrade proposal \
             to the governance canister with some wasm.",
            LOG_PREFIX
        );
        println!("{}", message);
        return Err(message);
    }

    // Get the sha256 of the currently installed governance canister and
    // make sure it matches the one on the proposal (we'll check it again
    // on execution, but we check it here first to provide a nice error
    // message to the user).
    let current_governance_wasm_sha = get_current_governance_canister_wasm().await;
    if expected_governance_wasm_sha != current_governance_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, expected_governance_wasm_sha
        );
        println!("{}", message);
        return Err(message);
    }

    // Get the node operators of the nns subnet from the registry and how
    // many nodes each of them controls. In order to do this we need to:
    // - Get the principal id of the nns subnet
    // - Get the list of nodes
    // - Get the node operators, for each node.
    let mut node_operator_ballots = Vec::new();
    let nns_subnet_id = get_nns_subnet_id()
        .await
        .map_err(|e| format!("Error: {:?}", e))?;
    let (nns_nodes, subnet_membership_registry_version) = get_nns_membership(&nns_subnet_id)
        .await
        .map_err(|e| format!("Error: {:?}", e))?;

    let mut voted_on: i32 = 0;
    let mut total_votes: i32 = 0;
    for node in nns_nodes {
        total_votes += 1;
        let node_operator_pid =
            get_node_operator_pid_of_node(&node, subnet_membership_registry_version)
                .await
                .map_err(|e| format!("Error: {:?}", e))?;
        if node_operator_pid == caller {
            voted_on += 1;
            node_operator_ballots.push((node_operator_pid, RootProposalBallot::Yes));
        } else {
            node_operator_ballots.push((node_operator_pid, RootProposalBallot::Undecided));
        }
    }

    // Check if the caller is among those principals, if it is it will have
    // cast at least one ballot.
    if voted_on == 0 {
        let message = format!(
            "{}Invalid proposal. Caller: {} must be among the node operators of the nns subnet.",
            LOG_PREFIX, caller
        );
        println!("{}", message);
        return Err(message);
    }

    PROPOSALS.with(|proposals| {
        // Check whether there is a previous proposal from the same principal and log
        // that we'll be replacing it.
        if let Some(previous_proposal_from_the_same_principal) = proposals.borrow().get(&caller) {
            println!(
                "{}Current root proposal {:?} from {} is going to be overwritten.",
                LOG_PREFIX, previous_proposal_from_the_same_principal, caller,
            );
        }

        // Store the proposal, the current list of principals that can vote,
        // together with the version number and as many votes for 'yes' as the
        // number of nodes the caller's principal operates, in the nns subnetwork.
        let proposed_wasm_sha = ic_crypto_sha::Sha256::hash(&payload.wasm_module).to_vec();

        proposals.borrow_mut().insert(
            caller,
            GovernanceUpgradeRootProposal {
                nns_subnet_id,
                current_wasm_sha: current_governance_wasm_sha.clone(),
                proposed_wasm_sha: proposed_wasm_sha.clone(),
                payload,
                proposer: caller,
                node_operator_ballots,
                subnet_membership_registry_version,
                submission_timestamp_seconds: now,
            },
        );

        println!(
            "{}Root proposal to upgrade the governance canister from: {:?} to {:?}, \
             proposed by: {:?} was submitted. Current tally: {}/{}",
            LOG_PREFIX,
            current_governance_wasm_sha,
            proposed_wasm_sha,
            caller,
            voted_on,
            total_votes
        );
    });
    Ok(())
}
/// Submits a "root" governance upgrade proposal.
///
/// The caller must be the principal corresponding to a node operator currently
/// running a node on the nns subnetwork.
///
/// These situations will delete a root proposal:
/// - There can be only one "root" proposal pending from a given principal at a
///   time, if there is already a proposal pending from the same principal the
///   old proposal is deleted and replaced with the new one, voting is reset.
/// - Root proposals are only avaiable for voting for 7 days. After this period
///   the proposal can't be accepted and is deleted, upon receving a vote or a
///   get request or the submission of a new one.
/// - Root proposals are not stored in stable storage, an upgrade of the root
///   canister will delete the currently pending root proposal, if there is one.
Submits a "root" governance upgrade proposal.
The caller must be the principal corresponding to a node operator currently
running a node on the nns subnetwork.

These situations will delete a root proposal:
There can be only one "root" proposal pending from a given principal at a
time, if there is already a proposal pending from the same principal the
old proposal is deleted and replaced with the new one, voting is reset.
Root proposals are only avaiable for voting for 7 days. After this period
the proposal can't be accepted and is deleted, upon receving a vote or a
get request or the submission of a new one.
Root proposals are not stored in stable storage, an upgrade of the root
canister will delete the currently pending root proposal, if there is one.
Submits a " root " governance upgrade proposal . The caller must be the principal corresponding to a node operator currently running a node on the nns subnetwork . These situations will delete a root proposal : There can be only one " root " proposal pending from a given principal at a time if there is already a proposal pending from the same principal the old proposal is deleted and replaced with the new one voting is reset . Root proposals are only avaiable for voting for 7 days . After this period the proposal can ' t be accepted and is deleted upon receving a vote or a get request or the submission of a new one . Root proposals are not stored in stable storage an upgrade of the root canister will delete the currently pending root proposal if there is one .
pub async fn submit_root_proposal_to_upgrade_governance_canister(
    caller: PrincipalId,
    expected_governance_wasm_sha: Vec<u8>,
    payload: ChangeNnsCanisterProposalPayload,
) -> Result<(), String> {
    let now = now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .expect("Could not get the duration.")
        .as_secs();
    // This is a new proposal and we're ready to prepare it.
    // Do some simple validation first:
    // - That the wasm has some bytes in it.
    // - That it targets the governance canister.
    // - That it is an upgrade (reinstall is not supported).
    if payload.wasm_module.is_empty()
        || payload.canister_id != GOVERNANCE_CANISTER_ID
        || payload.mode != CanisterInstallMode::Upgrade
    {
        let message = format!(
            "{}Invalid proposal. Proposal must be an upgrade proposal \
             to the governance canister with some wasm.",
            LOG_PREFIX
        );
        println!("{}", message);
        return Err(message);
    }
    // Get the sha256 of the currently installed governance canister and
    // make sure it matches the one on the proposal (we'll check it again
    // on execution, but we check it here first to provide a nice error
    // message to the user).
    let current_governance_wasm_sha = get_current_governance_canister_wasm().await;
    if expected_governance_wasm_sha != current_governance_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, expected_governance_wasm_sha
        );
        println!("{}", message);
        return Err(message);
    }
    // Get the node operators of the nns subnet from the registry and how
    // many nodes each of them controls. In order to do this we need to:
    // - Get the principal id of the nns subnet
    // - Get the list of nodes
    // - Get the node operators, for each node.
    let mut node_operator_ballots = Vec::new();
    let nns_subnet_id = get_nns_subnet_id()
        .await
        .map_err(|e| format!("Error: {:?}", e))?;
    let (nns_nodes, subnet_membership_registry_version) = get_nns_membership(&nns_subnet_id)
        .await
        .map_err(|e| format!("Error: {:?}", e))?;
    let mut voted_on: i32 = 0;
    let mut total_votes: i32 = 0;
    for node in nns_nodes {
        total_votes += 1;
        let node_operator_pid =
            get_node_operator_pid_of_node(&node, subnet_membership_registry_version)
                .await
                .map_err(|e| format!("Error: {:?}", e))?;
        if node_operator_pid == caller {
            voted_on += 1;
            node_operator_ballots.push((node_operator_pid, RootProposalBallot::Yes));
        } else {
            node_operator_ballots.push((node_operator_pid, RootProposalBallot::Undecided));
        }
    }
    // Check if the caller is among those principals, if it is it will have
    // cast at least one ballot.
    if voted_on == 0 {
        let message = format!(
            "{}Invalid proposal. Caller: {} must be among the node operators of the nns subnet.",
            LOG_PREFIX, caller
        );
        println!("{}", message);
        return Err(message);
    }
    PROPOSALS.with(|proposals| {
        // Check whether there is a previous proposal from the same principal and log
        // that we'll be replacing it.
        if let Some(previous_proposal_from_the_same_principal) = proposals.borrow().get(&caller) {
            println!(
                "{}Current root proposal {:?} from {} is going to be overwritten.",
                LOG_PREFIX, previous_proposal_from_the_same_principal, caller,
            );
        }
        // Store the proposal, the current list of principals that can vote,
        // together with the version number and as many votes for 'yes' as the
        // number of nodes the caller's principal operates, in the nns subnetwork.
        let proposed_wasm_sha = ic_crypto_sha::Sha256::hash(&payload.wasm_module).to_vec();
        proposals.borrow_mut().insert(
            caller,
            GovernanceUpgradeRootProposal {
                nns_subnet_id,
                current_wasm_sha: current_governance_wasm_sha.clone(),
                proposed_wasm_sha: proposed_wasm_sha.clone(),
                payload,
                proposer: caller,
                node_operator_ballots,
                subnet_membership_registry_version,
                submission_timestamp_seconds: now,
            },
        );
        println!(
            "{}Root proposal to upgrade the governance canister from: {:?} to {:?}, \
             proposed by: {:?} was submitted. Current tally: {}/{}",
            LOG_PREFIX,
            current_governance_wasm_sha,
            proposed_wasm_sha,
            caller,
            voted_on,
            total_votes
        );
    });
    Ok(())
}
pub async fn submit_root_proposal_to_upgrade_governance_canister ( caller : PrincipalId , expected_governance_wasm_sha : Vec < u8 > , payload : ChangeNnsCanisterProposalPayload , ) -> Result < ( ) , String > { let now = now ( ) . duration_since ( SystemTime :: UNIX_EPOCH ) . expect ( " " ) . as_secs ( ) ; // This is a new proposal and we're ready to prepare it. // Do some simple validation first: // - That the wasm has some bytes in it. // - That it targets the governance canister. // - That it is an upgrade (reinstall is not supported). if payload . wasm_module . is_empty ( ) || payload . canister_id != GOVERNANCE_CANISTER_ID || payload . mode != CanisterInstallMode :: Upgrade { let message = format ! ( " \
 " LOG_PREFIX ) ; println ! ( " " message ) ; return Err ( message ) ; } // Get the sha256 of the currently installed governance canister and // make sure it matches the one on the proposal (we'll check it again // on execution, but we check it here first to provide a nice error // message to the user). let current_governance_wasm_sha = get_current_governance_canister_wasm ( ) . await ; if expected_governance_wasm_sha != current_governance_wasm_sha { let message = format ! ( " \
 " LOG_PREFIX current_governance_wasm_sha expected_governance_wasm_sha ) ; println ! ( " " message ) ; return Err ( message ) ; } // Get the node operators of the nns subnet from the registry and how // many nodes each of them controls. In order to do this we need to: // - Get the principal id of the nns subnet // - Get the list of nodes // - Get the node operators, for each node. let mut node_operator_ballots = Vec :: new ( ) ; let nns_subnet_id = get_nns_subnet_id ( ) . await . map_err ( | e | format ! ( " " e ) ) ? ; let ( nns_nodes , subnet_membership_registry_version ) = get_nns_membership ( & nns_subnet_id ) . await . map_err ( | e | format ! ( " " e ) ) ? ; let mut voted_on : i32 = 0 ; let mut total_votes : i32 = 0 ; for node in nns_nodes { total_votes += 1 ; let node_operator_pid = get_node_operator_pid_of_node ( & node , subnet_membership_registry_version ) . await . map_err ( | e | format ! ( " " e ) ) ? ; if node_operator_pid == caller { voted_on += 1 ; node_operator_ballots . push ( ( node_operator_pid , RootProposalBallot :: Yes ) ) ; } else { node_operator_ballots . push ( ( node_operator_pid , RootProposalBallot :: Undecided ) ) ; } } // Check if the caller is among those principals, if it is it will have // cast at least one ballot. if voted_on == 0 { let message = format ! ( " " LOG_PREFIX caller ) ; println ! ( " " message ) ; return Err ( message ) ; } PROPOSALS . with ( | proposals | { // Check whether there is a previous proposal from the same principal and log // that we'll be replacing it. if let Some ( previous_proposal_from_the_same_principal ) = proposals . borrow ( ) . get ( & caller ) { println ! ( " " LOG_PREFIX previous_proposal_from_the_same_principal caller ) ; } // Store the proposal, the current list of principals that can vote, // together with the version number and as many votes for 'yes' as the // number of nodes the caller's principal operates, in the nns subnetwork. let proposed_wasm_sha = ic_crypto_sha :: Sha256 :: hash ( & payload . wasm_module ) . to_vec ( ) ; proposals . borrow_mut ( ) . insert ( caller , GovernanceUpgradeRootProposal { nns_subnet_id , current_wasm_sha : current_governance_wasm_sha . clone ( ) , proposed_wasm_sha : proposed_wasm_sha . clone ( ) , payload , proposer : caller , node_operator_ballots , subnet_membership_registry_version , submission_timestamp_seconds : now , } , ) ; println ! ( " \
 " LOG_PREFIX current_governance_wasm_sha proposed_wasm_sha caller voted_on total_votes ) ; } ) ; Ok ( ( ) ) }
Submits a "root" governance upgrade proposal.
Submits a " root " governance upgrade proposal .
caller
PrincipalId
expected_governance_wasm_sha
Vec<u8>
payload
ChangeNnsCanisterProposalPayload
caller
PrincipalId
expected_governance_wasm_sha
Vec<u8>
payload
ChangeNnsCanisterProposalPayload