From ab51cd157cce095e7f37e324d06dfbd72c40472f Mon Sep 17 00:00:00 2001 From: horologger Date: Sat, 13 Dec 2025 12:38:17 -0500 Subject: [PATCH 1/2] Fix panic when querying revoked spaces Fix data inconsistency in RevokeReason::Expired handling that caused panics when querying spaces that were revoked due to expiration. Root cause: Expired revocations only removed Outpoint->Spaceout mapping but left Space->Outpoint mapping, creating inconsistent state. Changes: - Remove Space->Outpoint mapping in Expired revocation handler - Handle inconsistencies gracefully in get_space_info by returning None and cleaning up orphaned Space->Outpoint mappings instead of panicking --- client/src/client.rs | 7 ++++++- client/src/store.rs | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/src/client.rs b/client/src/client.rs index b056343..f1996ac 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -279,7 +279,12 @@ impl Client { // Space => Outpoint mapping will be removed // since this type of revocation only happens when an // expired space is being re-opened for auction. - // No bids here so only remove Outpoint -> Spaceout + // Remove both Space -> Outpoint and Outpoint -> Spaceout mappings + if let Some(space) = update.output.spaceout.space.as_ref() { + let base_hash = Sha256::hash(space.name.as_ref()); + let space_key = SpaceKey::from(base_hash); + state.remove(space_key); + } let hash = OutpointKey::from_outpoint::(update.output.outpoint()); state.remove(hash); diff --git a/client/src/store.rs b/client/src/store.rs index e87dc3d..95a5f63 100644 --- a/client/src/store.rs +++ b/client/src/store.rs @@ -218,10 +218,19 @@ impl ChainState for LiveSnapshot { if let Some(outpoint) = outpoint { let spaceout = self.get_spaceout(&outpoint)?; - return Ok(Some(FullSpaceOut { - txid: outpoint.txid, - spaceout: spaceout.expect("should exist if outpoint exists"), - })); + // Handle data inconsistency gracefully: if outpoint exists but spaceout doesn't, + // this indicates the space was revoked but the space->outpoint mapping wasn't cleaned up. + // Clean up the inconsistent mapping and return None instead of panicking. + if let Some(spaceout) = spaceout { + return Ok(Some(FullSpaceOut { + txid: outpoint.txid, + spaceout, + })); + } else { + // Clean up the inconsistent space->outpoint mapping + self.remove(*space_hash); + return Ok(None); + } } Ok(None) } From 5831c5010cf8fb3c67b812a0b76fffb582c4d3bd Mon Sep 17 00:00:00 2001 From: horologger Date: Sat, 13 Dec 2025 12:48:22 -0500 Subject: [PATCH 2/2] Fix panic in open subcommand when spaceout is missing Fix data inconsistency handling in prepare_open that caused panics when opening spaces that were revoked due to expiration. Root cause: When an outpoint exists but spaceout doesn't (due to inconsistent state from Expired revocations), the code would panic with 'spaceout exists' instead of handling it gracefully. Changes: - Replace expect() with match statement to handle None case - Treat missing spaceout as new space (space was revoked, so it's effectively not registered anymore) --- protocol/src/script.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/protocol/src/script.rs b/protocol/src/script.rs index b2f77b8..95a53e0 100644 --- a/protocol/src/script.rs +++ b/protocol/src/script.rs @@ -148,10 +148,18 @@ impl SpaceScript { let existing = src.get_space_outpoint(&spacehash)?; match existing { None => OpenHistory::NewSpace(name.to_owned()), - Some(outpoint) => OpenHistory::ExistingSpace(FullSpaceOut { - txid: outpoint.txid, - spaceout: src.get_spaceout(&outpoint)?.expect("spaceout exists"), - }), + Some(outpoint) => { + // Handle data inconsistency: if spaceout doesn't exist, treat as new space + // This can happen if the space was revoked but the space->outpoint mapping + // wasn't cleaned up properly + match src.get_spaceout(&outpoint)? { + Some(spaceout) => OpenHistory::ExistingSpace(FullSpaceOut { + txid: outpoint.txid, + spaceout, + }), + None => OpenHistory::NewSpace(name.to_owned()), + } + } } }; let open = Ok(kind);