Skip to main content

SimulatedDht

Struct SimulatedDht 

Source
pub struct SimulatedDht { /* private fields */ }
Expand description

Simulated DHT for evaluation.

Single-process, in-memory implementation that faithfully models DHT behavior without network overhead. Suitable for evaluation and testing.

§Thread Safety

One RwLock covers all of the state, so lookups run concurrently with each other and writes are exclusive. There is deliberately not a lock per index: every write already touches all of them, so splitting them bought no concurrency and cost an acquisition order to get wrong.

§Examples

use agent_uri::{AgentUri, CapabilityPath, TrustRoot};
use agent_uri_attestation::SigningKey;
use agent_uri_dht::{
    Dht, Endpoint, MutationProof, Query, ReadOptions, Registration, SimulatedDht,
    SimulationConfig, WriteOptions,
};
use futures::executor::block_on;

// Explicitly unverified because this example isolates indexing behavior.
let dht = SimulatedDht::new(
    SimulationConfig::default().with_verify_attestations(false)
);

let uri = AgentUri::parse("agent://anthropic.com/assistant/chat/llm_01h455vb4pex5vsknk084sn02q").unwrap();
let agent_key = SigningKey::generate();
let registration = Registration::new(
    uri.clone(),
    agent_key.verifying_key(),
    vec![Endpoint::https("agent.anthropic.com")],
);

let proof = MutationProof::sign_registration(&agent_key, &registration);

block_on(dht.register(registration, &proof, WriteOptions::default())).unwrap();

let query = Query::exact(
    TrustRoot::parse("anthropic.com").unwrap(),
    CapabilityPath::parse("assistant/chat").unwrap(),
);
let page = block_on(dht.lookup(&query, &ReadOptions::default())).unwrap();

assert_eq!(page.len(), 1);

Implementations§

Source§

impl SimulatedDht

Source

pub fn new(config: SimulationConfig) -> Self

Creates a new simulated DHT with the given configuration.

Source

pub fn with_verifier(config: SimulationConfig, verifier: Verifier) -> Self

Creates a simulated DHT with trusted roots for registration verification.

Source

pub fn with_defaults() -> Self

Creates a new simulated DHT with default configuration.

Source

pub const fn config(&self) -> &SimulationConfig

Returns the configuration.

Source

pub fn register_batch( &self, registrations: Vec<(Registration, MutationProof)>, ) -> Result<usize, DhtError>

Registers multiple agents in batch.

More efficient than individual registrations for bulk setup.

§Returns

The number of successfully registered agents.

§Errors

Returns DhtError if a critical error occurs (though individual registration failures are silently counted).

Source

pub fn stats(&self) -> DhtStats

Returns statistics about the DHT state.

§Panics

Panics if the internal lock is poisoned.

Source

pub fn simulate_migration( &self, agent_uri: &AgentUri, new_endpoint: Endpoint, agent_key: &SigningKey, ) -> Result<MigrationResult, DhtError>

Simulates agent migration with timing.

Takes the agent’s signing key because it plays the part of the agent: it reads the record’s current sequence number and mints the proof the migration needs, exactly as a migrating agent would.

§Errors

Returns DhtError::NotFound if the agent is not registered, or DhtError::Unauthorized if agent_key is not the key the record names.

§Panics

Panics if the internal lock is poisoned.

Source

pub fn clear(&self)

Clears all registrations.

§Panics

Panics if the internal lock is poisoned.

Source

pub fn expire_stale(&self) -> usize

Removes expired registrations.

Returns the number of registrations removed.

A simulation under load does not need this call: writes evict what has lapsed as they go, when SimulationConfig::auto_expire is set. It is here for a store that has gone quiet with garbage still in it, and for one that has turned automatic expiry off. It removes what is due either way, because the configuration decides whether expiry happens unasked, not whether it happens when asked.

The cost is the number of records actually due rather than the number stored: deadlines are kept in order, so a store where nothing has lapsed costs one comparison (issue #55).

§Panics

Panics if the internal lock is poisoned.

Trait Implementations§

Source§

impl Dht for SimulatedDht

Source§

fn register<'life0, 'life1, 'async_trait>( &'life0 self, registration: Registration, proof: &'life1 MutationProof, options: WriteOptions, ) -> Pin<Box<dyn Future<Output = Result<WriteReceipt, DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Registers an agent at its capability path. Read more
Source§

fn update_endpoint<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, agent_uri: &'life1 AgentUri, new_endpoints: Vec<Endpoint>, proof: &'life2 MutationProof, options: WriteOptions, ) -> Pin<Box<dyn Future<Output = Result<WriteReceipt, DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Updates an existing registration’s endpoints. Read more
Source§

fn refresh<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, agent_uri: &'life1 AgentUri, ttl: Duration, expires_at: SystemTime, proof: &'life2 MutationProof, options: WriteOptions, ) -> Pin<Box<dyn Future<Output = Result<WriteReceipt, DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Extends an existing registration’s lifetime. Read more
Source§

fn deregister<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, agent_uri: &'life1 AgentUri, proof: &'life2 MutationProof, _options: WriteOptions, ) -> Pin<Box<dyn Future<Output = Result<(), DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Removes a registration. Read more
Source§

fn lookup<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, query: &'life1 Query, options: &'life2 ReadOptions, ) -> Pin<Box<dyn Future<Output = Result<Page<Registration>, DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Looks up agents matching a capability query. Read more
Source§

fn local_id(&self) -> NodeId

Returns this node’s identity in the overlay.
Source§

fn bootstrap<'life0, 'life1, 'async_trait>( &'life0 self, peers: &'life1 [PeerAddr], ) -> Pin<Box<dyn Future<Output = Result<(), DhtError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Joins the overlay through the given peers. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V