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, ®istration);
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
impl SimulatedDht
Sourcepub fn new(config: SimulationConfig) -> Self
pub fn new(config: SimulationConfig) -> Self
Creates a new simulated DHT with the given configuration.
Sourcepub fn with_verifier(config: SimulationConfig, verifier: Verifier) -> Self
pub fn with_verifier(config: SimulationConfig, verifier: Verifier) -> Self
Creates a simulated DHT with trusted roots for registration verification.
Sourcepub fn with_defaults() -> Self
pub fn with_defaults() -> Self
Creates a new simulated DHT with default configuration.
Sourcepub const fn config(&self) -> &SimulationConfig
pub const fn config(&self) -> &SimulationConfig
Returns the configuration.
Sourcepub fn register_batch(
&self,
registrations: Vec<(Registration, MutationProof)>,
) -> Result<usize, DhtError>
pub fn register_batch( &self, registrations: Vec<(Registration, MutationProof)>, ) -> Result<usize, DhtError>
Sourcepub fn simulate_migration(
&self,
agent_uri: &AgentUri,
new_endpoint: Endpoint,
agent_key: &SigningKey,
) -> Result<MigrationResult, DhtError>
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.
Sourcepub fn expire_stale(&self) -> usize
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.