Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/offchain-worker-executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl<

fn get_latest_parentchain_header(&self) -> Result<ParentchainBlock::Header> {
let header = self.validator_accessor.execute_on_validator(|v| {
let latest_parentchain_header = v.latest_finalized_header(v.num_relays())?;
let latest_parentchain_header = v.latest_finalized_header()?;
Ok(latest_parentchain_header)
})?;
Ok(header)
Expand Down
7 changes: 3 additions & 4 deletions core/parentchain/block-importer/src/block_importer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ use crate::{error::Result, ImportParentchainBlocks};
use ita_stf::ParentchainHeader;
use itc_parentchain_indirect_calls_executor::ExecuteIndirectCalls;
use itc_parentchain_light_client::{
concurrent_access::ValidatorAccess, BlockNumberOps, ExtrinsicSender, LightClientState,
Validator,
concurrent_access::ValidatorAccess, BlockNumberOps, ExtrinsicSender, Validator,
};
use itp_extrinsics_factory::CreateExtrinsics;
use itp_stf_executor::traits::StfUpdateState;
Expand Down Expand Up @@ -127,9 +126,9 @@ impl<
// Check if there are any extrinsics in the to-be-imported block that we sent and cached in the light-client before.
// If so, remove them now from the cache.
if let Err(e) = self.validator_accessor.execute_mut_on_validator(|v| {
v.check_xt_inclusion(v.num_relays(), &signed_block.block)?;
v.check_xt_inclusion(&signed_block.block)?;

v.submit_block(v.num_relays(), &signed_block)
v.submit_block(&signed_block)
}) {
error!("[Validator] Header submission failed: {:?}", e);
return Err(e.into())
Expand Down
6 changes: 1 addition & 5 deletions core/parentchain/light-client/src/concurrent_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,8 @@ where
where
F: FnOnce(&Self::ValidatorType) -> Result<R>,
{
let mut light_validation_lock =
let light_validation_lock =
self.light_validation.write().map_err(|_| Error::PoisonedLock)?;
let state = Seal::unseal_from_static_file()?;
light_validation_lock.set_state(state);
Comment on lines -108 to -111
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a global lock; The persisted light-client file will never contain more recent information than the already initialized validator. So we can skip reading from disk.

getter_function(&light_validation_lock)
}

Expand All @@ -118,8 +116,6 @@ where
{
let mut light_validation_lock =
self.light_validation.write().map_err(|_| Error::PoisonedLock)?;
let state = Seal::unseal_from_static_file()?;
light_validation_lock.set_state(state);
Comment on lines -121 to -122
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dito

let result = mutating_function(&mut light_validation_lock);
Seal::seal_to_static_file(light_validation_lock.get_state())?;
result
Expand Down
2 changes: 0 additions & 2 deletions core/parentchain/light-client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ pub enum Error {
ValidatorSetMismatch,
#[error("Invalid ancestry proof")]
InvalidAncestryProof,
#[error("No such relay exists")]
NoSuchRelayExists,
#[error("Invalid Finality Proof: {0}")]
InvalidFinalityProof(#[from] JustificationError),
#[error("Header ancestry mismatch")]
Expand Down
107 changes: 61 additions & 46 deletions core/parentchain/light-client/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use crate::{
error::Result,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I mainly changed the initialization flow, which was really hard to handle because of side-effects of some functions. I think that there is still very much potential, but the code will be further amended in the course of #1242 anyhow. So I left it in the current state.

finality::{Finality, GrandpaFinality, ParachainFinality},
light_client_init_params::{GrandpaParams, SimpleParams},
light_validation::LightValidation,
light_validation::{check_validator_set_proof, LightValidation},
state::RelayState,
Error, LightValidationState, NumberFor, Validator,
};
use codec::{Decode, Encode};
Expand All @@ -28,7 +29,6 @@ use itp_ocall_api::EnclaveOnChainOCallApi;
use itp_settings::files::LIGHT_CLIENT_DB;
use itp_sgx_io::{seal, unseal, StaticSealedIO};
use log::*;
use sp_finality_grandpa::AuthorityList;
use sp_runtime::traits::{Block, Header};
use std::{boxed::Box, fs, sgxfs::SgxFile, sync::Arc};

Expand Down Expand Up @@ -68,26 +68,43 @@ where
NumberFor<B>: finality_grandpa::BlockNumberOps,
OCallApi: EnclaveOnChainOCallApi,
{
check_validator_set_proof::<B>(
params.genesis_header.state_root(),
params.authority_proof,
&params.authorities,
)?;

// FIXME: That should be an unique path.
if SgxFile::open(LIGHT_CLIENT_DB).is_err() {
info!("[Enclave] ChainRelay DB not found, creating new! {}", LIGHT_CLIENT_DB);
return init_grandpa_validator::<B, OCallApi>(params, ocall_api)
let validator = init_grandpa_validator::<B, OCallApi>(
ocall_api,
RelayState::new(params.genesis_header, params.authorities).into(),
)?;
LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(
validator.get_state(),
)?;
return Ok(validator)
}

let (validation_state, genesis_hash) = get_validation_state::<B>()?;

let mut validator = init_grandpa_validator::<B, OCallApi>(params.clone(), ocall_api)?;

if genesis_hash == params.genesis_header.hash() {
validator.set_state(validation_state);
// The init_grandpa_validator function clear the state every time,
// so we should write the state again.
LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(
validator.get_state(),
)?;
let init_state = if genesis_hash == params.genesis_header.hash() {
info!("Found already initialized light client with Genesis Hash: {:?}", genesis_hash);
}
validation_state
} else {
info!(
"Previous light client db belongs to another parentchain genesis. Creating new: {:?}",
genesis_hash
);
RelayState::new(params.genesis_header, params.authorities).into()
};

let validator = init_grandpa_validator::<B, OCallApi>(ocall_api, init_state)?;

info!("light client state: {:?}", validator);

LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(validator.get_state())?;
Ok(validator)
}

Expand All @@ -103,78 +120,76 @@ where
// FIXME: That should be an unique path.
if SgxFile::open(LIGHT_CLIENT_DB).is_err() {
info!("[Enclave] ChainRelay DB not found, creating new! {}", LIGHT_CLIENT_DB);
return init_parachain_validator::<B, OCallApi>(params, ocall_api)
let validator = init_parachain_validator::<B, OCallApi>(
ocall_api,
RelayState::new(params.genesis_header, Default::default()).into(),
)?;
LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(
validator.get_state(),
)?;
return Ok(validator)
}

let (validation_state, genesis_hash) = get_validation_state::<B>()?;

let mut validator = init_parachain_validator::<B, OCallApi>(params.clone(), ocall_api)?;

if genesis_hash == params.genesis_header.hash() {
validator.set_state(validation_state);
// The init_parachain_validator function clear the state every time,
// so we should write the state again.
LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(
validator.get_state(),
)?;
let init_state = if genesis_hash == params.genesis_header.hash() {
info!("Found already initialized light client with Genesis Hash: {:?}", genesis_hash);
}
validation_state
} else {
info!(
"Previous light client db belongs to another parentchain genesis. Creating new: {:?}",
genesis_hash
);
RelayState::new(params.genesis_header, vec![]).into()
};

let validator = init_parachain_validator::<B, OCallApi>(ocall_api, init_state)?;
info!("light client state: {:?}", validator);

LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(validator.get_state())?;
Ok(validator)
}

fn get_validation_state<B: Block>() -> Result<(LightValidationState<B>, B::Hash)>
where
B: Block,
{
// Todo: Implement this on the `LightClientStateSeal` itself.
fn get_validation_state<B: Block>() -> Result<(LightValidationState<B>, B::Hash)> {
let validation_state =
LightClientStateSeal::<B, LightValidationState<B>>::unseal_from_static_file()?;

let relay = validation_state
.tracked_relays
.get(&validation_state.num_relays)
.ok_or(Error::NoSuchRelayExists)?;
let relay = validation_state.get_relay();
let genesis_hash = relay.header_hashes[0];

Ok((validation_state, genesis_hash))
}

fn init_grandpa_validator<B, OCallApi>(
params: GrandpaParams<B::Header>,
ocall_api: Arc<OCallApi>,
state: LightValidationState<B>,
) -> Result<LightValidation<B, OCallApi>>
Comment on lines 164 to 167
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function needed to be more lean, plus it had side effects (overwriting the disk with the freshly initialized light-client state, which was not always wished from on the calling site).

where
B: Block,
NumberFor<B>: finality_grandpa::BlockNumberOps,
OCallApi: EnclaveOnChainOCallApi,
{
let finality: Arc<Box<dyn Finality<B> + Sync + Send + 'static>> =
Arc::new(Box::new(GrandpaFinality {}));
let mut validator = LightValidation::<B, OCallApi>::new(ocall_api, finality);
validator.initialize_grandpa_relay(
params.genesis_header,
params.authorities,
params.authority_proof,
)?;
Arc::new(Box::new(GrandpaFinality));

let validator = LightValidation::<B, OCallApi>::new(ocall_api, finality, state);

LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(validator.get_state())?;
Ok(validator)
}

fn init_parachain_validator<B, OCallApi>(
params: SimpleParams<B::Header>,
ocall_api: Arc<OCallApi>,
state: LightValidationState<B>,
) -> Result<LightValidation<B, OCallApi>>
where
B: Block,
NumberFor<B>: finality_grandpa::BlockNumberOps,
OCallApi: EnclaveOnChainOCallApi,
{
let finality: Arc<Box<dyn Finality<B> + Sync + Send + 'static>> =
Arc::new(Box::new(ParachainFinality {}));
let mut validator = LightValidation::<B, OCallApi>::new(ocall_api, finality);
validator.initialize_parachain_relay(params.genesis_header, AuthorityList::default())?;
Arc::new(Box::new(ParachainFinality));

LightClientStateSeal::<B, LightValidationState<B>>::seal_to_static_file(validator.get_state())?;
let validator = LightValidation::<B, OCallApi>::new(ocall_api, finality, state);
Ok(validator)
}
35 changes: 6 additions & 29 deletions core/parentchain/light-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ pub use sp_finality_grandpa::{AuthorityList, SetId};

use crate::light_validation_state::LightValidationState;
use error::Error;
use itp_storage::StorageProof;
use sp_finality_grandpa::{AuthorityId, AuthorityWeight, ConsensusLog, GRANDPA_ENGINE_ID};
use sp_runtime::{
generic::{Digest, OpaqueDigestItemId, SignedBlock},
Expand Down Expand Up @@ -73,28 +72,9 @@ pub trait Validator<Block: ParentchainBlockTrait>
where
NumberFor<Block>: finality_grandpa::BlockNumberOps,
{
fn initialize_grandpa_relay(
&mut self,
block_header: Block::Header,
validator_set: AuthorityList,
validator_set_proof: StorageProof,
) -> Result<RelayId, Error>;
Comment on lines -76 to -81
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed, we initialize the relay along with the constructor now - much leaner IMO.

fn submit_block(&mut self, signed_block: &SignedBlock<Block>) -> Result<(), Error>;

fn initialize_parachain_relay(
&mut self,
block_header: Block::Header,
validator_set: AuthorityList,
) -> Result<RelayId, Error>;

fn submit_block(
&mut self,
relay_id: RelayId,
signed_block: &SignedBlock<Block>,
) -> Result<(), Error>;

fn check_xt_inclusion(&mut self, relay_id: RelayId, block: &Block) -> Result<(), Error>;

fn set_state(&mut self, state: LightValidationState<Block>);
fn check_xt_inclusion(&mut self, block: &Block) -> Result<(), Error>;

fn get_state(&self) -> &LightValidationState<Block>;
}
Expand All @@ -105,17 +85,14 @@ pub trait ExtrinsicSender {
}

pub trait LightClientState<Block: ParentchainBlockTrait> {
fn num_xt_to_be_included(&self, relay_id: RelayId) -> Result<usize, Error>;
fn num_xt_to_be_included(&self) -> Result<usize, Error>;

fn genesis_hash(&self, relay_id: RelayId) -> Result<HashFor<Block>, Error>;
fn genesis_hash(&self) -> Result<HashFor<Block>, Error>;

fn latest_finalized_header(&self, relay_id: RelayId) -> Result<Block::Header, Error>;
fn latest_finalized_header(&self) -> Result<Block::Header, Error>;

// Todo: Check if we still need this after #423
fn penultimate_finalized_block_header(&self, relay_id: RelayId)
-> Result<Block::Header, Error>;

fn num_relays(&self) -> RelayId;
fn penultimate_finalized_block_header(&self) -> Result<Block::Header, Error>;
}

pub fn grandpa_log<Block: ParentchainBlockTrait>(
Expand Down
Loading