dfinity / agent-rs

A collection of libraries and tools for building software around the Internet Computer, in Rust.
https://sdk.dfinity.org/
Apache License 2.0
124 stars 77 forks source link

feat(BOUN-1168): add dynamic route provider (Discovery Library) #568

Closed nikolay-komarevskiy closed 3 months ago

nikolay-komarevskiy commented 5 months ago

Description

API boundary nodes (BNs) have already been introduced into the Internet Computer (IC) landscape. Currently, the agent does not support dynamic discovery of existing API BNs or the dynamic routing of requests to these nodes based on specific strategies, such as latency. This PR enhances the agent by adding functionality for the dynamic routing to API BNs. In a nutshell the newly introduced DynamicRouteProvider is the implementation of the RouteProvider trait.

Example usage 1 - ergonomic:

#[tokio::main]
async fn main() {
    let client = Client::builder().build().expect("failed to build a client");

    // Initialize the agent with a custom dynamic transport layer
    // NOTE: this requires an async context
    let agent = Agent::builder()
        .with_discovery_transport(client)
        .await
        .build()
        .expect("failed to create an agent");
    //
    // ... use agent
    //

}

Example usage 2 - fully customized:

#[tokio::main]
async fn main() {
    let client = Client::builder().build().expect("failed to build a client");
    let seeds = vec![Node::new("ic0.app").expect("domain is invalid")];
    let snapshot = LatencyRoutingSnapshot::new();
    let route_provider = DynamicRouteProviderBuilder::new(snapshot, seeds, client.clone()).build().await;
    let transport = ReqwestTransport::create_with_client_route(Arc::new(route_provider), client.clone()).unwrap();

    // Initialize the agent with a custom dynamic transport layer
    let agent = Agent::builder()
        .with_transport(transport)
        .build()
        .expect("failed to create an agent");
    //
    // ... use agent
    //

}

How Has This Been Tested?

  1. Added a mainnet test
  2. Created a draft PR and tested on the api_boundary_node_decentralization_test, which is a system-test in the ic-repo. NOTE: @adamspofford-dfinity and @lwshang the suggestion to fully remove the fetch_root_key() was probably wrong. As system-test fails without this call. Could You commit a conditional fetch_root_key() invocation, which would work for both mainnet and testnets.

Checklist: