From 8368ace632fa3f6053947ee0a22c4fe16c0b50f6 Mon Sep 17 00:00:00 2001 From: Luke Valenta Date: Wed, 15 Jul 2026 16:24:04 -0400 Subject: [PATCH] Remove brute-force workaround for DurableObject name lookup The Durable Object runtime now passes through the name used with `idFromName`, so it is available inside the DO constructor via `state.id().name()` (cloudflare/workerd#2240). Previously `get_durable_object_name` brute-forced the name by enumerating every configured log (and batcher shard) and comparing `id_from_name` results against the DO's id. Replace it with the runtime-provided name: - Sequencers and cleaners are unsharded, so their DO name is the base log name; they read `state.id().name()` directly. - Batchers are always addressed with a shard suffix (`{name}_{shard_id:x}`), so a new `get_sharded_durable_object_base_name` helper strips the trailing `_{shard_id:x}` component to recover the base log name. --- crates/bootstrap_mtc_worker/src/batcher_do.rs | 16 ++----- crates/bootstrap_mtc_worker/src/cleaner_do.rs | 20 ++++---- .../bootstrap_mtc_worker/src/sequencer_do.rs | 24 +++++----- crates/ct_worker/src/batcher_do.rs | 16 ++----- crates/ct_worker/src/cleaner_do.rs | 20 ++++---- crates/ct_worker/src/sequencer_do.rs | 23 ++++----- crates/generic_log_worker/src/lib.rs | 47 +++++++------------ 7 files changed, 63 insertions(+), 103 deletions(-) diff --git a/crates/bootstrap_mtc_worker/src/batcher_do.rs b/crates/bootstrap_mtc_worker/src/batcher_do.rs index 6ef14ac..102c32f 100644 --- a/crates/bootstrap_mtc_worker/src/batcher_do.rs +++ b/crates/bootstrap_mtc_worker/src/batcher_do.rs @@ -1,5 +1,5 @@ use crate::{BootstrapMtcSequenceMetadata, CONFIG, init_sentry}; -use generic_log_worker::{BATCHER_BINDING, BatcherConfig, GenericBatcher, get_durable_object_name}; +use generic_log_worker::{BatcherConfig, GenericBatcher, get_sharded_durable_object_base_name}; #[allow(clippy::wildcard_imports)] use worker::*; @@ -12,22 +12,14 @@ impl std::panic::RefUnwindSafe for Batcher {} impl DurableObject for Batcher { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - BATCHER_BINDING, - &mut CONFIG - .logs - .iter() - .map(|(name, params)| (name.as_str(), params.num_batchers)), - ); - let params = &CONFIG.logs[name]; + let name = get_sharded_durable_object_base_name(&state); + let params = &CONFIG.logs[&name]; let config = BatcherConfig { - name: name.to_string(), max_batch_entries: params.max_batch_entries, batch_timeout_millis: params.batch_timeout_millis, enable_dedup: false, // deduplication is not currently supported location_hint: params.location_hint.clone(), + name, }; init_sentry(&env); Batcher(GenericBatcher::new(state, env, config)) diff --git a/crates/bootstrap_mtc_worker/src/cleaner_do.rs b/crates/bootstrap_mtc_worker/src/cleaner_do.rs index 6c670a2..08b694d 100644 --- a/crates/bootstrap_mtc_worker/src/cleaner_do.rs +++ b/crates/bootstrap_mtc_worker/src/cleaner_do.rs @@ -2,7 +2,7 @@ use std::time::Duration; use crate::{CONFIG, init_sentry, load_checkpoint_cosigner, load_origin}; use bootstrap_mtc_api::BootstrapMtcPendingLogEntry; -use generic_log_worker::{CLEANER_BINDING, CleanerConfig, GenericCleaner, get_durable_object_name}; +use generic_log_worker::{CleanerConfig, GenericCleaner}; use signed_note::VerifierList; use tlog_checkpoint::CheckpointSigner; use tlog_entry::PendingLogEntry; @@ -18,21 +18,19 @@ impl std::panic::RefUnwindSafe for Cleaner {} impl DurableObject for Cleaner { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - CLEANER_BINDING, - &mut CONFIG.logs.keys().map(|name| (name.as_str(), 0)), - ); - let params = &CONFIG.logs[name]; + let name = state + .id() + .name() + .expect("durable object name not provided by runtime"); + let params = &CONFIG.logs[&name]; let config = CleanerConfig { - name: name.to_string(), - origin: load_origin(name), + origin: load_origin(&name), data_path: BootstrapMtcPendingLogEntry::DATA_TILE_PATH, aux_path: BootstrapMtcPendingLogEntry::AUX_TILE_PATH, - verifiers: VerifierList::new(vec![load_checkpoint_cosigner(&env, name).verifier()]), + verifiers: VerifierList::new(vec![load_checkpoint_cosigner(&env, &name).verifier()]), clean_interval: Duration::from_secs(params.clean_interval_secs), + name, }; init_sentry(&env); diff --git a/crates/bootstrap_mtc_worker/src/sequencer_do.rs b/crates/bootstrap_mtc_worker/src/sequencer_do.rs index 23f12b8..6963599 100644 --- a/crates/bootstrap_mtc_worker/src/sequencer_do.rs +++ b/crates/bootstrap_mtc_worker/src/sequencer_do.rs @@ -13,8 +13,8 @@ use bootstrap_mtc_api::{ LandmarkSequence, }; use generic_log_worker::{ - CachedRoObjectBucket, CheckpointCallbacker, GenericSequencer, ObjectBucket, SEQUENCER_BINDING, - SequencerConfig, get_durable_object_name, load_public_bucket, + CachedRoObjectBucket, CheckpointCallbacker, GenericSequencer, ObjectBucket, SequencerConfig, + load_public_bucket, log_ops::{ProofError, prove_subtree_consistency}, }; use serde::{Deserialize, Serialize}; @@ -34,25 +34,23 @@ impl std::panic::RefUnwindSafe for Sequencer {} impl DurableObject for Sequencer { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - SEQUENCER_BINDING, - &mut CONFIG.logs.keys().map(|name| (name.as_str(), 0)), - ); - let params = &CONFIG.logs[name]; + let name = state + .id() + .name() + .expect("durable object name not provided by runtime"); + let params = &CONFIG.logs[&name]; let config = SequencerConfig { - name: name.to_string(), - origin: load_origin(name), - checkpoint_signers: vec![Box::new(load_checkpoint_cosigner(&env, name))], + origin: load_origin(&name), + checkpoint_signers: vec![Box::new(load_checkpoint_cosigner(&env, &name))], checkpoint_extension: Box::new(|_| vec![]), // no checkpoint extension for MTC sequence_interval: Duration::from_millis(params.sequence_interval_millis), max_sequence_skips: params.max_sequence_skips, enable_dedup: false, // deduplication is not currently supported sequence_skip_threshold_millis: params.sequence_skip_threshold_millis, location_hint: params.location_hint.clone(), - checkpoint_callback: checkpoint_callback(&env, name), + checkpoint_callback: checkpoint_callback(&env, &name), + name, }; init_sentry(&env); diff --git a/crates/ct_worker/src/batcher_do.rs b/crates/ct_worker/src/batcher_do.rs index d20a502..4561fe8 100644 --- a/crates/ct_worker/src/batcher_do.rs +++ b/crates/ct_worker/src/batcher_do.rs @@ -1,5 +1,5 @@ use crate::{CONFIG, StaticCTSequenceMetadata, init_sentry}; -use generic_log_worker::{BATCHER_BINDING, BatcherConfig, GenericBatcher, get_durable_object_name}; +use generic_log_worker::{BatcherConfig, GenericBatcher, get_sharded_durable_object_base_name}; #[allow(clippy::wildcard_imports)] use worker::*; @@ -12,22 +12,14 @@ impl std::panic::RefUnwindSafe for Batcher {} impl DurableObject for Batcher { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - BATCHER_BINDING, - &mut CONFIG - .logs - .iter() - .map(|(name, params)| (name.as_str(), params.num_batchers)), - ); - let params = &CONFIG.logs[name]; + let name = get_sharded_durable_object_base_name(&state); + let params = &CONFIG.logs[&name]; let config = BatcherConfig { - name: name.to_string(), max_batch_entries: params.max_batch_entries, batch_timeout_millis: params.batch_timeout_millis, enable_dedup: params.enable_dedup, location_hint: params.location_hint.clone(), + name, }; init_sentry(&env); Batcher(GenericBatcher::new(state, env, config)) diff --git a/crates/ct_worker/src/cleaner_do.rs b/crates/ct_worker/src/cleaner_do.rs index 726a5d4..955bdc2 100644 --- a/crates/ct_worker/src/cleaner_do.rs +++ b/crates/ct_worker/src/cleaner_do.rs @@ -1,7 +1,7 @@ use std::time::Duration; use crate::{CONFIG, init_sentry, load_checkpoint_signers, load_origin}; -use generic_log_worker::{CLEANER_BINDING, CleanerConfig, GenericCleaner, get_durable_object_name}; +use generic_log_worker::{CleanerConfig, GenericCleaner}; use signed_note::VerifierList; use static_ct_api::StaticCTPendingLogEntry; use tlog_entry::PendingLogEntry; @@ -17,26 +17,24 @@ impl std::panic::RefUnwindSafe for Cleaner {} impl DurableObject for Cleaner { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - CLEANER_BINDING, - &mut CONFIG.logs.keys().map(|name| (name.as_str(), 0)), - ); - let params = &CONFIG.logs[name]; + let name = state + .id() + .name() + .expect("durable object name not provided by runtime"); + let params = &CONFIG.logs[&name]; let config = CleanerConfig { - name: name.to_string(), - origin: load_origin(name), + origin: load_origin(&name), data_path: StaticCTPendingLogEntry::DATA_TILE_PATH, aux_path: StaticCTPendingLogEntry::AUX_TILE_PATH, verifiers: VerifierList::new( - load_checkpoint_signers(&env, name) + load_checkpoint_signers(&env, &name) .iter() .map(|s| s.verifier()) .collect(), ), clean_interval: Duration::from_secs(params.clean_interval_secs), + name, }; init_sentry(&env); diff --git a/crates/ct_worker/src/sequencer_do.rs b/crates/ct_worker/src/sequencer_do.rs index 83c3216..fa6897a 100644 --- a/crates/ct_worker/src/sequencer_do.rs +++ b/crates/ct_worker/src/sequencer_do.rs @@ -6,10 +6,7 @@ use std::time::Duration; use crate::{CONFIG, StaticCTSequenceMetadata, init_sentry, load_checkpoint_signers, load_origin}; -use generic_log_worker::{ - GenericSequencer, SEQUENCER_BINDING, SequencerConfig, empty_checkpoint_callback, - get_durable_object_name, -}; +use generic_log_worker::{GenericSequencer, SequencerConfig, empty_checkpoint_callback}; use static_ct_api::StaticCTLogEntry; #[allow(clippy::wildcard_imports)] use worker::*; @@ -23,18 +20,15 @@ impl std::panic::RefUnwindSafe for Sequencer {} impl DurableObject for Sequencer { fn new(state: State, env: Env) -> Self { - let name = get_durable_object_name( - &env, - &state, - SEQUENCER_BINDING, - &mut CONFIG.logs.keys().map(|name| (name.as_str(), 0)), - ); - let params = &CONFIG.logs[name]; + let name = state + .id() + .name() + .expect("durable object name not provided by runtime"); + let params = &CONFIG.logs[&name]; let config = SequencerConfig { - name: name.to_string(), - origin: load_origin(name), - checkpoint_signers: load_checkpoint_signers(&env, name), + origin: load_origin(&name), + checkpoint_signers: load_checkpoint_signers(&env, &name), checkpoint_extension: Box::new(|_| vec![]), // no checkpoint extensions for CT sequence_interval: Duration::from_millis(params.sequence_interval_millis), max_sequence_skips: params.max_sequence_skips, @@ -42,6 +36,7 @@ impl DurableObject for Sequencer { sequence_skip_threshold_millis: params.sequence_skip_threshold_millis, location_hint: params.location_hint.clone(), checkpoint_callback: empty_checkpoint_callback(), + name, }; init_sentry(&env); diff --git a/crates/generic_log_worker/src/lib.rs b/crates/generic_log_worker/src/lib.rs index 6516357..d3db49b 100644 --- a/crates/generic_log_worker/src/lib.rs +++ b/crates/generic_log_worker/src/lib.rs @@ -81,38 +81,25 @@ where bitcode::deserialize::(bytes).map_err(|e| Error::RustError(e.to_string())) } -/// Get the name for this Durable Object enumerating all possibilities. +/// Get the base log name for this sharded Durable Object. +/// +/// Sharded Durable Objects are addressed as `{name}_{shard_id:x}` (see +/// [`get_durable_object_stub`]), so the trailing shard suffix is stripped to +/// recover the base log name. /// /// # Panics -/// Panics if the name can't be found (e.g., if the wrong binding is used). -pub fn get_durable_object_name<'a>( - env: &Env, - state: &State, - binding: &str, - name_shard_tuples: &mut impl Iterator, -) -> &'a str { - let id = state.id(); - let namespace = env.durable_object(binding).unwrap(); - - let (name, _) = name_shard_tuples - .find(|(name, num_shards)| { - if *num_shards > 0 { - for shard_id in 0..*num_shards { - if id - == namespace - .id_from_name(&format!("{name}_{shard_id:x}")) - .unwrap() - { - return true; - } - } - false - } else { - id == namespace.id_from_name(name).unwrap() - } - }) - .expect("unable to find durable object name"); - name +/// +/// Panics if the runtime does not provide a name, or if the name does not +/// contain a shard suffix. +#[must_use] +pub fn get_sharded_durable_object_base_name(state: &State) -> String { + let name = state + .id() + .name() + .expect("durable object name not provided by runtime"); + name.rsplit_once('_') + .map(|(base, _)| base.to_string()) + .expect("sharded durable object name missing shard suffix") } /// Retrieve a Durable Object stub for the given parameters.