use anyhow::anyhow;
use crate::{
common::namespace::Namespace,
consensus::{
beacon::EpochTime,
roothash::Header,
state::{
beacon::ImmutableState as BeaconState, roothash::ImmutableState as RoothashState,
ConsensusState,
},
tendermint::{verifier::Cache, LightBlockMeta},
verifier::Error,
LightBlock,
},
};
pub fn verify_namespace(trusted: Namespace, runtime_header: &Header) -> Result<(), Error> {
if trusted != runtime_header.namespace {
return Err(Error::VerificationFailed(anyhow!(
"header namespace does not match trusted runtime id"
)));
}
Ok(())
}
pub fn verify_consensus_advance(cache: &Cache, consensus_block: &LightBlock) -> Result<(), Error> {
if consensus_block.height < cache.last_verified_height {
return Err(Error::VerificationFailed(anyhow!(
"height seems to have moved backwards"
)));
}
Ok(())
}
pub fn verify_round_advance(
cache: &Cache,
runtime_header: &Header,
consensus_block: &LightBlock,
epoch: EpochTime,
) -> Result<(), Error> {
if runtime_header.round < cache.last_verified_round {
return Err(Error::VerificationFailed(anyhow!(
"round seems to have moved backwards"
)));
}
if epoch < cache.last_verified_epoch {
return Err(Error::VerificationFailed(anyhow!(
"epoch seems to have moved backwards"
)));
}
if runtime_header.round > cache.last_verified_round
&& consensus_block.height <= cache.last_verified_height
{
return Err(Error::VerificationFailed(anyhow!(
"consensus height did not advance but runtime round did"
)));
}
Ok(())
}
pub fn verify_time(runtime_header: &Header, consensus_block: &LightBlockMeta) -> Result<(), Error> {
let consensus_header = &consensus_block
.signed_header
.as_ref()
.ok_or_else(|| Error::VerificationFailed(anyhow!("missing signed header")))?
.header;
if runtime_header.timestamp != consensus_header.time.unix_timestamp() as u64 {
return Err(Error::VerificationFailed(anyhow!(
"runtime block timestamp inconsistent with consensus time"
)));
}
Ok(())
}
pub fn verify_state_root(state: &ConsensusState, runtime_header: &Header) -> Result<(), Error> {
let roothash_state = RoothashState::new(&state);
let state_root = roothash_state
.state_root(runtime_header.namespace)
.map_err(|err| {
Error::VerificationFailed(anyhow!("failed to retrieve trusted state root: {}", err))
})?;
if runtime_header.state_root != state_root {
return Err(Error::VerificationFailed(anyhow!(
"state root mismatch (expected: {} got: {})",
state_root,
runtime_header.state_root
)));
}
Ok(())
}
pub fn verify_epoch(state: &ConsensusState, epoch: EpochTime) -> Result<(), Error> {
let beacon_state = BeaconState::new(&state);
let current_epoch = beacon_state
.epoch()
.map_err(|err| Error::VerificationFailed(anyhow!("failed to retrieve epoch: {}", err)))?;
if current_epoch != epoch {
return Err(Error::VerificationFailed(anyhow!(
"epoch number mismatch (expected: {} got: {})",
current_epoch,
epoch,
)));
}
Ok(())
}