Skip to content

Replace Unimplemented Revert Aux-Hook with No-Op and Handle current_dir Resolution Errors - #704

Closed
mozluk wants to merge 1 commit into
Quantus-Network:mainfrom
mozluk:mozluk-patch-1
Closed

mozluk wants to merge 1 commit into
Quantus-Network:mainfrom
mozluk:mozluk-patch-1

Conversation

@mozluk

@mozluk mozluk commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Description

This pull request resolves medium- and low-severity CLI panic vectors in chain identified during the Quantus workspace security audit (FM-13, FM-14).

Previously, invoking the revert subcommand triggered an unimplemented!() panic when executing consensus auxiliary data revert logic (leftover from Grandpa's removal)[cite: 49]. Additionally, resolving a relative path passed via --node-key-file relied on an unhandled std::env::current_dir().unwrap(), which panicked if the working directory was invalid or deleted[cite: 49].

Key Changes & Remediations

1. Safe No-Op Consensus Revert Hook (FM-13 - node/src/command.rs)

  • Eliminated unimplemented!() Panic: Replaced the unimplemented Grandpa consensus revert closure with a deliberate no-op closure returning Ok(()): ```rust let aux_revert = Box::new( |_client, _, _blocks| -> Result<(), sc_cli::Error> { Ok(()) }, );

Upstream Type Alignment: Conforms strictly to upstream sc_cli::AuxRevertHandler (Box<dyn FnOnce(...) -> Result<(), sc_cli::Error>>), allowing chain reverts to complete cleanly without crashing the node process[cite: 49].

2. Graceful Relative Node Key Resolution

(FM-14 - node/src/command.rs)Eliminated current_dir().unwrap(): Replaced .unwrap() with explicit error mapping via .map_err(...). Descriptive Input Error: Maps working directory lookup failures to sc_cli::Error::Input with an informative error message instead of an unhandled panic[cite: 49, 61].

How to Review

Inspect node/src/command.rs under Some(Subcommand::Revert(cmd)) to verify the no-op aux_revert closure. Inspect the relative path resolution branch for --node-key-file to verify the error mapping around std::env::current_dir().

…dir` Resolution Errors

### Description
This pull request resolves medium- and low-severity CLI panic vectors in `chain` identified during the Quantus workspace security audit (**FM-13, FM-14**).

Previously, invoking the `revert` subcommand triggered an `unimplemented!()` panic when executing consensus auxiliary data revert logic (leftover from Grandpa's removal)[cite: 49]. Additionally, resolving a relative path passed via `--node-key-file` relied on an unhandled `std::env::current_dir().unwrap()`, which panicked if the working directory was invalid or deleted[cite: 49].

### Key Changes & Remediations

#### 1. Safe No-Op Consensus Revert Hook (FM-13 - `node/src/command.rs`)
* **Eliminated `unimplemented!()` Panic:** Replaced the unimplemented Grandpa consensus revert closure with a deliberate no-op closure returning `Ok(())`:
  ```rust
  let aux_revert = Box::new(
      |_client, _, _blocks| -> Result<(), sc_cli::Error> { Ok(()) },
  );

Upstream Type Alignment: Conforms strictly to upstream sc_cli::AuxRevertHandler (Box<dyn FnOnce(...) -> Result<(), sc_cli::Error>>), allowing chain reverts to complete cleanly without crashing the node process[cite: 49].2. Graceful Relative Node Key Resolution (FM-14 - node/src/command.rs)Eliminated current_dir().unwrap(): Replaced .unwrap() with explicit error mapping via .map_err(...).  Descriptive Input Error: Maps working directory lookup failures to sc_cli::Error::Input with an informative error message instead of an unhandled panic[cite: 49, 61].How to ReviewInspect node/src/command.rs under Some(Subcommand::Revert(cmd)) to verify the no-op aux_revert closure.  Inspect the relative path resolution branch for --node-key-file to verify the error mapping around std::env::current_dir().

@n13 n13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question on the first item

Second item is good, and agree with that

Comment thread node/src/command.rs
let aux_revert = Box::new(|_client, _, _blocks| {
unimplemented!("TODO - g*randpa was removed.");
});
// Grandpa was removed from this chain, so there is no consensus

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General policy is to fail early vs hide bugs

I think it's better to throw, which is why we're throwing.

Why did you make this change?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If anything, a nice error message would be better, we don't want to ignore this

Comment thread node/src/command.rs
} else {
// This is a valid assumption because the node is run from the shell
std::env::current_dir().unwrap().join(path)
// This is a valid assumption because the node is run from the shell;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is good

@illuzen

illuzen commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

subsumed into #720

@illuzen illuzen closed this Oct 28, 2026
illuzen added a commit that referenced this pull request Oct 31, 2026
…upersedes #704) (#720)

* Replace Unimplemented Revert Aux-Hook with No-Op and Handle `current_dir` Resolution Errors

### Description
This pull request resolves medium- and low-severity CLI panic vectors in `chain` identified during the Quantus workspace security audit (**FM-13, FM-14**).

Previously, invoking the `revert` subcommand triggered an `unimplemented!()` panic when executing consensus auxiliary data revert logic (leftover from Grandpa's removal)[cite: 49]. Additionally, resolving a relative path passed via `--node-key-file` relied on an unhandled `std::env::current_dir().unwrap()`, which panicked if the working directory was invalid or deleted[cite: 49].

### Key Changes & Remediations

#### 1. Safe No-Op Consensus Revert Hook (FM-13 - `node/src/command.rs`)
* **Eliminated `unimplemented!()` Panic:** Replaced the unimplemented Grandpa consensus revert closure with a deliberate no-op closure returning `Ok(())`:
  ```rust
  let aux_revert = Box::new(
      |_client, _, _blocks| -> Result<(), sc_cli::Error> { Ok(()) },
  );

Upstream Type Alignment: Conforms strictly to upstream sc_cli::AuxRevertHandler (Box<dyn FnOnce(...) -> Result<(), sc_cli::Error>>), allowing chain reverts to complete cleanly without crashing the node process[cite: 49].2. Graceful Relative Node Key Resolution (FM-14 - node/src/command.rs)Eliminated current_dir().unwrap(): Replaced .unwrap() with explicit error mapping via .map_err(...).  Descriptive Input Error: Maps working directory lookup failures to sc_cli::Error::Input with an informative error message instead of an unhandled panic[cite: 49, 61].How to ReviewInspect node/src/command.rs under Some(Subcommand::Revert(cmd)) to verify the no-op aux_revert closure.  Inspect the relative path resolution branch for --node-key-file to verify the error mapping around std::env::current_dir().

* fix(node): revert QPoW achieved-work aux on `revert`

The revert aux hook previously panicked (unimplemented!) and the PR's
no-op would have left stale QPow:AchievedWork: entries behind. Delete the
entries for every block above the revert point, across all branches that
descend from it, before the backend rewinds the chain. Mirrors
sc_consensus_babe::revert's handling of block weights.

* fix(qpow): tie achieved-work cleanup to what the backend revert removes

sc_client_db::Backend::revert starts from the highest leaf on any branch,
can stop early once it hits canonicalized state, and afterwards prunes
only the leaf blocks above where it stopped. Deleting aux up front based
on min(blocks, best - finalized) therefore dropped entries for blocks that
survived a partial revert and missed fork leaves diverging below the
target.

sc_consensus_qpow::revert now owns the whole operation: it enumerates
every block above the lowest reachable target across all leaves, runs the
backend revert, and deletes entries only for candidates whose header is
gone afterwards. Lookup failures propagate instead of being treated as
'not a descendant'. The node's revert arm calls it directly rather than
through RevertCmd's pre-revert hook.

Regression tests run against the real sc-client-db memory backend for the
ordinary, partial-revert and divergent-fork cases, plus a lookup-failure
test for the candidate walk.

* test(client-db): drop vendored tests that need substrate-test-runtime-client

The vendored sc-client-db kept three upstream tests gated on the
test-helpers feature that call substrate_test_runtime_client, a
dev-dependency that was not carried over. They were never compiled until
sc-consensus-qpow started enabling test-helpers for its revert tests, at
which point feature unification under `cargo test --workspace` broke the
sc-client-db lib test build.

---------

Co-authored-by: mozluk <160273088+mozluk@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants