Skip to content

Fix channel manager race panic #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 2, 2022

Conversation

MaxFangX
Copy link
Contributor

@MaxFangX MaxFangX commented Oct 18, 2022

The race:

  • (1) If a channel manager is starting for the first time, it gets its initial block hash by calling BlockSource::get_blockchain_info() and constructing a BestBlock out of that.
  • (2) During the initial chain sync, if chain_tip.is_none() then the best chain_tip is retrieved using lightning_block_sync::init::validate_best_block_header() which similarly uses BlockSource::get_best_block()
  • If blocks were mined between (1) and (2), the channel manager’s block hash will be at a lower height than that of the block hash contained inside the chain_tip fed to the SpvClient. Suppose that this results in the channel manager being at block 1 and the SpvClient being at block 2. Once block 3 comes in and the SpvClient detects it via poll_best_tip(), the SpvClient computes the ChainDifference between its saved chain_tip value and block 3, concluding that it just needs to connect block 3. However, when Listen::filtered_block_connected is called using the data in block 3, the channel manager panics with “Blocks must be connected in chain-order - the connected header must build on the last connected header” - because block 3’s prev block hash is block 2’s block hash, rather than block 1’s block hash which the channel manager expects

This commit fixes it by removing the fresh channel manager's query to the block source, instead deriving its best block from the validated block header using a new .to_best_block() method.

Depends on lightningdevkit/rust-lightning#1777.

This can be tested locally by adding the following to ldk-sample's Cargo.toml:

[patch.crates-io]
lightning = { git = "https://github.com/lexe-tech/rust-lightning", branch = "max/best-block-header-best-block", features = ["max_level_trace"]}
lightning-block-sync = { git = "https://github.com/lexe-tech/rust-lightning", branch = "max/best-block-header-best-block", features = [ "rpc-client" ] }

Fixes #74.

@TheBlueMatt
Copy link
Contributor

Needs rebase, should pass CI now. Thanks!

@MaxFangX MaxFangX force-pushed the fix-chanman-race-panic branch 2 times, most recently from eae9614 to 9f08ea3 Compare November 2, 2022 18:55
@MaxFangX
Copy link
Contributor Author

MaxFangX commented Nov 2, 2022

CI passed, ready for re-review @TheBlueMatt @jkczyz

The race:
- (1) If a channel manager is starting for the first time, it gets its
  initial block hash by calling BlockSource::get_blockchain_info() and
  constructing a BestBlock out of that.
- (2) During the initial chain sync, if chain_tip.is_none() then the
  best chain_tip is retrieved using
  lightning_block_sync::init::validate_best_block_header() which
  similarly uses BlockSource::get_best_block()
- If blocks were mined between (1) and (2), the channel manager’s block
  hash will be at a lower height than that of the block hash contained
  inside the chain_tip fed to the SpvClient. Suppose that this results
  in the channel manager being at block 1 and the SpvClient being at
  block 2. Once block 3 comes in and the SpvClient detects it via
  poll_best_tip(), the SpvClient computes the ChainDifference between
  its saved chain_tip value and block 3, concluding that it just needs
  to connect block 3. However, when Listen::filtered_block_connected is
  called using the data in block 3, the channel manager panics with
  “Blocks must be connected in chain-order - the connected header must
  build on the last connected header” - because block 3’s prev block
  hash is block 2’s block hash, rather than block 1’s block hash which
  the channel manager expects

This commit fixes it by removing the fresh channel manager's query to
the block source, instead deriving its best block from the validated
block header using a new `.to_best_block()` method.
@MaxFangX MaxFangX force-pushed the fix-chanman-race-panic branch from 9f08ea3 to 430084f Compare November 2, 2022 20:16
@jkczyz jkczyz merged commit 0c2522a into lightningdevkit:main Nov 2, 2022
@MaxFangX MaxFangX deleted the fix-chanman-race-panic branch November 2, 2022 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Race Between Initial Block Hashes can cause panic
5 participants