Skip to content

Commit df9f957

Browse files
node: Add graphman chain rebuild-storage command
Adds the rebuild-storage subcommand to graphman chain. Looks up the chain in public.chains, rejects shared-storage chains, prompts for confirmation when storage already exists (--force skips the prompt), then delegates to BlockStore::rebuild_chain_storage.
1 parent 27bf875 commit df9f957

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

node/src/bin/manager.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,20 @@ pub enum ChainCommand {
603603
/// The block number to ingest
604604
number: BlockNumber,
605605
},
606+
607+
/// Rebuild a chain's storage schema and reset head metadata.
608+
///
609+
/// If the storage schema is missing, rebuilds it silently.
610+
/// If the storage already exists, prompts for confirmation before
611+
/// dropping and rebuilding it (use --force to skip the prompt).
612+
RebuildStorage {
613+
/// Chain name (must be an existing chain, see 'chain list')
614+
#[clap(value_parser = clap::builder::NonEmptyStringValueParser::new())]
615+
chain_name: String,
616+
/// Skip confirmation prompt when storage already exists
617+
#[clap(long, short)]
618+
force: bool,
619+
},
606620
}
607621

608622
#[derive(Clone, Debug, Subcommand)]
@@ -1581,6 +1595,10 @@ async fn main() -> anyhow::Result<()> {
15811595
ctx.chain_store_and_adapter(&name).await?;
15821596
commands::chain::ingest(&logger, chain_store, ethereum_adapter, number).await
15831597
}
1598+
RebuildStorage { chain_name, force } => {
1599+
let (block_store, primary) = ctx.block_store_and_primary_pool().await;
1600+
commands::chain::rebuild_storage(primary, block_store, chain_name, force).await
1601+
}
15841602
}
15851603
}
15861604
Stats(cmd) => {

node/src/manager/commands/chain.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use graph::cheap_clone::CheapClone;
1010
use graph::components::network_provider::ChainName;
1111
use graph::components::store::ChainIdStore;
1212
use graph::components::store::StoreError;
13+
use graph::prelude::anyhow::Context as _;
1314
use graph::prelude::BlockNumber;
1415
use graph::prelude::ChainStore as _;
1516
use graph::prelude::LightEthereumBlock;
@@ -30,8 +31,10 @@ use graph_store_postgres::ChainStore;
3031
use graph_store_postgres::PoolCoordinator;
3132
use graph_store_postgres::ScopedFutureExt;
3233
use graph_store_postgres::Shard;
34+
use graph_store_postgres::Storage;
3335
use graph_store_postgres::{command_support::catalog::block_store, ConnectionPool};
3436

37+
use crate::manager::prompt::prompt_for_confirmation;
3538
use crate::network_setup::Networks;
3639

3740
pub async fn list(primary: ConnectionPool, store: BlockStore) -> Result<(), Error> {
@@ -329,3 +332,55 @@ pub async fn ingest(
329332
}
330333
Ok(())
331334
}
335+
336+
pub async fn rebuild_storage(
337+
primary: ConnectionPool,
338+
store: BlockStore,
339+
name: String,
340+
force: bool,
341+
) -> Result<(), Error> {
342+
let mut conn = primary.get().await?;
343+
344+
let chain = block_store::find_chain(&mut conn, &name)
345+
.await?
346+
.ok_or_else(|| {
347+
anyhow!(
348+
"Chain {} not found in public.chains.\n\
349+
This command only supports chains already present in metadata.",
350+
name
351+
)
352+
})?;
353+
354+
if matches!(chain.storage, Storage::Shared) {
355+
bail!(
356+
"Chain {} uses shared storage public and cannot be rebuilt with this command.",
357+
name
358+
);
359+
}
360+
361+
let namespace = chain.storage.to_string();
362+
let shard = &chain.shard;
363+
let ident = chain.network_identifier()?;
364+
365+
if store.has_namespace(&chain).await? {
366+
let prompt = format!(
367+
"Storage {namespace} for chain {name} already exists on shard {shard}.\n\
368+
This will drop and rebuild chain storage. All cached blocks and call cache \
369+
data in that namespace will be permanently deleted.\n\
370+
Proceed?"
371+
);
372+
if !force && !prompt_for_confirmation(&prompt)? {
373+
println!("Aborting.");
374+
return Ok(());
375+
}
376+
}
377+
378+
store
379+
.rebuild_chain_storage(&name, &ident)
380+
.await
381+
.with_context(|| format!("Failed to rebuild storage {namespace} for chain {name}"))?;
382+
383+
println!("Successfully rebuilt storage {namespace} for chain {name} on shard {shard}.");
384+
385+
Ok(())
386+
}

0 commit comments

Comments
 (0)