// Fetches a delegation from the NNS subnet to allow this subnet to issue
// certificates on its behalf. On the NNS subnet this method is a no-op.
Fetches a delegation from the NNS subnet to allow this subnet to issue
certificates on its behalf. On the NNS subnet this method is a no-op.
Fetches a delegation from the NNS subnet to allow this subnet to issue certificates on its behalf . On the NNS subnet this method is a no - op .
fn load_root_delegation(
    state_reader: &dyn StateReader<State = ReplicatedState>,
    subnet_id: SubnetId,
    nns_subnet_id: SubnetId,
    log: &ReplicaLogger,
) -> Result<Option<CertificateDelegation>, Error> {
    if subnet_id == nns_subnet_id {
        info!(log, "On the NNS subnet. Skipping fetching the delegation.");
        // On the NNS subnet. No delegation needs to be fetched.
        return Ok(None);
    }
    for _ in 0..MAX_FETCH_DELEGATION_ATTEMPTS {
        info!(log, "Fetching delegation from the nns subnet...");
        let log_err_and_backoff = |err: &dyn std::error::Error| {
            // Fetching the NNS delegation failed. Do a random backoff and try again.
            let mut rng = rand::thread_rng();
            let backoff = Duration::from_secs(rng.gen_range(1..15));
            warn!(
                log,
                "Fetching delegation from nns subnet failed. Retrying again in {} seconds...\n\
                    Error received: {}",
                backoff.as_secs(),
                err
            );
            std::thread::sleep(backoff);
        };
        let node = match get_random_node_from_nns_subnet(state_reader, nns_subnet_id) {
            Ok(node_topology) => node_topology,
            Err(err) => {
                fatal!(
                    log,
                    "Could not find a node from the root subnet to talk to. Error :{}",
                    err
                );
            }
        };
        let envelope = HttpRequestEnvelope {
            content: HttpReadStateContent::ReadState {
                read_state: HttpReadState {
                    sender: Blob(vec![4]),
                    paths: vec![
                        Path::new(vec![
                            b"subnet".into(),
                            subnet_id.get().into(),
                            b"public_key".into(),
                        ]),
                        Path::new(vec![
                            b"subnet".into(),
                            subnet_id.get().into(),
                            b"canister_ranges".into(),
                        ]),
                    ],
                    ingress_expiry: current_time_and_expiry_time().1.as_nanos_since_unix_epoch(),
                    nonce: None,
                },
            },
            sender_pubkey: None,
            sender_sig: None,
            sender_delegation: None,
        };
        let body = serde_cbor::ser::to_vec(&envelope).unwrap();
        let http_client = reqwest::blocking::Client::new();
        let ip_addr = node.ip_address.parse().unwrap();
        // any effective canister id can be used when invoking read_state here
        let address = format!(
            "http://{}/api/v2/canister/aaaaa-aa/read_state",
            SocketAddr::new(ip_addr, node.http_port)
        );
        info!(
            log,
            "Attempt to fetch delegation from root subnet node with url `{}`", address
        );
        let raw_response_res = match http_client
            .post(&address)
            .header(hyper::header::CONTENT_TYPE, CONTENT_TYPE_CBOR)
            .body(body)
            .send()
        {
            Ok(res) => res.bytes(),
            Err(err) => {
                log_err_and_backoff(&err);
                continue;
            }
        };
        match raw_response_res {
            Ok(raw_response) => {
                debug!(log, "Response from nns subnet: {:?}", raw_response);
                let response: HttpReadStateResponse = match serde_cbor::from_slice(&raw_response) {
                    Ok(r) => r,
                    Err(e) => {
                        log_err_and_backoff(&e);
                        continue;
                    }
                };
                let delegation = CertificateDelegation {
                    subnet_id: Blob(subnet_id.get().to_vec()),
                    certificate: response.certificate,
                };
                info!(log, "Setting NNS delegation to: {:?}", delegation);
                return Ok(Some(delegation));
            }
            Err(err) => {
                // Fetching the NNS delegation failed. Do a random backoff and try again.
                log_err_and_backoff(&err);
            }
        }
    }
    Err(Error::new(
        ErrorKind::TimedOut,
        format!(
            "Couldn't load NNS delegation after {} attempts.",
            MAX_FETCH_DELEGATION_ATTEMPTS
        ),
    ))
}
fn load_root_delegation ( state_reader : & dyn StateReader < State = ReplicatedState > , subnet_id : SubnetId , nns_subnet_id : SubnetId , log : & ReplicaLogger , ) -> Result < Option < CertificateDelegation > , Error > { if subnet_id == nns_subnet_id { info ! ( log " " ) ; // On the NNS subnet. No delegation needs to be fetched. return Ok ( None ) ; } for _ in 0 .. MAX_FETCH_DELEGATION_ATTEMPTS { info ! ( log " " ) ; let log_err_and_backoff = | err : & dyn std :: error :: Error | { // Fetching the NNS delegation failed. Do a random backoff and try again. let mut rng = rand :: thread_rng ( ) ; let backoff = Duration :: from_secs ( rng . gen_range ( 1 .. 15 ) ) ; warn ! ( log " \n \
 " backoff as_secs ( ) err ) ; std :: thread :: sleep ( backoff ) ; } ; let node = match get_random_node_from_nns_subnet ( state_reader , nns_subnet_id ) { Ok ( node_topology ) => node_topology , Err ( err ) => { fatal ! ( log " " err ) ; } } ; let envelope = HttpRequestEnvelope { content : HttpReadStateContent :: ReadState { read_state : HttpReadState { sender : Blob ( vec ! [ 4 ] ) , paths : vec ! [ Path new ( vec [ b" " into ( ) subnet_id get ( ) into ( ) b" " into ( ) ] ) Path new ( vec [ b" " into ( ) subnet_id get ( ) into ( ) b" " into ( ) ] ) ] , ingress_expiry : current_time_and_expiry_time ( ) . 1 . as_nanos_since_unix_epoch ( ) , nonce : None , } , } , sender_pubkey : None , sender_sig : None , sender_delegation : None , } ; let body = serde_cbor :: ser :: to_vec ( & envelope ) . unwrap ( ) ; let http_client = reqwest :: blocking :: Client :: new ( ) ; let ip_addr = node . ip_address . parse ( ) . unwrap ( ) ; // any effective canister id can be used when invoking read_state here let address = format ! ( " " SocketAddr new ( ip_addr node http_port ) ) ; info ! ( log " " address ) ; let raw_response_res = match http_client . post ( & address ) . header ( hyper :: header :: CONTENT_TYPE , CONTENT_TYPE_CBOR ) . body ( body ) . send ( ) { Ok ( res ) => res . bytes ( ) , Err ( err ) => { log_err_and_backoff ( & err ) ; continue ; } } ; match raw_response_res { Ok ( raw_response ) => { debug ! ( log " " raw_response ) ; let response : HttpReadStateResponse = match serde_cbor :: from_slice ( & raw_response ) { Ok ( r ) => r , Err ( e ) => { log_err_and_backoff ( & e ) ; continue ; } } ; let delegation = CertificateDelegation { subnet_id : Blob ( subnet_id . get ( ) . to_vec ( ) ) , certificate : response . certificate , } ; info ! ( log " " delegation ) ; return Ok ( Some ( delegation ) ) ; } Err ( err ) => { // Fetching the NNS delegation failed. Do a random backoff and try again. log_err_and_backoff ( & err ) ; } } } Err ( Error :: new ( ErrorKind :: TimedOut , format ! ( " " MAX_FETCH_DELEGATION_ATTEMPTS ) , ) ) }
Fetches a delegation from the NNS subnet to allow this subnet to issue
certificates on its behalf.
Fetches a delegation from the NNS subnet to allow this subnet to issue certificates on its behalf .
state_reader
&dyn StateReader<State = ReplicatedState>
subnet_id
SubnetId
nns_subnet_id
SubnetId
log
&ReplicaLogger