Skip to content

Commit 9a69712

Browse files
authored
Find Durable Object name by iterating over config (#56)
Unfortunately, we can't use ctx.id.name to find a Durable Object's name within the DO itself (this previously worked only for local testing, but has been removed: cloudflare/workerd#4351). Instead, we can iterate over all possible names for the durable object based on the app configuration until we find the correct one. Also, clean up some clippy lint complaints.
1 parent 436f4b5 commit 9a69712

File tree

8 files changed

+86
-85
lines changed

8 files changed

+86
-85
lines changed

crates/ct_worker/src/batcher_do.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use crate::CONFIG;
2-
use generic_log_worker::{
3-
get_durable_object_name, get_durable_object_stub, load_cache_kv, BatcherConfig, GenericBatcher,
4-
};
2+
use generic_log_worker::{get_durable_object_stub, load_cache_kv, BatcherConfig, GenericBatcher};
53
use static_ct_api::StaticCTPendingLogEntry;
64
#[allow(clippy::wildcard_imports)]
75
use worker::*;
@@ -12,11 +10,27 @@ struct Batcher(GenericBatcher<StaticCTPendingLogEntry>);
1210
#[durable_object]
1311
impl DurableObject for Batcher {
1412
fn new(state: State, env: Env) -> Self {
15-
let (_, object_name) = get_durable_object_name(state).unwrap();
16-
// Get the log name from the batcher name (see 'get_durable_object_stub'
17-
// for how the batcher name is derived).
18-
let name = object_name.rsplit_once('_').unwrap().0;
19-
let params = &CONFIG.logs[name];
13+
// Find the Durable Object name by enumerating all possibilities.
14+
// TODO after update to worker > 0.6.0 use ObjectId::equals for comparison.
15+
let id = state.id().to_string();
16+
let namespace = env.durable_object("BATCHER").unwrap();
17+
let (name, params) = CONFIG
18+
.logs
19+
.iter()
20+
.find(|(name, params)| {
21+
for shard_id in 0..params.num_batchers {
22+
if id
23+
== namespace
24+
.id_from_name(&format!("{name}_{shard_id:x}"))
25+
.unwrap()
26+
.to_string()
27+
{
28+
return true;
29+
}
30+
}
31+
false
32+
})
33+
.expect("unable to find batcher name");
2034
let kv = load_cache_kv(&env, name).unwrap();
2135
let sequencer = get_durable_object_stub(
2236
&env,

crates/ct_worker/src/sequencer_do.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
use std::time::Duration;
77

88
use crate::{load_signing_key, load_witness_key, CONFIG};
9-
use generic_log_worker::{
10-
get_durable_object_name, load_public_bucket, GenericSequencer, SequencerConfig,
11-
};
9+
use generic_log_worker::{load_public_bucket, GenericSequencer, SequencerConfig};
1210
use prometheus::Registry;
1311
use static_ct_api::{StaticCTCheckpointSigner, StaticCTLogEntry};
1412
use tlog_tiles::{CheckpointSigner, Ed25519CheckpointSigner};
@@ -21,8 +19,15 @@ struct Sequencer(GenericSequencer<StaticCTLogEntry>);
2119
#[durable_object]
2220
impl DurableObject for Sequencer {
2321
fn new(state: State, env: Env) -> Self {
24-
let (state, name) = get_durable_object_name(state).unwrap();
25-
let params = &CONFIG.logs[&name];
22+
// Find the Durable Object name by enumerating all possibilities.
23+
// TODO after update to worker > 0.6.0 use ObjectId::equals for comparison.
24+
let id = state.id().to_string();
25+
let namespace = env.durable_object("SEQUENCER").unwrap();
26+
let (name, params) = CONFIG
27+
.logs
28+
.iter()
29+
.find(|(name, _)| id == namespace.id_from_name(name).unwrap().to_string())
30+
.expect("unable to find sequencer name");
2631

2732
// https://github.com/C2SP/C2SP/blob/main/static-ct-api.md#checkpoints
2833
// The origin line MUST be the submission prefix of the log as a schema-less URL with no trailing slashes.
@@ -37,8 +42,8 @@ impl DurableObject for Sequencer {
3742
let checkpoint_extension = Box::new(|_| vec![]);
3843

3944
let checkpoint_signers: Vec<Box<dyn CheckpointSigner>> = {
40-
let signing_key = load_signing_key(&env, &name).unwrap().clone();
41-
let witness_key = load_witness_key(&env, &name).unwrap().clone();
45+
let signing_key = load_signing_key(&env, name).unwrap().clone();
46+
let witness_key = load_witness_key(&env, name).unwrap().clone();
4247

4348
// Make the checkpoint signers from the secret keys and put them in a vec
4449
let signer = StaticCTCheckpointSigner::new(origin, signing_key)
@@ -50,11 +55,11 @@ impl DurableObject for Sequencer {
5055

5156
vec![Box::new(signer), Box::new(witness)]
5257
};
53-
let bucket = load_public_bucket(&env, &name).unwrap();
58+
let bucket = load_public_bucket(&env, name).unwrap();
5459
let registry = Registry::new();
5560

5661
let config = SequencerConfig {
57-
name,
62+
name: name.to_string(),
5863
origin: origin.to_string(),
5964
checkpoint_signers,
6065
checkpoint_extension,

crates/generic_log_worker/src/lib.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,6 @@ pub fn get_durable_object_stub(
8080
}
8181
}
8282

83-
/// Retrieve the
84-
/// [name](https://developers.cloudflare.com/durable-objects/api/id/#name) that
85-
/// was used to create a Durable Object Id with `id_from_name`. The signature of
86-
/// this function is a little funny since the only way to access the `State`'s
87-
/// inner `DurableObjectState` is via the `_inner()` method which takes
88-
/// ownership of the state. Thus, we just re-derive the State from the inner
89-
/// state and return it in case the calling function still needs it.
90-
///
91-
/// # Errors
92-
///
93-
/// Returns an error if the 'name' property is not present, for example if the
94-
/// object was created with a random ID.
95-
pub fn get_durable_object_name(state: State) -> Result<(State, String)> {
96-
let inner_state = state._inner();
97-
let id = inner_state.id()?;
98-
let obj = js_sys::Object::from(id);
99-
let name = js_sys::Reflect::get(&obj, &"name".into())?
100-
.as_string()
101-
.unwrap_or_default();
102-
Ok((State::from(inner_state), name))
103-
}
104-
10583
/// Return a handle for the public R2 bucket from which to serve this log's
10684
/// static assets.
10785
///

crates/generic_log_worker/src/log_ops.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use std::collections::HashMap;
3333
use std::{
3434
cell::RefCell,
3535
cmp::{Ord, Ordering},
36+
string::String,
3637
sync::LazyLock,
3738
};
3839
use thiserror::Error;
@@ -226,7 +227,7 @@ struct TileWithBytes {
226227
b: Vec<u8>,
227228
}
228229

229-
/// A fake TileReader that just accumulates the tiles that we'll need for a proof
230+
/// A fake `TileReader` that just accumulates the tiles that we'll need for a proof
230231
#[derive(Default)]
231232
struct ProofPreparer(RefCell<Vec<TlogTile>>);
232233

@@ -241,13 +242,13 @@ impl TileReader for ProofPreparer {
241242
*self.0.borrow_mut() = tiles
242243
.iter()
243244
.map(|t| {
244-
if t.height() != TlogTile::HEIGHT {
245+
if t.height() == TlogTile::HEIGHT {
246+
Ok(TlogTile::new(t.level(), t.level_index(), t.width(), None))
247+
} else {
245248
Err(TlogError::InvalidInput(
246249
"SimpleTlogTileReader cannot read tiles of height not equal to 8"
247250
.to_string(),
248251
))
249-
} else {
250-
Ok(TlogTile::new(t.level(), t.level_index(), t.width(), None))
251252
}
252253
})
253254
.collect::<Result<Vec<_>, TlogError>>()?;
@@ -261,7 +262,7 @@ impl TileReader for ProofPreparer {
261262
fn save_tiles(&self, _tiles: &[Tile], _data: &[Vec<u8>]) {}
262263
}
263264

264-
/// A thin wrapper around a map of tlog tile ⇒ bytestring. Implements TileReader
265+
/// A thin wrapper around a map of tlog tile ⇒ bytestring. Implements `TileReader`
265266
/// so we can use it for producing inclusion proofs.
266267
struct SimpleTlogTileReader(HashMap<TlogTile, Vec<u8>>);
267268

@@ -359,7 +360,7 @@ pub(crate) async fn create_log(
359360
let sth = tree
360361
.sign(
361362
&config.origin,
362-
&extensions.iter().map(|e| e.as_str()).collect::<Vec<_>>(),
363+
&extensions.iter().map(String::as_str).collect::<Vec<_>>(),
363364
&dyn_signers,
364365
&mut rand::thread_rng(),
365366
)
@@ -538,11 +539,6 @@ impl SequenceState {
538539
})
539540
}
540541

541-
/// Returns the current number of leaves in the tree
542-
pub(crate) fn num_leaves(&self) -> u64 {
543-
self.tree.size()
544-
}
545-
546542
/// Returns the current checkpoint
547543
pub(crate) fn checkpoint(&self) -> &[u8] {
548544
&self.checkpoint
@@ -983,7 +979,7 @@ async fn sequence_entries<L: LogEntry>(
983979
let new_checkpoint = tree
984980
.sign(
985981
&config.origin,
986-
&extensions.iter().map(|e| e.as_str()).collect::<Vec<_>>(),
982+
&extensions.iter().map(String::as_str).collect::<Vec<_>>(),
987983
&dyn_signers,
988984
&mut rand::thread_rng(),
989985
)
@@ -1422,7 +1418,7 @@ mod tests {
14221418
fn sequence_one_leaf(n: u64) {
14231419
let mut log = TestLog::new();
14241420
for i in 0..n {
1425-
let old_tree_hash = log.sequence_state.as_ref().map(|s| s.tree.hash().clone());
1421+
let old_tree_hash = log.sequence_state.as_ref().map(|s| *s.tree.hash());
14261422

14271423
let res = log.add_certificate();
14281424
log.sequence().unwrap();
@@ -1456,7 +1452,7 @@ mod tests {
14561452
tree_size - 1,
14571453
old_tree_hash.unwrap(),
14581454
)
1459-
.unwrap()
1455+
.unwrap();
14601456
}
14611457
}
14621458
// Check that the static CT log is valid
@@ -1476,7 +1472,7 @@ mod tests {
14761472
.unwrap()
14771473
.unwrap();
14781474
// Extract the correct hash from the tile
1479-
let leaf_tile_idx = (i % TlogTile::FULL_WIDTH as u64) as usize;
1475+
let leaf_tile_idx = usize::try_from(i % u64::from(TlogTile::FULL_WIDTH)).unwrap();
14801476
Hash(
14811477
leaf_tile_data[HASH_SIZE * leaf_tile_idx..HASH_SIZE * (leaf_tile_idx + 1)]
14821478
.try_into()

crates/generic_log_worker/src/sequencer_do.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ pub struct SequencerConfig {
5656
pub enable_dedup: bool,
5757
}
5858

59-
/// GET query structure for the sequencer's /prove_inclusion endpoint
59+
/// GET query structure for the sequencer's `/prove_inclusion` endpoint
6060
#[derive(Serialize, Deserialize)]
6161
pub struct ProveInclusionQuery {
6262
pub leaf_index: LeafIndex,
6363
}
6464

65-
/// GET response structure for the sequencer's /prove_inclusion endpoint
65+
/// GET response structure for the sequencer's `/prove_inclusion` endpoint
6666
#[serde_as]
6767
#[derive(Serialize, Deserialize)]
6868
pub struct ProveInclusionResponse {
@@ -265,17 +265,6 @@ impl<L: LogEntry> GenericSequencer<L> {
265265
.collect::<Vec<_>>()
266266
}
267267

268-
/// Returns the number of entries in this log
269-
pub fn log_size(&self) -> Result<u64, WorkerError> {
270-
if let Some(s) = self.sequence_state.as_ref() {
271-
Ok(s.num_leaves())
272-
} else {
273-
Err(WorkerError::RustError(
274-
"cannot get log size of a sequencer with no sequence state".to_string(),
275-
))
276-
}
277-
}
278-
279268
/// Loads the sequence state if it's not already loaded.
280269
///
281270
/// # Errors

crates/mtc_worker/src/batcher_do.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use crate::CONFIG;
2-
use generic_log_worker::{
3-
get_durable_object_name, get_durable_object_stub, load_cache_kv, BatcherConfig, GenericBatcher,
4-
};
2+
use generic_log_worker::{get_durable_object_stub, load_cache_kv, BatcherConfig, GenericBatcher};
53
use mtc_api::MtcPendingLogEntry;
64
#[allow(clippy::wildcard_imports)]
75
use worker::*;
@@ -12,11 +10,27 @@ struct Batcher(GenericBatcher<MtcPendingLogEntry>);
1210
#[durable_object]
1311
impl DurableObject for Batcher {
1412
fn new(state: State, env: Env) -> Self {
15-
let (_, object_name) = get_durable_object_name(state).unwrap();
16-
// Get the log name from the batcher name (see 'get_durable_object_stub'
17-
// for how the batcher name is derived).
18-
let name = object_name.rsplit_once('_').unwrap().0;
19-
let params = &CONFIG.logs[name];
13+
// Find the Durable Object name by enumerating all possibilities.
14+
// TODO after update to worker > 0.6.0 use ObjectId::equals for comparison.
15+
let id = state.id().to_string();
16+
let namespace = env.durable_object("BATCHER").unwrap();
17+
let (name, params) = CONFIG
18+
.logs
19+
.iter()
20+
.find(|(name, params)| {
21+
for shard_id in 0..params.num_batchers {
22+
if id
23+
== namespace
24+
.id_from_name(&format!("{name}_{shard_id:x}"))
25+
.unwrap()
26+
.to_string()
27+
{
28+
return true;
29+
}
30+
}
31+
false
32+
})
33+
.expect("unable to find batcher name");
2034
let kv = load_cache_kv(&env, name).unwrap();
2135
let sequencer = get_durable_object_stub(
2236
&env,

crates/mtc_worker/src/sequencer_do.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
use std::time::Duration;
77

88
use crate::{load_signing_key, load_witness_key, CONFIG};
9-
use generic_log_worker::{
10-
get_durable_object_name, load_public_bucket, GenericSequencer, SequencerConfig,
11-
};
9+
use generic_log_worker::{load_public_bucket, GenericSequencer, SequencerConfig};
1210
use mtc_api::MtcLogEntry;
1311
use prometheus::Registry;
1412
use tlog_tiles::{CheckpointSigner, Ed25519CheckpointSigner};
@@ -21,8 +19,15 @@ struct Sequencer(GenericSequencer<MtcLogEntry>);
2119
#[durable_object]
2220
impl DurableObject for Sequencer {
2321
fn new(state: State, env: Env) -> Self {
24-
let (state, name) = get_durable_object_name(state).unwrap();
25-
let params = &CONFIG.logs[&name];
22+
// Find the Durable Object name by enumerating all possibilities.
23+
// TODO after update to worker > 0.6.0 use ObjectId::equals for comparison.
24+
let id = state.id().to_string();
25+
let namespace = env.durable_object("SEQUENCER").unwrap();
26+
let (name, params) = CONFIG
27+
.logs
28+
.iter()
29+
.find(|(name, _)| id == namespace.id_from_name(name).unwrap().to_string())
30+
.expect("unable to find sequencer name");
2631

2732
// https://github.com/C2SP/C2SP/blob/main/static-ct-api.md#checkpoints
2833
// The origin line MUST be the submission prefix of the log as a schema-less URL with no trailing slashes.
@@ -37,8 +42,8 @@ impl DurableObject for Sequencer {
3742
let checkpoint_extension = Box::new(|_| vec![]);
3843

3944
let checkpoint_signers: Vec<Box<dyn CheckpointSigner>> = {
40-
let signing_key = load_signing_key(&env, &name).unwrap().clone();
41-
let witness_key = load_witness_key(&env, &name).unwrap().clone();
45+
let signing_key = load_signing_key(&env, name).unwrap().clone();
46+
let witness_key = load_witness_key(&env, name).unwrap().clone();
4247

4348
// Make the checkpoint signers from the secret keys and put them in a vec
4449
let signer = Ed25519CheckpointSigner::new(origin, signing_key)
@@ -50,11 +55,11 @@ impl DurableObject for Sequencer {
5055

5156
vec![Box::new(signer), Box::new(witness)]
5257
};
53-
let bucket = load_public_bucket(&env, &name).unwrap();
58+
let bucket = load_public_bucket(&env, name).unwrap();
5459
let registry = Registry::new();
5560

5661
let config = SequencerConfig {
57-
name,
62+
name: name.to_string(),
5863
origin: origin.to_string(),
5964
checkpoint_signers,
6065
checkpoint_extension,

crates/tlog_tiles/src/checkpoint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ impl Checkpoint {
266266
&origin,
267267
n,
268268
hash,
269-
&extensions.iter().map(|e| e.as_str()).collect::<Vec<_>>(),
269+
&extensions.iter().map(String::as_str).collect::<Vec<_>>(),
270270
)
271271
}
272272

0 commit comments

Comments
 (0)