,
phantom: PhantomData,
polkadot_client: Arc,
}
impl JustifiedBlockAnnounceValidator {
pub fn new(authorities: Vec, polkadot_client: Arc) -> Self {
Self {
authorities,
phantom: Default::default(),
polkadot_client,
}
}
}
impl BlockAnnounceValidator for JustifiedBlockAnnounceValidator
where
P: ProvideRuntimeApi,
P::Api: ParachainHost,
{
fn validate(
&mut self,
header: &B::Header,
mut data: &[u8],
) -> Result> {
// If no data is provided the announce is valid.
if data.is_empty() {
return Ok(Validation::Success);
}
// Check data is a gossip message.
let gossip_message = GossipMessage::decode(&mut data).map_err(|_| {
Box::new(ClientError::BadJustification(
"cannot decode block announced justification, must be a gossip message".to_string(),
)) as Box<_>
})?;
// Check message is a gossip statement.
let gossip_statement = match gossip_message {
GossipMessage::Statement(gossip_statement) => gossip_statement,
_ => {
return Err(Box::new(ClientError::BadJustification(
"block announced justification statement must be a gossip statement"
.to_string(),
)) as Box<_>)
}
};
let GossipStatement {
relay_chain_leaf,
signed_statement: SignedStatement {
statement,
signature,
sender,
},
} = gossip_statement;
let signing_context = self
.polkadot_client
.runtime_api()
.signing_context(&BlockId::Hash(relay_chain_leaf))
.map_err(|e| Box::new(ClientError::Msg(format!("{:?}", e))) as Box<_>)?;
// Check that the signer is a legit validator.
let signer = self.authorities.get(sender as usize).ok_or_else(|| {
Box::new(ClientError::BadJustification(
"block accounced justification signer is a validator index out of bound"
.to_string(),
)) as Box<_>
})?;
// Check statement is correctly signed.
if !check_statement(&statement, &signature, signer.clone(), &signing_context) {
return Err(Box::new(ClientError::BadJustification(
"block announced justification signature is invalid".to_string(),
)) as Box<_>);
}
// Check statement is a candidate statement.
let candidate_receipt = match statement {
Statement::Candidate(candidate_receipt) => candidate_receipt,
_ => {
return Err(Box::new(ClientError::BadJustification(
"block announced justification statement must be a candidate statement"
.to_string(),
)) as Box<_>)
}
};
// Check the header in the candidate_receipt match header given header.
if header.encode() != candidate_receipt.head_data.0 {
return Err(Box::new(ClientError::BadJustification(
"block announced header does not match the one justified".to_string(),
)) as Box<_>);
}
Ok(Validation::Success)
}
}