Skip to content

Commit

Permalink
Bridge: check bridge GRANDPA pallet call limits from signed extension (
Browse files Browse the repository at this point in the history
…paritytech#4385)

silent, because it'll be deployed with the
paritytech#4102, where this code
has been introduced

I've planned originally to avoid doing that check in the runtime code,
because it **may be** checked offchain. But actually, the check is quite
cheap and we could do that onchain too.
  • Loading branch information
svyatonik authored and hitchhooker committed Jun 5, 2024
1 parent 18511d0 commit e400f0d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 2 deletions.
67 changes: 65 additions & 2 deletions bridges/modules/grandpa/src/call_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,13 @@ impl<T: Config<I>, I: 'static> SubmitFinalityProofHelper<T, I> {
}
}

// we do not check whether the header matches free submission criteria here - it is the
// relayer responsibility to check that
// let's also check whether the header submission fits the hardcoded limits. A normal
// relayer would check that before submitting a transaction (since limits are constants
// and do not depend on a volatile runtime state), but the ckeck itself is cheap, so
// let's do it here too
if !call_info.fits_limits() {
return Err(Error::<T, I>::HeaderOverflowLimits);
}

Ok(improved_by)
}
Expand Down Expand Up @@ -468,6 +473,64 @@ mod tests {
})
}

#[test]
fn extension_rejects_new_header_if_it_overflow_size_limits() {
run_test(|| {
let mut large_finality_target = test_header(10 + FreeHeadersInterval::get() as u64);
large_finality_target
.digest_mut()
.push(DigestItem::Other(vec![42u8; 1024 * 1024]));
let justification_params = JustificationGeneratorParams {
header: large_finality_target.clone(),
..Default::default()
};
let large_justification = make_justification_for_header(justification_params);

let bridge_grandpa_call = crate::Call::<TestRuntime, ()>::submit_finality_proof_ex {
finality_target: Box::new(large_finality_target),
justification: large_justification,
current_set_id: 0,
is_free_execution_expected: true,
};
sync_to_header_10();

// if overflow size limits => Err
FreeHeadersRemaining::<TestRuntime, ()>::put(2);
assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa(
bridge_grandpa_call.clone(),
),)
.is_err());
})
}

#[test]
fn extension_rejects_new_header_if_it_overflow_weight_limits() {
run_test(|| {
let finality_target = test_header(10 + FreeHeadersInterval::get() as u64);
let justification_params = JustificationGeneratorParams {
header: finality_target.clone(),
ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY,
..Default::default()
};
let justification = make_justification_for_header(justification_params);

let bridge_grandpa_call = crate::Call::<TestRuntime, ()>::submit_finality_proof_ex {
finality_target: Box::new(finality_target),
justification,
current_set_id: 0,
is_free_execution_expected: true,
};
sync_to_header_10();

// if overflow weight limits => Err
FreeHeadersRemaining::<TestRuntime, ()>::put(2);
assert!(RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa(
bridge_grandpa_call.clone(),
),)
.is_err());
})
}

#[test]
fn extension_rejects_new_header_if_free_execution_is_requested_and_improved_by_is_below_expected(
) {
Expand Down
3 changes: 3 additions & 0 deletions bridges/modules/grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,9 @@ pub mod pallet {
/// The submitter wanted free execution, but the difference between best known and
/// bundled header numbers is below the `FreeHeadersInterval`.
BelowFreeHeaderInterval,
/// The header (and its finality) submission overflows hardcoded chain limits: size
/// and/or weight are larger than expected.
HeaderOverflowLimits,
}

/// Called when new free header is imported.
Expand Down

0 comments on commit e400f0d

Please sign in to comment.