Skip to content

Commit 2285ee1

Browse files
authored
graph, store: Reject grafts below the base's earliest block (#6610)
Mirrors the guard added for `graphman copy` in #6384. Without this, grafting at a block below `base.earliest_block_number` silently produces a destination missing all pre-graft mutable entity versions, and (when the base has dynamic data sources) handlers fail with `unexpected null in handler` because `data_sources$` registrations survive pruning while the entities they reference do not.
1 parent 60c0880 commit 2285ee1

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

graph/src/components/store/traits.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ pub trait SubgraphStore: Send + Sync + 'static {
219219
/// being set up
220220
async fn least_block_ptr(&self, id: &DeploymentHash) -> Result<Option<BlockPtr>, StoreError>;
221221

222+
/// Return the earliest block for which the deployment with the given
223+
/// `id` still has entity data. Blocks below this are either pre-`startBlock`
224+
/// or have been removed by pruning, and cannot serve as a graft or copy
225+
/// source.
226+
async fn earliest_block_number(&self, id: &DeploymentHash) -> Result<BlockNumber, StoreError>;
227+
222228
async fn is_healthy(&self, id: &DeploymentHash) -> Result<bool, StoreError>;
223229

224230
/// Find all deployment locators for the subgraph with the given hash.

graph/src/data/subgraph/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,24 @@ impl Graft {
600600
self.block,
601601
ptr.number - 1
602602
))),
603-
(Some(_), _) => Ok(()),
603+
(Some(_), _) => {
604+
// The graft block must be at or above the base's earliest
605+
// available block. Below that the base store no longer has
606+
// the entity versions the copy step would need: either the
607+
// base started above the graft block, or pruning has
608+
// removed the history.
609+
let earliest_block = store
610+
.earliest_block_number(&self.base)
611+
.await
612+
.map_err(|e| GraftBaseInvalid(e.to_string()))?;
613+
if self.block < earliest_block {
614+
return Err(GraftBaseInvalid(format!(
615+
"failed to graft onto `{}` at block {} since its earliest available block is {}",
616+
self.base, self.block, earliest_block
617+
)));
618+
}
619+
Ok(())
620+
}
604621
}
605622
}
606623
}

store/postgres/src/subgraph_store.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,12 @@ impl SubgraphStoreTrait for SubgraphStore {
18881888
store.block_ptr(site.cheap_clone()).await
18891889
}
18901890

1891+
async fn earliest_block_number(&self, id: &DeploymentHash) -> Result<BlockNumber, StoreError> {
1892+
let (store, site) = self.store(id).await?;
1893+
let state = store.deployment_state(site.cheap_clone()).await?;
1894+
Ok(state.earliest_block_number)
1895+
}
1896+
18911897
async fn is_healthy(&self, id: &DeploymentHash) -> Result<bool, StoreError> {
18921898
let (store, site) = self.store(id).await?;
18931899
let health = store.health(&site).await?;

0 commit comments

Comments
 (0)