/// Error when applying blocks to a local chain.
#[derive(Clone, Debug, PartialEq)]
pub enum ApplyBlockError {
- /// Genesis block is missing or would be altered.
+ /// Genesis block is missing.
MissingGenesis,
/// Block's `prev_blockhash` doesn't match the expected block.
PrevBlockhashMismatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ApplyBlockError::MissingGenesis => {
- write!(f, "genesis block is missing or would be altered")
+ write!(f, "genesis block is missing")
}
ApplyBlockError::PrevBlockhashMismatch { expected } => write!(
f,
}
}
} else {
+ // Genesis block (height 0) cannot be replaced. If the original and
+ // update disagree on genesis, they belong to different chains.
+ if o.height() == 0 && !o.is_placeholder() {
+ return Err(CannotConnectError {
+ try_include_height: 0,
+ });
+ }
// We have an invalidation height so we set the height to the updated hash and
// also purge all the original chain block hashes above this block.
changeset.blocks.insert(u.height(), u.data());
},
TestLocalChain {
name: "fix blockhash before agreement point",
- chain: local_chain![(0, hash!("im-wrong")), (1, hash!("we-agree"))],
- update: chain_update![(0, hash!("fix")), (1, hash!("we-agree"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("im-wrong")), (2, hash!("we-agree"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("fix")), (2, hash!("we-agree"))],
exp: ExpectedResult::Ok {
- changeset: &[(0, Some(hash!("fix")))],
- init_changeset: &[(0, Some(hash!("fix"))), (1, Some(hash!("we-agree")))],
+ changeset: &[(1, Some(hash!("fix")))],
+ init_changeset: &[(0, Some(hash!("_"))), (1, Some(hash!("fix"))), (2, Some(hash!("we-agree")))],
},
},
// B and C are in both chain and update
],
},
},
+ // Conflicting genesis with no point of agreement should fail.
+ // | 0 | 2
+ // chain | _ B
+ // update | _' B'
+ TestLocalChain {
+ name: "conflicting genesis without agreement point",
+ chain: local_chain![(0, hash!("_")), (2, hash!("B"))],
+ update: chain_update![(0, hash!("_'")), (2, hash!("B'"))],
+ exp: ExpectedResult::Err(CannotConnectError {
+ try_include_height: 0,
+ }),
+ },
]
.into_iter()
.for_each(TestLocalChain::run);