Skip to content
1 change: 1 addition & 0 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
branches:
- master
- 'sdk-v[0-9]+.[0-9]+.[0-9]+-*'
- 'szp/polkadot-v0.9.42'

env:
CARGO_TERM_COLOR: always
Expand Down
15 changes: 11 additions & 4 deletions cli/src/trusted_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
trusted_cli::TrustedCli,
Cli,
};
use base58::FromBase58;
use base58::{FromBase58, ToBase58};
use codec::{Decode, Encode};
use ita_stf::{Getter, TrustedOperation};
use itc_rpc_client::direct_client::{DirectApi, DirectClient};
Expand All @@ -45,7 +45,6 @@ use substrate_api_client::{
};
use teerex_primitives::Request;
use thiserror::Error;
use base58::ToBase58;

#[derive(Debug, Error)]
pub(crate) enum TrustedOperationError {
Expand Down Expand Up @@ -127,7 +126,11 @@ fn send_indirect_request(
let call_encrypted = encryption_key.encrypt(&trusted_operation.encode()).unwrap();

let shard = read_shard(trusted_args).unwrap();
debug!("indirect send_request: trusted operation: {:?}, shard: {}", trusted_operation, shard.encode().to_base58());
debug!(
"indirect send_request: trusted operation: {:?}, shard: {}",
trusted_operation,
shard.encode().to_base58()
);
let arg_signer = &trusted_args.xt_signer;
let signer = get_pair_from_str(arg_signer);
chain_api.set_signer(ParentchainExtrinsicSigner::new(sr25519_core::Pair::from(signer)));
Expand Down Expand Up @@ -224,7 +227,11 @@ fn send_direct_request(
let encryption_key = get_shielding_key(cli).unwrap();
let shard = read_shard(trusted_args).unwrap();
let jsonrpc_call: String = get_json_request(shard, operation_call, encryption_key);
debug!("send_direct_request: trusted operation: {:?}, shard: {}", operation_call, shard.encode().to_base58());
debug!(
"send_direct_request: trusted operation: {:?}, shard: {}",
operation_call,
shard.encode().to_base58()
);
let direct_api = get_worker_api_direct(cli);

debug!("setup sender and receiver");
Expand Down
10 changes: 5 additions & 5 deletions core/parentchain/light-client/src/concurrent_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use crate::{
};
use finality_grandpa::BlockNumberOps;
use sp_runtime::traits::{Block as ParentchainBlockTrait, NumberFor};
use std::marker::PhantomData;
use std::{marker::PhantomData, sync::Arc};

/// Retrieve an exclusive lock on a validator for either read or write access.
///
Expand Down Expand Up @@ -62,15 +62,15 @@ where
/// Implementation of a validator access based on a global lock and corresponding file.
#[derive(Debug)]
pub struct ValidatorAccessor<Validator, ParentchainBlock, LightClientSeal> {
seal: LightClientSeal,
seal: Arc<LightClientSeal>,
light_validation: RwLock<Validator>,
_phantom: PhantomData<(LightClientSeal, Validator, ParentchainBlock)>,
}

impl<Validator, ParentchainBlock, LightClientSeal>
ValidatorAccessor<Validator, ParentchainBlock, LightClientSeal>
{
pub fn new(validator: Validator, seal: LightClientSeal) -> Self {
pub fn new(validator: Validator, seal: Arc<LightClientSeal>) -> Self {
ValidatorAccessor {
light_validation: RwLock::new(validator),
seal,
Expand All @@ -85,7 +85,7 @@ where
Validator: ValidatorTrait<ParentchainBlock>
+ LightClientState<ParentchainBlock>
+ ExtrinsicSenderTrait,
Seal: LightClientSealing<LightValidationState<ParentchainBlock>>,
Seal: LightClientSealing<LightClientState = LightValidationState<ParentchainBlock>>,
ParentchainBlock: ParentchainBlockTrait,
NumberFor<ParentchainBlock>: BlockNumberOps,
{
Expand Down Expand Up @@ -126,7 +126,7 @@ mod tests {
fn execute_with_and_without_mut_in_single_thread_works() {
let validator_mock = ValidatorMock::default();
let seal = LightValidationStateSealMock::new();
let accessor = TestAccessor::new(validator_mock, seal);
let accessor = TestAccessor::new(validator_mock, seal.into());

let _read_result = accessor.execute_on_validator(|_v| Ok(())).unwrap();
let _write_result = accessor.execute_mut_on_validator(|_v| Ok(())).unwrap();
Expand Down
54 changes: 50 additions & 4 deletions core/parentchain/light-client/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

use crate::{
error::Result,
error::{Error, Result},
finality::{Finality, GrandpaFinality, ParachainFinality},
light_client_init_params::{GrandpaParams, SimpleParams},
light_validation::{check_validator_set_proof, LightValidation},
Expand All @@ -37,6 +37,12 @@ use std::{
sync::Arc,
};

#[cfg(feature = "sgx")]
use std::sync::SgxRwLock as RwLock;

#[cfg(feature = "std")]
use std::sync::RwLock;

pub const DB_FILE: &str = "db.bin";
pub const BACKUP_FILE: &str = "db.bin.backup";

Expand Down Expand Up @@ -81,9 +87,11 @@ impl<B, L> LightClientStateSeal<B, L> {
}
}

impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing<LightClientState>
impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing
for LightClientStateSeal<B, LightClientState>
{
type LightClientState = LightClientState;

fn seal(&self, unsealed: &LightClientState) -> Result<()> {
trace!("Backup light client state");

Expand All @@ -108,6 +116,44 @@ impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing<Lig
}
}

/// Same as [LightClientStateSeal], but it ensures that no concurrent write operations are done
/// accross different threads.
#[derive(Debug)]
pub struct LightClientStateSealSync<B, LightClientState> {
seal: LightClientStateSeal<B, LightClientState>,
_rw_lock: RwLock<()>,
}

impl<B, LightClientState> LightClientStateSealSync<B, LightClientState> {
pub fn new(base_path: PathBuf) -> Result<Self> {
Ok(Self { seal: LightClientStateSeal::new(base_path)?, _rw_lock: RwLock::new(()) })
}
}

impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing
for LightClientStateSealSync<B, LightClientState>
{
type LightClientState = LightClientState;

fn seal(&self, unsealed: &LightClientState) -> Result<()> {
let _lock = self._rw_lock.write().map_err(|_| Error::PoisonedLock)?;
self.seal.seal(unsealed)
}

fn unseal(&self) -> Result<LightClientState> {
let _lock = self._rw_lock.read().map_err(|_| Error::PoisonedLock)?;
self.seal.unseal()
}

fn exists(&self) -> bool {
self.seal.exists()
}

fn path(&self) -> &Path {
self.seal.path()
}
}

// FIXME: This is a lot of duplicate code for the initialization of two
// different but sameish light clients. Should be tackled with #1081
pub fn read_or_init_grandpa_validator<B, OCallApi, LightClientSeal>(
Expand All @@ -119,7 +165,7 @@ where
B: Block,
NumberFor<B>: finality_grandpa::BlockNumberOps,
OCallApi: EnclaveOnChainOCallApi,
LightClientSeal: LightClientSealing<LightValidationState<B>>,
LightClientSeal: LightClientSealing<LightClientState = LightValidationState<B>>,
{
check_validator_set_proof::<B>(
params.genesis_header.state_root(),
Expand Down Expand Up @@ -168,7 +214,7 @@ where
B: Block,
NumberFor<B>: finality_grandpa::BlockNumberOps,
OCallApi: EnclaveOnChainOCallApi,
LightClientSeal: LightClientSealing<LightValidationState<B>>,
LightClientSeal: LightClientSealing<LightClientState = LightValidationState<B>>,
{
if !seal.exists() {
info!("[Enclave] ChainRelay DB not found, creating new! {}", seal.path().display());
Expand Down
8 changes: 5 additions & 3 deletions core/parentchain/light-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ pub trait LightClientState<Block: ParentchainBlockTrait> {
fn penultimate_finalized_block_header(&self) -> Result<Block::Header, Error>;
}

pub trait LightClientSealing<LightClientState> {
fn seal(&self, state: &LightClientState) -> Result<(), Error>;
fn unseal(&self) -> Result<LightClientState, Error>;
pub trait LightClientSealing {
type LightClientState;

fn seal(&self, state: &Self::LightClientState) -> Result<(), Error>;
fn unseal(&self) -> Result<Self::LightClientState, Error>;
fn exists(&self) -> bool;
fn path(&self) -> &Path;
}
Expand Down
4 changes: 2 additions & 2 deletions core/parentchain/light-client/src/light_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ impl<Block: ParentchainBlockTrait, OcallApi: EnclaveOnChainOCallApi>
}

// A valid grandpa proof proves finalization of all previous unjustified blocks.
relay.header_hashes.append(&mut relay.unjustified_headers);
relay.header_hashes.push(header.hash());
relay.justify_headers();
relay.push_header_hash(header.hash());

relay.set_last_finalized_block_header(header);

Expand Down
4 changes: 1 addition & 3 deletions core/parentchain/light-client/src/light_validation_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ where
}

fn genesis_hash(&self) -> Result<HashFor<Block>, Error> {
let relay = self.get_relay();
let hash = relay.header_hashes.get(0).ok_or(Error::NoGenesis)?;
Ok(*hash)
Ok(self.get_relay().genesis_hash)
}

fn latest_finalized_header(&self) -> Result<Block::Header, Error> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ impl Default for LightValidationStateSealMock {
}
}

impl LightClientSealing<LightValidationState<Block>> for LightValidationStateSealMock {
impl LightClientSealing for LightValidationStateSealMock {
type LightClientState = LightValidationState<Block>;

fn unseal(&self) -> Result<LightValidationState<Block>, Error> {
Ok(LightValidationState::new(RelayState::new(
ParentchainHeaderBuilder::default().build(),
Expand Down
40 changes: 34 additions & 6 deletions core/parentchain/light-client/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,61 @@ use sp_runtime::{
traits::{Block as BlockT, Header as HeaderT},
OpaqueExtrinsic,
};
use std::{fmt, vec::Vec};
use std::{collections::VecDeque, fmt, vec::Vec};

/// Defines the amount of parentchain headers to keep.
pub const PARENTCHAIN_HEADER_PRUNING: u64 = 1000;

#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct RelayState<Block: BlockT> {
pub genesis_hash: Block::Hash,
pub last_finalized_block_header: Block::Header,
pub penultimate_finalized_block_header: Block::Header,
pub current_validator_set: AuthorityList,
pub current_validator_set_id: SetId,
pub header_hashes: Vec<Block::Hash>,
header_hashes: VecDeque<Block::Hash>,
pub unjustified_headers: Vec<Block::Hash>, // Finalized headers without grandpa proof
pub verify_tx_inclusion: Vec<OpaqueExtrinsic>, // Transactions sent by the relay
pub scheduled_change: Option<ScheduledChangeAtBlock<Block::Header>>, // Scheduled Authorities change as indicated in the header's digest.
}

impl<Block: BlockT> RelayState<Block> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Todo to me: introduce separate datatype instead of implementing this on the RelayState itself, and do some testing

pub fn push_header_hash(&mut self, header: Block::Hash) {
self.header_hashes.push_back(header);

if self.header_hashes.len() > PARENTCHAIN_HEADER_PRUNING as usize {
self.header_hashes.pop_front().expect("Tested above that is not empty; qed");
}
}

pub fn justify_headers(&mut self) {
self.header_hashes.extend(&mut self.unjustified_headers.iter());
self.unjustified_headers.clear();

while self.header_hashes.len() > PARENTCHAIN_HEADER_PRUNING as usize {
self.header_hashes.pop_front().expect("Tested above that is not empty; qed");
}
}

pub fn header_hashes(&self) -> &VecDeque<Block::Hash> {
&self.header_hashes
}
}

#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct ScheduledChangeAtBlock<Header: HeaderT> {
pub at_block: Header::Number,
pub next_authority_list: AuthorityList,
}

impl<Block: BlockT> RelayState<Block> {
pub fn new(block_header: Block::Header, validator_set: AuthorityList) -> Self {
pub fn new(genesis: Block::Header, validator_set: AuthorityList) -> Self {
RelayState {
header_hashes: vec![block_header.hash()],
last_finalized_block_header: block_header.clone(),
genesis_hash: genesis.hash(),
header_hashes: vec![genesis.hash()].into(),
last_finalized_block_header: genesis.clone(),
// is it bad to initialize with the same? Header trait does no implement default...
penultimate_finalized_block_header: block_header,
penultimate_finalized_block_header: genesis,
current_validator_set: validator_set,
current_validator_set_id: 0,
unjustified_headers: Vec::new(),
Expand Down
16 changes: 12 additions & 4 deletions enclave-runtime/src/initialization/global_components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use itc_parentchain::{
IndirectCallsExecutor,
},
light_client::{
concurrent_access::ValidatorAccessor, io::LightClientStateSeal,
concurrent_access::ValidatorAccessor, io::LightClientStateSealSync,
light_validation::LightValidation, light_validation_state::LightValidationState,
},
};
Expand Down Expand Up @@ -132,7 +132,7 @@ pub type EnclaveSidechainApi = SidechainApi<ParentchainBlock>;

// Parentchain types
pub type EnclaveLightClientSeal =
LightClientStateSeal<ParentchainBlock, LightValidationState<ParentchainBlock>>;
LightClientStateSealSync<ParentchainBlock, LightValidationState<ParentchainBlock>>;
pub type EnclaveExtrinsicsFactory =
ExtrinsicsFactory<EnclaveParentchainSigner, NonceCache, EnclaveNodeMetadataRepository>;
pub type EnclaveIndirectCallsExecutor = IndirectCallsExecutor<
Expand Down Expand Up @@ -215,8 +215,12 @@ pub type EnclaveSidechainBlockImportQueueWorker = BlockImportQueueWorker<
EnclaveSidechainBlockImportQueue,
EnclaveSidechainBlockSyncer,
>;
pub type EnclaveSealHandler =
SealHandler<EnclaveShieldingKeyRepository, EnclaveStateKeyRepository, EnclaveStateHandler>;
pub type EnclaveSealHandler = SealHandler<
EnclaveShieldingKeyRepository,
EnclaveStateKeyRepository,
EnclaveStateHandler,
EnclaveLightClientSeal,
>;
pub type EnclaveOffchainWorkerExecutor = itc_offchain_worker_executor::executor::Executor<
ParentchainBlock,
EnclaveTopPoolAuthor,
Expand Down Expand Up @@ -244,6 +248,10 @@ pub static GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT: ComponentContainer<
EnclaveSigningKeyRepository,
> = ComponentContainer::new("Signing key repository");

/// Light client db seal.
pub static GLOBAL_LIGHT_CLIENT_SEAL: ComponentContainer<EnclaveLightClientSeal> =
ComponentContainer::new("EnclaveLightClientSealSync");
Comment on lines +251 to +253
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Had to introduce a separate component to access this in the tls-ra domain


/// O-Call API
pub static GLOBAL_OCALL_API_COMPONENT: ComponentContainer<EnclaveOCallApi> =
ComponentContainer::new("O-call API");
Expand Down
14 changes: 9 additions & 5 deletions enclave-runtime/src/initialization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ pub mod parentchain;
use crate::{
error::{Error, Result as EnclaveResult},
initialization::global_components::{
EnclaveBlockImportConfirmationHandler, EnclaveGetterExecutor, EnclaveOCallApi,
EnclaveRpcConnectionRegistry, EnclaveRpcResponder, EnclaveShieldingKeyRepository,
EnclaveSidechainApi, EnclaveSidechainBlockImportQueue,
EnclaveBlockImportConfirmationHandler, EnclaveGetterExecutor, EnclaveLightClientSeal,
EnclaveOCallApi, EnclaveRpcConnectionRegistry, EnclaveRpcResponder,
EnclaveShieldingKeyRepository, EnclaveSidechainApi, EnclaveSidechainBlockImportQueue,
EnclaveSidechainBlockImportQueueWorker, EnclaveSidechainBlockImporter,
EnclaveSidechainBlockSyncer, EnclaveStateFileIo, EnclaveStateHandler,
EnclaveStateInitializer, EnclaveStateObserver, EnclaveStateSnapshotRepository,
EnclaveStfEnclaveSigner, EnclaveTopPool, EnclaveTopPoolAuthor,
GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT,
GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_LIGHT_CLIENT_SEAL, GLOBAL_OCALL_API_COMPONENT,
GLOBAL_RPC_WS_HANDLER_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT,
GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_SYNCER_COMPONENT,
GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT,
Expand Down Expand Up @@ -59,7 +59,7 @@ use itc_tls_websocket_server::{
use itp_attestation_handler::IntelAttestationHandler;
use itp_component_container::{ComponentGetter, ComponentInitializer};
use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE;
use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE;
use itp_settings::files::{LIGHT_CLIENT_DB_PATH, STATE_SNAPSHOTS_CACHE_SIZE};
use itp_sgx_crypto::{
get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey,
};
Expand Down Expand Up @@ -94,6 +94,10 @@ pub(crate) fn init_enclave(
let state_key_repository = Arc::new(get_aes_repository(base_dir.clone())?);
GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone());

let light_client_seal =
Arc::new(EnclaveLightClientSeal::new(base_dir.join(LIGHT_CLIENT_DB_PATH))?);
GLOBAL_LIGHT_CLIENT_SEAL.initialize(light_client_seal);

let state_file_io =
Arc::new(EnclaveStateFileIo::new(state_key_repository, StateDir::new(base_dir)));
let state_initializer =
Expand Down
Loading