mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 09:51:02 +00:00
118 lines
3.6 KiB
Rust
118 lines
3.6 KiB
Rust
// Copyright 2021 Parity Technologies (UK) Ltd.
|
|
// This file is part of Parity Bridges Common.
|
|
|
|
// Parity Bridges Common is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Parity Bridges Common is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use crate::{Config, Pallet};
|
|
use bp_runtime::FilterCall;
|
|
use frame_support::{dispatch::CallableCallFor, traits::IsSubType};
|
|
use sp_runtime::{
|
|
traits::Header,
|
|
transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction},
|
|
};
|
|
|
|
/// Validate Grandpa headers in order to avoid "mining" transactions that provide outdated
|
|
/// bridged chain headers. Without this validation, even honest relayers may lose their funds
|
|
/// if there are multiple relays running and submitting the same information.
|
|
impl<
|
|
Call: IsSubType<CallableCallFor<Pallet<T, I>, T>>,
|
|
T: frame_system::Config<RuntimeCall = Call> + Config<I>,
|
|
I: 'static,
|
|
> FilterCall<Call> for Pallet<T, I>
|
|
{
|
|
fn validate(call: &<T as frame_system::Config>::RuntimeCall) -> TransactionValidity {
|
|
let bundled_block_number = match call.is_sub_type() {
|
|
Some(crate::Call::<T, I>::submit_finality_proof { ref finality_target, .. }) =>
|
|
*finality_target.number(),
|
|
_ => return Ok(ValidTransaction::default()),
|
|
};
|
|
|
|
let best_finalized = crate::BestFinalized::<T, I>::get();
|
|
let best_finalized_number = match best_finalized {
|
|
Some(best_finalized_id) => best_finalized_id.number(),
|
|
None => return InvalidTransaction::Call.into(),
|
|
};
|
|
|
|
if best_finalized_number >= bundled_block_number {
|
|
log::trace!(
|
|
target: crate::LOG_TARGET,
|
|
"Rejecting obsolete bridged header: bundled {:?}, best {:?}",
|
|
bundled_block_number,
|
|
best_finalized_number,
|
|
);
|
|
|
|
return InvalidTransaction::Stale.into()
|
|
}
|
|
|
|
Ok(ValidTransaction::default())
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::FilterCall;
|
|
use crate::{
|
|
mock::{run_test, test_header, RuntimeCall, TestNumber, TestRuntime},
|
|
BestFinalized,
|
|
};
|
|
use bp_runtime::HeaderId;
|
|
use bp_test_utils::make_default_justification;
|
|
|
|
fn validate_block_submit(num: TestNumber) -> bool {
|
|
crate::Pallet::<TestRuntime>::validate(&RuntimeCall::Grandpa(crate::Call::<
|
|
TestRuntime,
|
|
(),
|
|
>::submit_finality_proof {
|
|
finality_target: Box::new(test_header(num)),
|
|
justification: make_default_justification(&test_header(num)),
|
|
}))
|
|
.is_ok()
|
|
}
|
|
|
|
fn sync_to_header_10() {
|
|
let header10_hash = sp_core::H256::default();
|
|
BestFinalized::<TestRuntime, ()>::put(HeaderId(10, header10_hash));
|
|
}
|
|
|
|
#[test]
|
|
fn extension_rejects_obsolete_header() {
|
|
run_test(|| {
|
|
// when current best finalized is #10 and we're trying to import header#5 => tx is
|
|
// rejected
|
|
sync_to_header_10();
|
|
assert!(!validate_block_submit(5));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn extension_rejects_same_header() {
|
|
run_test(|| {
|
|
// when current best finalized is #10 and we're trying to import header#10 => tx is
|
|
// rejected
|
|
sync_to_header_10();
|
|
assert!(!validate_block_submit(10));
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn extension_accepts_new_header() {
|
|
run_test(|| {
|
|
// when current best finalized is #10 and we're trying to import header#15 => tx is
|
|
// accepted
|
|
sync_to_header_10();
|
|
assert!(validate_block_submit(15));
|
|
});
|
|
}
|
|
}
|