Approve block announcements of backed blocks (#394)

* Approve block announcements of backed blocks

If we receive a block announcement without a statement attached that
matches the latest backed block, it is valid and we need to approve the
block announcement to download the block.

* Fix tests

* Approve block announcement if it comes from the best known block

* Fetch backed block only when required
This commit is contained in:
Bastian Köcher
2021-04-12 13:54:07 +02:00
committed by GitHub
parent 605ab2b957
commit 959f5852ed
2 changed files with 129 additions and 45 deletions
+54 -7
View File
@@ -15,7 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use cumulus_test_service::runtime::{Block, Header};
use cumulus_test_service::runtime::{Block, Header, Hash};
use futures::{executor::block_on, poll, task::Poll};
use polkadot_node_primitives::{SignedFullStatement, Statement};
use polkadot_primitives::v1::{
@@ -37,6 +37,7 @@ use sp_keyring::Sr25519Keyring;
use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr};
use sp_runtime::RuntimeAppPublic;
use std::collections::BTreeMap;
use parking_lot::Mutex;
fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceError) -> bool) {
let error = *error
@@ -173,6 +174,7 @@ fn invalid_if_no_data_exceeds_best_known_number() {
let mut validator = make_validator_and_api().0;
let header = Header {
number: 1,
state_root: Hash::random(),
..default_header()
};
let res = block_on(validator.validate(&header, &[]));
@@ -184,6 +186,18 @@ fn invalid_if_no_data_exceeds_best_known_number() {
);
}
#[test]
fn valid_if_no_data_and_block_matches_best_known_block() {
let mut validator = make_validator_and_api().0;
let res = block_on(validator.validate(&default_header(), &[]));
assert_eq!(
res.unwrap(),
Validation::Success { is_new_best: true },
"validation is successful when the block hash matches the best known block",
);
}
#[test]
fn check_statement_is_encoded_correctly() {
let mut validator = make_validator_and_api().0;
@@ -331,13 +345,33 @@ fn relay_parent_not_imported_when_block_announce_is_processed() {
});
}
/// Ensures that when we receive a block announcement without a statement included, while the block
/// is not yet included by the node checking the announcement, but the node is already backed.
#[test]
fn block_announced_without_statement_and_block_only_backed() {
block_on(async move {
let (mut validator, api) = make_validator_and_api();
api.data.lock().has_pending_availability = true;
let header = default_header();
let validation = validator.validate(&header, &[]);
assert!(matches!(
validation.await,
Ok(Validation::Success { is_new_best: true })
));
});
}
#[derive(Default)]
struct ApiData {
validators: Vec<ValidatorId>,
has_pending_availability: bool,
}
struct TestApi {
data: Arc<ApiData>,
data: Arc<Mutex<ApiData>>,
relay_client: Arc<PClient>,
relay_backend: Arc<PBackend>,
}
@@ -348,9 +382,10 @@ impl TestApi {
let relay_backend = builder.backend();
Self {
data: Arc::new(ApiData {
data: Arc::new(Mutex::new(ApiData {
validators: vec![Sr25519Keyring::Alice.public().into()],
}),
has_pending_availability: false,
})),
relay_client: Arc::new(builder.build()),
relay_backend,
}
@@ -359,7 +394,7 @@ impl TestApi {
#[derive(Default)]
struct RuntimeApi {
data: Arc<ApiData>,
data: Arc<Mutex<ApiData>>,
}
impl ProvideRuntimeApi<PBlock> for TestApi {
@@ -376,7 +411,7 @@ impl ProvideRuntimeApi<PBlock> for TestApi {
sp_api::mock_impl_runtime_apis! {
impl ParachainHost<PBlock> for RuntimeApi {
fn validators(&self) -> Vec<ValidatorId> {
self.data.validators.clone()
self.data.lock().validators.clone()
}
fn validator_groups(&self) -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<BlockNumber>) {
@@ -407,7 +442,19 @@ sp_api::mock_impl_runtime_apis! {
}
fn candidate_pending_availability(&self, _: ParaId) -> Option<CommittedCandidateReceipt<PHash>> {
None
if self.data.lock().has_pending_availability {
Some(CommittedCandidateReceipt {
descriptor: CandidateDescriptor {
para_head: polkadot_parachain::primitives::HeadData(
default_header().encode(),
).hash(),
..Default::default()
},
..Default::default()
})
} else {
None
}
}
fn candidate_events(&self) -> Vec<CandidateEvent<PHash>> {