Skip to content

LocalChain::apply_changeset silently replaces the genesis block #2309

Description

@noahjoeris

Describe the bug

LocalChain::apply_changeset accepts a ChangeSet containing (0, Some(hash)) with a hash different from the chain's current genesis and silently rewrites the genesis block. apply_changeset_to_checkpoint (crates/chain/src/local_chain.rs) collects the existing checkpoints from the changeset's lowest height upwards, overwrites height 0 with the changeset entry, and rebuilds the chain via LocalChain::from_blocks, which never compares against the previous genesis.

The other mutation entrypoints enforce this invariant: apply_update (via merge_chains) returns CannotConnectError when the update disagrees on genesis, and insert_block / disconnect_from also refuse to alter height 0. apply_changeset is the only one that does not, so a persisted or externally constructed changeset with a wrong height-0 entry can move a chain onto a different genesis (e.g. another network) without any error.

This issue was found by AI.

To Reproduce

Add crates/chain/tests/test_genesis_changeset.rs and run cargo test -p bdk_chain --test test_genesis_changeset:

use bdk_chain::local_chain::{ChangeSet, LocalChain};
use bdk_testenv::{hash, local_chain};
use bitcoin::BlockHash;

#[test]
fn apply_changeset_does_not_replace_genesis() {
    let mut chain: LocalChain = local_chain![(0, hash!("G")), (1, hash!("A"))];
    let changeset: ChangeSet<BlockHash> = [(0, Some(hash!("not_G")))].into_iter().collect();

    let result = chain.apply_changeset(&changeset);

    assert_eq!(chain.genesis_hash(), hash!("G"), "apply_changeset returned {result:?}");
}

Current output:

assertion `left == right` failed: apply_changeset returned Ok(())
  left: 7fa96a46d03a598e64ddfaadb1525023753ae80470cacac37ebb5fbc837ebeb9
 right: dc4e3f5d6f1c6736abbdfa7a86e999ebdc7b132b82411571fc3909ac0ebc41fa

Expected behavior

apply_changeset should not silently replace an existing genesis block; a changeset that disagrees on height 0 should be handled consistently with the other LocalChain mutation methods.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    • Status
      In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions