Skip to content

Commit b2c4f8d

Browse files
bingyanglinmuXxer
authored andcommitted
fix(core+tool): epochs_v2 backfill and formal-restore cleanup (#11870)
# Description of change Some cleanup for #11697 - **Local epoch backfill: only missing data counts as pruned (`iota-core`, `iota-types`).** Real storage failures were swallowed as "data pruned, retry once a newer snapshot is published". Absent-data errors now carry `Kind::Missing` (was `custom`) and only those end the best-effort replay; anything else propagates. Nothing else reads the kind. - **Operator doc fixes (`iota-config`, `docs`).** The config doc still described the removed background task (the backfill is synchronous and gates startup); the snapshots guide now documents the refuse-to-start case when even the latest snapshot is older than the node's pruned-away history. ## How the change has been tested - [x] Basic tests (linting, compilation, formatting, unit/integration tests) - [ ] Patch-specific tests (correctness, functionality coverage) - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have checked that new and existing unit tests pass locally with my changes
1 parent 986acb6 commit b2c4f8d

4 files changed

Lines changed: 20 additions & 12 deletions

File tree

crates/iota-config/src/node.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,11 @@ pub struct NodeConfig {
193193
#[serde(default)]
194194
pub state_snapshot_write_config: StateSnapshotConfig,
195195

196-
/// Read-side formal-snapshot source. When set, a running fullnode
197-
/// background-backfills its gRPC `epochs_v2` table from the snapshot's
198-
/// `EPOCH_INFO`. Disabled when `None` (the default).
196+
/// Read-side formal-snapshot source. When set, a fullnode whose gRPC
197+
/// `epochs_v2` table is incomplete backfills it from the snapshot's
198+
/// `EPOCH_INFO` synchronously at startup; with a gap and no source
199+
/// configured, the node refuses to start. Disabled when `None` (the
200+
/// default).
199201
#[serde(default, skip_serializing_if = "Option::is_none")]
200202
pub state_snapshot_read_config: Option<ObjectStoreConfig>,
201203

crates/iota-core/src/grpc_indexes.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ use iota_types::{
2626
storage::{
2727
AccountOwnedObjectInfo, DynamicFieldKey, EpochInfo, EpochInfoV2, OwnedObjectCursor,
2828
OwnedObjectIteratorItem, PackageVersionInfo, PackageVersionIteratorItem, PackageVersionKey,
29-
TransactionInfo, error::Error as StorageError,
29+
TransactionInfo,
30+
error::{Error as StorageError, Kind as StorageErrorKind},
3031
},
3132
};
3233
use serde::{Deserialize, Serialize};
@@ -943,9 +944,14 @@ impl IndexStoreTables {
943944
else {
944945
return Ok(None);
945946
};
946-
// Errors are "transaction/effects/objects already pruned" on
947-
// a healthy store.
948-
Ok(assemble_sparse_checkpoint_data(authority_store, summary, contents).ok())
947+
match assemble_sparse_checkpoint_data(authority_store, summary, contents) {
948+
Ok(data) => Ok(Some(data)),
949+
// Pruned-away transactions/effects/objects are the
950+
// expected end of what can be rebuilt locally; anything
951+
// else is a real storage failure and must propagate.
952+
Err(e) if e.kind() == StorageErrorKind::Missing => Ok(None),
953+
Err(e) => Err(e),
954+
}
949955
})()?;
950956
let Some(checkpoint_data) = checkpoint_data else {
951957
warn!(
@@ -1776,14 +1782,14 @@ fn assemble_sparse_checkpoint_data(
17761782
.multi_get_transaction_blocks(&transaction_digests)?
17771783
.into_iter()
17781784
.map(|maybe_transaction| {
1779-
maybe_transaction.ok_or_else(|| StorageError::custom("missing transaction"))
1785+
maybe_transaction.ok_or_else(|| StorageError::missing("missing transaction"))
17801786
})
17811787
.collect::<Result<Vec<_>, _>>()?;
17821788

17831789
let effects = authority_store
17841790
.multi_get_executed_effects(&transaction_digests)?
17851791
.into_iter()
1786-
.map(|maybe_effects| maybe_effects.ok_or_else(|| StorageError::custom("missing effects")))
1792+
.map(|maybe_effects| maybe_effects.ok_or_else(|| StorageError::missing("missing effects")))
17871793
.collect::<Result<Vec<_>, _>>()?;
17881794

17891795
let mut full_transactions = Vec::with_capacity(transactions.len());

crates/iota-types/src/storage/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ pub fn get_transaction_input_objects(
593593
.enumerate()
594594
.map(|(idx, maybe_object)| {
595595
maybe_object.ok_or_else(|| {
596-
StorageError::custom(format!(
596+
StorageError::missing(format!(
597597
"missing input object key {:?} from tx {}",
598598
input_object_keys[idx],
599599
effects.transaction_digest()
@@ -620,7 +620,7 @@ pub fn get_transaction_output_objects(
620620
.enumerate()
621621
.map(|(idx, maybe_object)| {
622622
maybe_object.ok_or_else(|| {
623-
StorageError::custom(format!(
623+
StorageError::missing(format!(
624624
"missing output object key {:?} from tx {}",
625625
output_object_keys[idx],
626626
effects.transaction_digest()

docs/content/operator/common/snapshots.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ state-snapshot-read-config:
249249

250250
</Tabs>
251251

252-
With this set, the node downloads the per-epoch metadata from the latest formal snapshot at startup (a few seconds; the large object files are not downloaded) and then starts normally.
252+
With this set, the node downloads the per-epoch metadata from the latest formal snapshot at startup (a few seconds; the large object files are not downloaded) and then starts normally. If even the latest snapshot is older than the node's executed history and the missing epochs' data is already pruned locally, the node still refuses to start: wait for a newer snapshot, restore from a formal snapshot, or disable the gRPC API.
253253

254254
## IOTA Foundation managed snapshots
255255

0 commit comments

Comments
 (0)