Skip to content

Commit f5e059f

Browse files
authored
Provision light-client in mutual remote attestation (#1399)
* [block-import] add `ImportType` to distinguish sync and block-production import type. * Revert "[block-import] add `ImportType` to distinguish sync and block-production import type." This reverts commit c3c46fd. * [light-validation] add genesis_hash field and introduce header prunging * [light-client] add `LightClientStateSealSync` which has some mechanisms such that it can be shared across threads in an arc. [light-client] add constructor to `LightClientStateSealSync` fix light-client adjustments remove pending wip of sealing adjustements * provision light-client state wip * [tls-ra] provision light-client state too * fix clippy * fix cargo test compilation
1 parent 3443f15 commit f5e059f

17 files changed

Lines changed: 247 additions & 92 deletions

File tree

core/parentchain/light-client/src/concurrent_access.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::{
3131
};
3232
use finality_grandpa::BlockNumberOps;
3333
use sp_runtime::traits::{Block as ParentchainBlockTrait, NumberFor};
34-
use std::marker::PhantomData;
34+
use std::{marker::PhantomData, sync::Arc};
3535

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

7070
impl<Validator, ParentchainBlock, LightClientSeal>
7171
ValidatorAccessor<Validator, ParentchainBlock, LightClientSeal>
7272
{
73-
pub fn new(validator: Validator, seal: LightClientSeal) -> Self {
73+
pub fn new(validator: Validator, seal: Arc<LightClientSeal>) -> Self {
7474
ValidatorAccessor {
7575
light_validation: RwLock::new(validator),
7676
seal,
@@ -85,7 +85,7 @@ where
8585
Validator: ValidatorTrait<ParentchainBlock>
8686
+ LightClientState<ParentchainBlock>
8787
+ ExtrinsicSenderTrait,
88-
Seal: LightClientSealing<LightValidationState<ParentchainBlock>>,
88+
Seal: LightClientSealing<LightClientState = LightValidationState<ParentchainBlock>>,
8989
ParentchainBlock: ParentchainBlockTrait,
9090
NumberFor<ParentchainBlock>: BlockNumberOps,
9191
{
@@ -126,7 +126,7 @@ mod tests {
126126
fn execute_with_and_without_mut_in_single_thread_works() {
127127
let validator_mock = ValidatorMock::default();
128128
let seal = LightValidationStateSealMock::new();
129-
let accessor = TestAccessor::new(validator_mock, seal);
129+
let accessor = TestAccessor::new(validator_mock, seal.into());
130130

131131
let _read_result = accessor.execute_on_validator(|_v| Ok(())).unwrap();
132132
let _write_result = accessor.execute_mut_on_validator(|_v| Ok(())).unwrap();

core/parentchain/light-client/src/io.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717

1818
use crate::{
19-
error::Result,
19+
error::{Error, Result},
2020
finality::{Finality, GrandpaFinality, ParachainFinality},
2121
light_client_init_params::{GrandpaParams, SimpleParams},
2222
light_validation::{check_validator_set_proof, LightValidation},
@@ -37,6 +37,12 @@ use std::{
3737
sync::Arc,
3838
};
3939

40+
#[cfg(feature = "sgx")]
41+
use std::sync::SgxRwLock as RwLock;
42+
43+
#[cfg(feature = "std")]
44+
use std::sync::RwLock;
45+
4046
pub const DB_FILE: &str = "db.bin";
4147
pub const BACKUP_FILE: &str = "db.bin.backup";
4248

@@ -81,9 +87,11 @@ impl<B, L> LightClientStateSeal<B, L> {
8187
}
8288
}
8389

84-
impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing<LightClientState>
90+
impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing
8591
for LightClientStateSeal<B, LightClientState>
8692
{
93+
type LightClientState = LightClientState;
94+
8795
fn seal(&self, unsealed: &LightClientState) -> Result<()> {
8896
trace!("Backup light client state");
8997

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

119+
/// Same as [LightClientStateSeal], but it ensures that no concurrent write operations are done
120+
/// accross different threads.
121+
#[derive(Debug)]
122+
pub struct LightClientStateSealSync<B, LightClientState> {
123+
seal: LightClientStateSeal<B, LightClientState>,
124+
_rw_lock: RwLock<()>,
125+
}
126+
127+
impl<B, LightClientState> LightClientStateSealSync<B, LightClientState> {
128+
pub fn new(base_path: PathBuf) -> Result<Self> {
129+
Ok(Self { seal: LightClientStateSeal::new(base_path)?, _rw_lock: RwLock::new(()) })
130+
}
131+
}
132+
133+
impl<B: Block, LightClientState: Decode + Encode + Debug> LightClientSealing
134+
for LightClientStateSealSync<B, LightClientState>
135+
{
136+
type LightClientState = LightClientState;
137+
138+
fn seal(&self, unsealed: &LightClientState) -> Result<()> {
139+
let _lock = self._rw_lock.write().map_err(|_| Error::PoisonedLock)?;
140+
self.seal.seal(unsealed)
141+
}
142+
143+
fn unseal(&self) -> Result<LightClientState> {
144+
let _lock = self._rw_lock.read().map_err(|_| Error::PoisonedLock)?;
145+
self.seal.unseal()
146+
}
147+
148+
fn exists(&self) -> bool {
149+
self.seal.exists()
150+
}
151+
152+
fn path(&self) -> &Path {
153+
self.seal.path()
154+
}
155+
}
156+
111157
// FIXME: This is a lot of duplicate code for the initialization of two
112158
// different but sameish light clients. Should be tackled with #1081
113159
pub fn read_or_init_grandpa_validator<B, OCallApi, LightClientSeal>(
@@ -119,7 +165,7 @@ where
119165
B: Block,
120166
NumberFor<B>: finality_grandpa::BlockNumberOps,
121167
OCallApi: EnclaveOnChainOCallApi,
122-
LightClientSeal: LightClientSealing<LightValidationState<B>>,
168+
LightClientSeal: LightClientSealing<LightClientState = LightValidationState<B>>,
123169
{
124170
check_validator_set_proof::<B>(
125171
params.genesis_header.state_root(),
@@ -168,7 +214,7 @@ where
168214
B: Block,
169215
NumberFor<B>: finality_grandpa::BlockNumberOps,
170216
OCallApi: EnclaveOnChainOCallApi,
171-
LightClientSeal: LightClientSealing<LightValidationState<B>>,
217+
LightClientSeal: LightClientSealing<LightClientState = LightValidationState<B>>,
172218
{
173219
if !seal.exists() {
174220
info!("[Enclave] ChainRelay DB not found, creating new! {}", seal.path().display());

core/parentchain/light-client/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,11 @@ pub trait LightClientState<Block: ParentchainBlockTrait> {
9595
fn penultimate_finalized_block_header(&self) -> Result<Block::Header, Error>;
9696
}
9797

98-
pub trait LightClientSealing<LightClientState> {
99-
fn seal(&self, state: &LightClientState) -> Result<(), Error>;
100-
fn unseal(&self) -> Result<LightClientState, Error>;
98+
pub trait LightClientSealing {
99+
type LightClientState;
100+
101+
fn seal(&self, state: &Self::LightClientState) -> Result<(), Error>;
102+
fn unseal(&self) -> Result<Self::LightClientState, Error>;
101103
fn exists(&self) -> bool;
102104
fn path(&self) -> &Path;
103105
}

core/parentchain/light-client/src/light_validation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ impl<Block: ParentchainBlockTrait, OcallApi: EnclaveOnChainOCallApi>
105105
}
106106

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

111111
relay.set_last_finalized_block_header(header);
112112

core/parentchain/light-client/src/light_validation_state.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ where
5858
}
5959

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

6664
fn latest_finalized_header(&self) -> Result<Block::Header, Error> {

core/parentchain/light-client/src/mocks/validator_mock_seal.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ impl Default for LightValidationStateSealMock {
4040
}
4141
}
4242

43-
impl LightClientSealing<LightValidationState<Block>> for LightValidationStateSealMock {
43+
impl LightClientSealing for LightValidationStateSealMock {
44+
type LightClientState = LightValidationState<Block>;
45+
4446
fn unseal(&self) -> Result<LightValidationState<Block>, Error> {
4547
Ok(LightValidationState::new(RelayState::new(
4648
ParentchainHeaderBuilder::default().build(),

core/parentchain/light-client/src/state.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,61 @@ use sp_runtime::{
2121
traits::{Block as BlockT, Header as HeaderT},
2222
OpaqueExtrinsic,
2323
};
24-
use std::{fmt, vec::Vec};
24+
use std::{collections::VecDeque, fmt, vec::Vec};
25+
26+
/// Defines the amount of parentchain headers to keep.
27+
pub const PARENTCHAIN_HEADER_PRUNING: u64 = 1000;
2528

2629
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
2730
pub struct RelayState<Block: BlockT> {
31+
pub genesis_hash: Block::Hash,
2832
pub last_finalized_block_header: Block::Header,
2933
pub penultimate_finalized_block_header: Block::Header,
3034
pub current_validator_set: AuthorityList,
3135
pub current_validator_set_id: SetId,
32-
pub header_hashes: Vec<Block::Hash>,
36+
header_hashes: VecDeque<Block::Hash>,
3337
pub unjustified_headers: Vec<Block::Hash>, // Finalized headers without grandpa proof
3438
pub verify_tx_inclusion: Vec<OpaqueExtrinsic>, // Transactions sent by the relay
3539
pub scheduled_change: Option<ScheduledChangeAtBlock<Block::Header>>, // Scheduled Authorities change as indicated in the header's digest.
3640
}
3741

42+
impl<Block: BlockT> RelayState<Block> {
43+
pub fn push_header_hash(&mut self, header: Block::Hash) {
44+
self.header_hashes.push_back(header);
45+
46+
if self.header_hashes.len() > PARENTCHAIN_HEADER_PRUNING as usize {
47+
self.header_hashes.pop_front().expect("Tested above that is not empty; qed");
48+
}
49+
}
50+
51+
pub fn justify_headers(&mut self) {
52+
self.header_hashes.extend(&mut self.unjustified_headers.iter());
53+
self.unjustified_headers.clear();
54+
55+
while self.header_hashes.len() > PARENTCHAIN_HEADER_PRUNING as usize {
56+
self.header_hashes.pop_front().expect("Tested above that is not empty; qed");
57+
}
58+
}
59+
60+
pub fn header_hashes(&self) -> &VecDeque<Block::Hash> {
61+
&self.header_hashes
62+
}
63+
}
64+
3865
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
3966
pub struct ScheduledChangeAtBlock<Header: HeaderT> {
4067
pub at_block: Header::Number,
4168
pub next_authority_list: AuthorityList,
4269
}
4370

4471
impl<Block: BlockT> RelayState<Block> {
45-
pub fn new(block_header: Block::Header, validator_set: AuthorityList) -> Self {
72+
pub fn new(genesis: Block::Header, validator_set: AuthorityList) -> Self {
4673
RelayState {
47-
header_hashes: vec![block_header.hash()],
48-
last_finalized_block_header: block_header.clone(),
74+
genesis_hash: genesis.hash(),
75+
header_hashes: vec![genesis.hash()].into(),
76+
last_finalized_block_header: genesis.clone(),
4977
// is it bad to initialize with the same? Header trait does no implement default...
50-
penultimate_finalized_block_header: block_header,
78+
penultimate_finalized_block_header: genesis,
5179
current_validator_set: validator_set,
5280
current_validator_set_id: 0,
5381
unjustified_headers: Vec::new(),

enclave-runtime/src/initialization/global_components.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use itc_parentchain::{
4646
IndirectCallsExecutor,
4747
},
4848
light_client::{
49-
concurrent_access::ValidatorAccessor, io::LightClientStateSeal,
49+
concurrent_access::ValidatorAccessor, io::LightClientStateSealSync,
5050
light_validation::LightValidation, light_validation_state::LightValidationState,
5151
},
5252
};
@@ -132,7 +132,7 @@ pub type EnclaveSidechainApi = SidechainApi<ParentchainBlock>;
132132

133133
// Parentchain types
134134
pub type EnclaveLightClientSeal =
135-
LightClientStateSeal<ParentchainBlock, LightValidationState<ParentchainBlock>>;
135+
LightClientStateSealSync<ParentchainBlock, LightValidationState<ParentchainBlock>>;
136136
pub type EnclaveExtrinsicsFactory =
137137
ExtrinsicsFactory<EnclaveParentchainSigner, NonceCache, EnclaveNodeMetadataRepository>;
138138
pub type EnclaveIndirectCallsExecutor = IndirectCallsExecutor<
@@ -215,8 +215,12 @@ pub type EnclaveSidechainBlockImportQueueWorker = BlockImportQueueWorker<
215215
EnclaveSidechainBlockImportQueue,
216216
EnclaveSidechainBlockSyncer,
217217
>;
218-
pub type EnclaveSealHandler =
219-
SealHandler<EnclaveShieldingKeyRepository, EnclaveStateKeyRepository, EnclaveStateHandler>;
218+
pub type EnclaveSealHandler = SealHandler<
219+
EnclaveShieldingKeyRepository,
220+
EnclaveStateKeyRepository,
221+
EnclaveStateHandler,
222+
EnclaveLightClientSeal,
223+
>;
220224
pub type EnclaveOffchainWorkerExecutor = itc_offchain_worker_executor::executor::Executor<
221225
ParentchainBlock,
222226
EnclaveTopPoolAuthor,
@@ -244,6 +248,10 @@ pub static GLOBAL_SIGNING_KEY_REPOSITORY_COMPONENT: ComponentContainer<
244248
EnclaveSigningKeyRepository,
245249
> = ComponentContainer::new("Signing key repository");
246250

251+
/// Light client db seal.
252+
pub static GLOBAL_LIGHT_CLIENT_SEAL: ComponentContainer<EnclaveLightClientSeal> =
253+
ComponentContainer::new("EnclaveLightClientSealSync");
254+
247255
/// O-Call API
248256
pub static GLOBAL_OCALL_API_COMPONENT: ComponentContainer<EnclaveOCallApi> =
249257
ComponentContainer::new("O-call API");

enclave-runtime/src/initialization/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ pub mod parentchain;
2121
use crate::{
2222
error::{Error, Result as EnclaveResult},
2323
initialization::global_components::{
24-
EnclaveBlockImportConfirmationHandler, EnclaveGetterExecutor, EnclaveOCallApi,
25-
EnclaveRpcConnectionRegistry, EnclaveRpcResponder, EnclaveShieldingKeyRepository,
26-
EnclaveSidechainApi, EnclaveSidechainBlockImportQueue,
24+
EnclaveBlockImportConfirmationHandler, EnclaveGetterExecutor, EnclaveLightClientSeal,
25+
EnclaveOCallApi, EnclaveRpcConnectionRegistry, EnclaveRpcResponder,
26+
EnclaveShieldingKeyRepository, EnclaveSidechainApi, EnclaveSidechainBlockImportQueue,
2727
EnclaveSidechainBlockImportQueueWorker, EnclaveSidechainBlockImporter,
2828
EnclaveSidechainBlockSyncer, EnclaveStateFileIo, EnclaveStateHandler,
2929
EnclaveStateInitializer, EnclaveStateObserver, EnclaveStateSnapshotRepository,
3030
EnclaveStfEnclaveSigner, EnclaveTopPool, EnclaveTopPoolAuthor,
31-
GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT,
31+
GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_LIGHT_CLIENT_SEAL, GLOBAL_OCALL_API_COMPONENT,
3232
GLOBAL_RPC_WS_HANDLER_COMPONENT, GLOBAL_SHIELDING_KEY_REPOSITORY_COMPONENT,
3333
GLOBAL_SIDECHAIN_BLOCK_COMPOSER_COMPONENT, GLOBAL_SIDECHAIN_BLOCK_SYNCER_COMPONENT,
3434
GLOBAL_SIDECHAIN_IMPORT_QUEUE_COMPONENT, GLOBAL_SIDECHAIN_IMPORT_QUEUE_WORKER_COMPONENT,
@@ -59,7 +59,7 @@ use itc_tls_websocket_server::{
5959
use itp_attestation_handler::IntelAttestationHandler;
6060
use itp_component_container::{ComponentGetter, ComponentInitializer};
6161
use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE;
62-
use itp_settings::files::STATE_SNAPSHOTS_CACHE_SIZE;
62+
use itp_settings::files::{LIGHT_CLIENT_DB_PATH, STATE_SNAPSHOTS_CACHE_SIZE};
6363
use itp_sgx_crypto::{
6464
get_aes_repository, get_ed25519_repository, get_rsa3072_repository, key_repository::AccessKey,
6565
};
@@ -94,6 +94,10 @@ pub(crate) fn init_enclave(
9494
let state_key_repository = Arc::new(get_aes_repository(base_dir.clone())?);
9595
GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.initialize(state_key_repository.clone());
9696

97+
let light_client_seal =
98+
Arc::new(EnclaveLightClientSeal::new(base_dir.join(LIGHT_CLIENT_DB_PATH))?);
99+
GLOBAL_LIGHT_CLIENT_SEAL.initialize(light_client_seal);
100+
97101
let state_file_io =
98102
Arc::new(EnclaveStateFileIo::new(state_key_repository, StateDir::new(base_dir)));
99103
let state_initializer =

enclave-runtime/src/initialization/parentchain/parachain.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use crate::{
1919
error::Result,
2020
initialization::{
2121
global_components::{
22-
EnclaveExtrinsicsFactory, EnclaveLightClientSeal, EnclaveNodeMetadataRepository,
23-
EnclaveOCallApi, EnclaveParentchainBlockImportDispatcher, EnclaveStfExecutor,
24-
EnclaveValidatorAccessor, GLOBAL_FULL_PARACHAIN_HANDLER_COMPONENT,
25-
GLOBAL_OCALL_API_COMPONENT, GLOBAL_STATE_HANDLER_COMPONENT,
22+
EnclaveExtrinsicsFactory, EnclaveNodeMetadataRepository, EnclaveOCallApi,
23+
EnclaveParentchainBlockImportDispatcher, EnclaveStfExecutor, EnclaveValidatorAccessor,
24+
GLOBAL_FULL_PARACHAIN_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT,
25+
GLOBAL_STATE_HANDLER_COMPONENT,
2626
},
2727
parentchain::common::{
2828
create_extrinsics_factory, create_offchain_immediate_import_dispatcher,
@@ -33,12 +33,10 @@ use crate::{
3333
use codec::Encode;
3434
use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, LightClientState};
3535
use itp_component_container::{ComponentGetter, ComponentInitializer};
36-
use itp_settings::{
37-
files::LIGHT_CLIENT_DB_PATH,
38-
worker_mode::{ProvideWorkerMode, WorkerMode},
39-
};
36+
use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode};
4037
use std::{path::PathBuf, sync::Arc, vec::Vec};
4138

39+
use crate::initialization::global_components::GLOBAL_LIGHT_CLIENT_SEAL;
4240
pub use itc_parentchain::primitives::{ParachainBlock, ParachainHeader, ParachainParams};
4341

4442
#[derive(Clone)]
@@ -54,7 +52,7 @@ pub struct FullParachainHandler {
5452

5553
impl FullParachainHandler {
5654
pub fn init<WorkerModeProvider: ProvideWorkerMode>(
57-
base_path: PathBuf,
55+
_base_path: PathBuf,
5856
params: ParachainParams,
5957
) -> Result<Vec<u8>> {
6058
let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?;
@@ -63,12 +61,12 @@ impl FullParachainHandler {
6361

6462
let genesis_header = params.genesis_header.clone();
6563

66-
let light_client_seal = EnclaveLightClientSeal::new(base_path.join(LIGHT_CLIENT_DB_PATH))?;
64+
let light_client_seal = GLOBAL_LIGHT_CLIENT_SEAL.get()?;
6765
let validator = itc_parentchain::light_client::io::read_or_init_parachain_validator::<
6866
ParachainBlock,
6967
EnclaveOCallApi,
7068
_,
71-
>(params, ocall_api.clone(), &light_client_seal)?;
69+
>(params, ocall_api.clone(), &*light_client_seal)?;
7270
let latest_header = validator.latest_finalized_header()?;
7371
let validator_accessor =
7472
Arc::new(EnclaveValidatorAccessor::new(validator, light_client_seal));

0 commit comments

Comments
 (0)