mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 22:01:04 +00:00
Block announce validation should use the correct Validation result (#315)
* Block announce validation should use the correct `Validation` result The error variant is just for internal errors and we need to return `Failure` always when the other node send us an invalid statement. * Update network/src/lib.rs Co-authored-by: Sergei Shulepov <sergei@parity.io> Co-authored-by: Sergei Shulepov <sergei@parity.io>
This commit is contained in:
+39
-27
@@ -54,10 +54,12 @@ use futures::{
|
|||||||
};
|
};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use std::{fmt, marker::PhantomData, pin::Pin, sync::Arc, convert::TryFrom};
|
use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc};
|
||||||
|
|
||||||
use wait_on_relay_chain_block::WaitOnRelayChainBlock;
|
use wait_on_relay_chain_block::WaitOnRelayChainBlock;
|
||||||
|
|
||||||
|
const LOG_TARGET: &str = "cumulus-network";
|
||||||
|
|
||||||
type BoxedError = Box<dyn std::error::Error + Send>;
|
type BoxedError = Box<dyn std::error::Error + Send>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -84,26 +86,33 @@ impl BlockAnnounceData {
|
|||||||
/// Validate that the receipt, statement and announced header match.
|
/// Validate that the receipt, statement and announced header match.
|
||||||
///
|
///
|
||||||
/// This will not check the signature, for this you should use [`BlockAnnounceData::check_signature`].
|
/// This will not check the signature, for this you should use [`BlockAnnounceData::check_signature`].
|
||||||
fn validate(&self, encoded_header: Vec<u8>) -> Result<(), BlockAnnounceError> {
|
fn validate(&self, encoded_header: Vec<u8>) -> Result<(), Validation> {
|
||||||
let candidate_hash = if let CompactStatement::Candidate(h) = self.statement.payload() {
|
let candidate_hash = if let CompactStatement::Candidate(h) = self.statement.payload() {
|
||||||
h
|
h
|
||||||
} else {
|
} else {
|
||||||
return Err(BlockAnnounceError(
|
log::debug!(
|
||||||
"`CompactStatement` isn't the candidate variant!".into(),
|
target: LOG_TARGET,
|
||||||
));
|
"`CompactStatement` isn't the candidate variant!",
|
||||||
|
);
|
||||||
|
return Err(Validation::Failure { disconnect: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
if *candidate_hash != self.receipt.hash() {
|
if *candidate_hash != self.receipt.hash() {
|
||||||
return Err(BlockAnnounceError(
|
log::debug!(
|
||||||
"Receipt candidate hash doesn't match candidate hash in statement".into(),
|
target: LOG_TARGET,
|
||||||
));
|
"Receipt candidate hash doesn't match candidate hash in statement",
|
||||||
|
);
|
||||||
|
return Err(Validation::Failure { disconnect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if polkadot_parachain::primitives::HeadData(encoded_header).hash() != self.receipt.descriptor.para_head
|
if polkadot_parachain::primitives::HeadData(encoded_header).hash()
|
||||||
|
!= self.receipt.descriptor.para_head
|
||||||
{
|
{
|
||||||
return Err(BlockAnnounceError(
|
log::debug!(
|
||||||
"Receipt para head hash doesn't match the hash of the header in the block announcement".into(),
|
target: LOG_TARGET,
|
||||||
));
|
"Receipt para head hash doesn't match the hash of the header in the block announcement",
|
||||||
|
);
|
||||||
|
return Err(Validation::Failure { disconnect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -112,7 +121,7 @@ impl BlockAnnounceData {
|
|||||||
/// Check the signature of the statement.
|
/// Check the signature of the statement.
|
||||||
///
|
///
|
||||||
/// Returns an `Err(_)` if it failed.
|
/// Returns an `Err(_)` if it failed.
|
||||||
fn check_signature<P>(&self, relay_chain_client: &Arc<P>) -> Result<(), BlockAnnounceError>
|
fn check_signature<P>(&self, relay_chain_client: &Arc<P>) -> Result<Validation, BlockAnnounceError>
|
||||||
where
|
where
|
||||||
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
P: ProvideRuntimeApi<PBlock> + Send + Sync + 'static,
|
||||||
P::Api: ParachainHost<PBlock>,
|
P::Api: ParachainHost<PBlock>,
|
||||||
@@ -143,10 +152,12 @@ impl BlockAnnounceData {
|
|||||||
let signer = match authorities.get(validator_index as usize) {
|
let signer = match authorities.get(validator_index as usize) {
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
None => {
|
None => {
|
||||||
return Err(BlockAnnounceError(
|
log::debug!(
|
||||||
"block accouncement justification signer is a validator index out of bound"
|
target: LOG_TARGET,
|
||||||
.to_string(),
|
"Block announcement justification signer is a validator index out of bound",
|
||||||
));
|
);
|
||||||
|
|
||||||
|
return Ok(Validation::Failure { disconnect: true })
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,12 +167,15 @@ impl BlockAnnounceData {
|
|||||||
.check_signature(&signing_context, &signer)
|
.check_signature(&signing_context, &signer)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
return Err(BlockAnnounceError(
|
log::debug!(
|
||||||
"block announcement justification signature is invalid".to_string(),
|
target: LOG_TARGET,
|
||||||
));
|
"Block announcement justification signature is invalid.",
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(Validation::Failure { disconnect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(Validation::Success { is_new_best: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,9 +354,9 @@ where
|
|||||||
let wait_on_relay_chain_block = self.wait_on_relay_chain_block.clone();
|
let wait_on_relay_chain_block = self.wait_on_relay_chain_block.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
block_announce_data
|
if let Err(e) = block_announce_data.validate(header_encoded) {
|
||||||
.validate(header_encoded)
|
return Ok(e);
|
||||||
.map_err(|e| Box::new(e) as Box<_>)?;
|
}
|
||||||
|
|
||||||
let relay_parent = block_announce_data.receipt.descriptor.relay_parent;
|
let relay_parent = block_announce_data.receipt.descriptor.relay_parent;
|
||||||
|
|
||||||
@@ -353,9 +367,7 @@ where
|
|||||||
|
|
||||||
block_announce_data
|
block_announce_data
|
||||||
.check_signature(&relay_chain_client)
|
.check_signature(&relay_chain_client)
|
||||||
.map_err(|e| Box::new(e) as Box<_>)?;
|
.map_err(|e| Box::new(e) as Box<_>)
|
||||||
|
|
||||||
Ok(Validation::Success { is_new_best: true })
|
|
||||||
}
|
}
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,14 +205,8 @@ fn check_signer_is_legit_validator() {
|
|||||||
let (signed_statement, header) = block_on(make_gossip_message_and_header_using_genesis(api, 1));
|
let (signed_statement, header) = block_on(make_gossip_message_and_header_using_genesis(api, 1));
|
||||||
let data = BlockAnnounceData::try_from(signed_statement).unwrap().encode();
|
let data = BlockAnnounceData::try_from(signed_statement).unwrap().encode();
|
||||||
|
|
||||||
let res = block_on(validator.validate(&header, &data))
|
let res = block_on(validator.validate(&header, &data));
|
||||||
.err()
|
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
||||||
.expect("Should fail on invalid validator");
|
|
||||||
|
|
||||||
assert!(matches!(
|
|
||||||
*res.downcast::<BlockAnnounceError>().unwrap(),
|
|
||||||
BlockAnnounceError(x) if x.contains("signer is a validator")
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -227,16 +221,8 @@ fn check_statement_is_correctly_signed() {
|
|||||||
let last = data.len() - 1;
|
let last = data.len() - 1;
|
||||||
data[last] = data[last].wrapping_add(1);
|
data[last] = data[last].wrapping_add(1);
|
||||||
|
|
||||||
let res = block_on(validator.validate(&header, &data))
|
let res = block_on(validator.validate(&header, &data));
|
||||||
.err()
|
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
||||||
.expect("Validation should fail if the statement is not signed correctly");
|
|
||||||
|
|
||||||
check_error(res, |error| {
|
|
||||||
matches!(
|
|
||||||
error,
|
|
||||||
BlockAnnounceError(x) if x.contains("signature is invalid")
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -276,16 +262,8 @@ fn check_statement_seconded() {
|
|||||||
statement: signed_statement.convert_payload(),
|
statement: signed_statement.convert_payload(),
|
||||||
}.encode();
|
}.encode();
|
||||||
|
|
||||||
let res = block_on(validator.validate(&header, &data))
|
let res = block_on(validator.validate(&header, &data));
|
||||||
.err()
|
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
||||||
.expect("validation should fail if not seconded statement");
|
|
||||||
|
|
||||||
check_error(res, |error| {
|
|
||||||
matches!(
|
|
||||||
error,
|
|
||||||
BlockAnnounceError(x) if x.contains("`CompactStatement` isn't the candidate variant")
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -297,16 +275,8 @@ fn check_header_match_candidate_receipt_header() {
|
|||||||
let data = BlockAnnounceData::try_from(signed_statement).unwrap().encode();
|
let data = BlockAnnounceData::try_from(signed_statement).unwrap().encode();
|
||||||
header.number = 300;
|
header.number = 300;
|
||||||
|
|
||||||
let res = block_on(validator.validate(&header, &data))
|
let res = block_on(validator.validate(&header, &data));
|
||||||
.err()
|
assert_eq!(Validation::Failure { disconnect: true }, res.unwrap());
|
||||||
.expect("validation should fail if the header in doesn't match");
|
|
||||||
|
|
||||||
check_error(res, |error| {
|
|
||||||
matches!(
|
|
||||||
error,
|
|
||||||
BlockAnnounceError(x) if x.contains("Receipt para head hash doesn't match")
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test that ensures that we postpone the block announce verification until
|
/// Test that ensures that we postpone the block announce verification until
|
||||||
|
|||||||
Reference in New Issue
Block a user