From ae60b4929f872b17a11a22893155d214c32b543d Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 5 Nov 2024 16:41:35 +0100 Subject: [PATCH 01/10] generic mortality. stay immortal for starters --- app-libs/stf/src/trusted_call.rs | 38 ++++++++++----- core-primitives/extrinsics-factory/src/lib.rs | 25 ++++++---- .../extrinsics-factory/src/mock.rs | 4 +- core-primitives/stf-executor/src/executor.rs | 18 +++---- core-primitives/types/src/parentchain.rs | 47 ++++++++++++------- core/offchain-worker-executor/src/executor.rs | 15 +++--- .../block-importer/src/block_importer.rs | 18 +++++-- enclave-runtime/src/attestation.rs | 5 +- enclave-runtime/src/shard_config.rs | 3 +- enclave-runtime/src/shard_vault.rs | 11 +++-- enclave-runtime/src/top_pool_execution.rs | 8 ++-- .../src/block_import_confirmation_handler.rs | 7 ++- 12 files changed, 126 insertions(+), 73 deletions(-) diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index 542fac2f48..a2ec6b05d8 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -53,7 +53,7 @@ use itp_stf_primitives::{ types::{AccountId, KeyPair, ShardIdentifier, Signature, TrustedOperation}, }; use itp_types::{ - parentchain::{ParentchainCall, ParentchainId, ProxyType}, + parentchain::{GenericMortality, ParentchainCall, ParentchainId, ProxyType}, Address, Moment, OpaqueCall, }; use itp_utils::stringify::account_id_to_string; @@ -340,9 +340,18 @@ where vault_transfer_call, )); let parentchain_call = match parentchain_id { - ParentchainId::Integritee => ParentchainCall::Integritee(proxy_call), - ParentchainId::TargetA => ParentchainCall::TargetA(proxy_call), - ParentchainId::TargetB => ParentchainCall::TargetB(proxy_call), + ParentchainId::Integritee => ParentchainCall::Integritee { + call: proxy_call, + mortality: GenericMortality::immortal(), + }, + ParentchainId::TargetA => ParentchainCall::TargetA { + call: proxy_call, + mortality: GenericMortality::immortal(), + }, + ParentchainId::TargetB => ParentchainCall::TargetB { + call: proxy_call, + mortality: GenericMortality::immortal(), + }, }; calls.push(parentchain_call); Ok(()) @@ -365,15 +374,18 @@ where shield_funds(who, value)?; // Send proof of execution on chain. - calls.push(ParentchainCall::Integritee(OpaqueCall::from_tuple(&( - node_metadata_repo - .get_from_metadata(|m| m.publish_hash_call_indexes()) - .map_err(|_| StfError::InvalidMetadata)? - .map_err(|_| StfError::InvalidMetadata)?, - call_hash, - Vec::::new(), - b"shielded some funds!".to_vec(), - )))); + calls.push(ParentchainCall::Integritee { + call: OpaqueCall::from_tuple(&( + node_metadata_repo + .get_from_metadata(|m| m.publish_hash_call_indexes()) + .map_err(|_| StfError::InvalidMetadata)? + .map_err(|_| StfError::InvalidMetadata)?, + call_hash, + Vec::::new(), + b"shielded some funds!".to_vec(), + )), + mortality: GenericMortality::immortal(), + }); Ok(()) }, TrustedCall::timestamp_set(enclave_account, now, parentchain_id) => { diff --git a/core-primitives/extrinsics-factory/src/lib.rs b/core-primitives/extrinsics-factory/src/lib.rs index fd55dfccb7..4dc9b964b0 100644 --- a/core-primitives/extrinsics-factory/src/lib.rs +++ b/core-primitives/extrinsics-factory/src/lib.rs @@ -38,9 +38,12 @@ use itp_node_api::{ metadata::{provider::AccessNodeMetadata, NodeMetadata}, }; use itp_nonce_cache::{MutateNonce, Nonce}; -use itp_types::{parentchain::AccountId, OpaqueCall}; +use itp_types::{ + parentchain::{AccountId, GenericMortality}, + OpaqueCall, +}; use sp_core::H256; -use sp_runtime::{generic::Era, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use std::{sync::Arc, vec::Vec}; use substrate_api_client::ac_compose_macros::compose_extrinsic_offline; @@ -55,7 +58,7 @@ pub mod mock; pub trait CreateExtrinsics { fn create_extrinsics( &self, - calls: &[OpaqueCall], + calls: &[(OpaqueCall, GenericMortality)], extrinsics_params: Option, ) -> Result>; } @@ -108,16 +111,12 @@ where { fn create_extrinsics( &self, - calls: &[OpaqueCall], + calls: &[(OpaqueCall, GenericMortality)], extrinsics_params: Option, ) -> Result> { let mut nonce_lock = self.nonce_cache.load_for_mutation()?; let mut nonce_value = nonce_lock.0; - let additional_extrinsic_params = extrinsics_params.unwrap_or_else(|| { - ParentchainAdditionalParams::new().era(Era::Immortal, self.genesis_hash).tip(0) - }); - let (runtime_spec_version, runtime_transaction_version) = self.node_metadata_repository.get_from_metadata(|m| { (m.get_runtime_version(), m.get_runtime_transaction_version()) @@ -125,7 +124,15 @@ where let extrinsics_buffer: Vec = calls .iter() - .map(|call| { + .map(|(call, mortality)| { + let additional_extrinsic_params = extrinsics_params.unwrap_or_else(|| { + ParentchainAdditionalParams::new() + .era( + mortality.era, + mortality.mortality_checkpoint.unwrap_or(self.genesis_hash), + ) + .tip(0) + }); let extrinsic_params = ParentchainExtrinsicParams::new( runtime_spec_version, runtime_transaction_version, diff --git a/core-primitives/extrinsics-factory/src/mock.rs b/core-primitives/extrinsics-factory/src/mock.rs index 4e1923210e..dfa6017a86 100644 --- a/core-primitives/extrinsics-factory/src/mock.rs +++ b/core-primitives/extrinsics-factory/src/mock.rs @@ -17,7 +17,7 @@ use crate::{error::Result, CreateExtrinsics}; use itp_node_api::api_client::ParentchainAdditionalParams; -use itp_types::OpaqueCall; +use itp_types::{parentchain::GenericMortality, OpaqueCall}; use sp_runtime::OpaqueExtrinsic; use std::vec::Vec; @@ -30,7 +30,7 @@ pub struct ExtrinsicsFactoryMock; impl CreateExtrinsics for ExtrinsicsFactoryMock { fn create_extrinsics( &self, - _calls: &[OpaqueCall], + _calls: &[(OpaqueCall, GenericMortality)], _additional_params: Option, ) -> Result> { // Intention was to map an OpaqueCall to some dummy OpaqueExtrinsic, diff --git a/core-primitives/stf-executor/src/executor.rs b/core-primitives/stf-executor/src/executor.rs index 566cf669cf..a61792ef1b 100644 --- a/core-primitives/stf-executor/src/executor.rs +++ b/core-primitives/stf-executor/src/executor.rs @@ -141,17 +141,17 @@ where for call in extrinsic_call_backs.clone() { match call { - ParentchainCall::Integritee(opaque_call) => trace!( - "trusted_call wants to send encoded call to [Integritee] parentchain: 0x{}", - hex::encode(opaque_call.encode()) + ParentchainCall::Integritee { call, mortality } => trace!( + "trusted_call wants to send encoded call to [Integritee] parentchain: 0x{} with mortality {:?}", + hex::encode(call.encode()), mortality ), - ParentchainCall::TargetA(opaque_call) => trace!( - "trusted_call wants to send encoded call to [TargetA] parentchain: 0x{}", - hex::encode(opaque_call.encode()) + ParentchainCall::TargetA { call, mortality } => trace!( + "trusted_call wants to send encoded call to [TargetA] parentchain: 0x{} with mortality {:?}", + hex::encode(call.encode()), mortality ), - ParentchainCall::TargetB(opaque_call) => trace!( - "trusted_call wants to send encoded call to [TargetB] parentchain: 0x{}", - hex::encode(opaque_call.encode()) + ParentchainCall::TargetB { call, mortality } => trace!( + "trusted_call wants to send encoded call to [TargetB] parentchain: 0x{} with mortality {:?}", + hex::encode(call.encode()), mortality ), } } diff --git a/core-primitives/types/src/parentchain.rs b/core-primitives/types/src/parentchain.rs index f8690e45ac..fc65172d3d 100644 --- a/core-primitives/types/src/parentchain.rs +++ b/core-primitives/types/src/parentchain.rs @@ -27,7 +27,9 @@ use serde::{Deserialize, Serialize}; pub use sidechain_primitives::SidechainBlockConfirmation; use sp_core::bounded::alloc; use sp_runtime::{ - generic::Header as HeaderG, traits::BlakeTwo256, DispatchError, MultiAddress, MultiSignature, + generic::{Era, Header as HeaderG}, + traits::BlakeTwo256, + DispatchError, MultiAddress, MultiSignature, }; use substrate_api_client::{ ac_node_api::StaticEvent, @@ -283,32 +285,45 @@ impl From for () { fn from(_: ParentchainError) -> Self {} } +// All info for additionalParam except tip whi +#[derive(Encode, Debug, Clone, PartialEq, Eq)] +pub struct GenericMortality { + pub era: Era, + pub mortality_checkpoint: Option, +} + +impl GenericMortality { + pub fn immortal() -> Self { + Self { era: Era::Immortal, mortality_checkpoint: None } + } +} + /// a wrapper to target calls to specific parentchains #[derive(Encode, Debug, Clone, PartialEq, Eq)] pub enum ParentchainCall { - Integritee(OpaqueCall), - TargetA(OpaqueCall), - TargetB(OpaqueCall), + Integritee { call: OpaqueCall, mortality: GenericMortality }, + TargetA { call: OpaqueCall, mortality: GenericMortality }, + TargetB { call: OpaqueCall, mortality: GenericMortality }, } impl ParentchainCall { - pub fn as_integritee(&self) -> Option { - if let Self::Integritee(call) = self { - Some(call.clone()) + pub fn as_integritee(&self) -> Option<(OpaqueCall, GenericMortality)> { + if let Self::Integritee { call, mortality } = self { + Some((call.clone(), mortality.clone())) } else { None } } - pub fn as_target_a(&self) -> Option { - if let Self::TargetA(call) = self { - Some(call.clone()) + pub fn as_target_a(&self) -> Option<(OpaqueCall, GenericMortality)> { + if let Self::TargetA { call, mortality } = self { + Some((call.clone(), mortality.clone())) } else { None } } - pub fn as_target_b(&self) -> Option { - if let Self::TargetB(call) = self { - Some(call.clone()) + pub fn as_target_b(&self) -> Option<(OpaqueCall, GenericMortality)> { + if let Self::TargetB { call, mortality } = self { + Some((call.clone(), mortality.clone())) } else { None } @@ -316,19 +331,19 @@ impl ParentchainCall { pub fn as_opaque_call_for(&self, parentchain_id: ParentchainId) -> Option { match parentchain_id { ParentchainId::Integritee => - if let Self::Integritee(call) = self { + if let Self::Integritee { call, mortality: _ } = self { Some(call.clone()) } else { None }, ParentchainId::TargetA => - if let Self::TargetA(call) = self { + if let Self::TargetA { call, mortality: _ } = self { Some(call.clone()) } else { None }, ParentchainId::TargetB => - if let Self::TargetB(call) = self { + if let Self::TargetB { call, mortality: _ } = self { Some(call.clone()) } else { None diff --git a/core/offchain-worker-executor/src/executor.rs b/core/offchain-worker-executor/src/executor.rs index 30433d5012..f07b2cc33c 100644 --- a/core/offchain-worker-executor/src/executor.rs +++ b/core/offchain-worker-executor/src/executor.rs @@ -28,7 +28,10 @@ use itp_stf_interface::system_pallet::SystemPalletEventInterface; use itp_stf_primitives::{traits::TrustedCallVerification, types::TrustedOperationOrHash}; use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; use itp_top_pool_author::traits::AuthorApi; -use itp_types::{parentchain::ParentchainCall, OpaqueCall, ShardIdentifier, H256}; +use itp_types::{ + parentchain::{GenericMortality, ParentchainCall}, + OpaqueCall, ShardIdentifier, H256, +}; use log::*; use sp_runtime::traits::Block; use std::{marker::PhantomData, sync::Arc, time::Duration, vec::Vec}; @@ -185,15 +188,15 @@ impl< } fn send_parentchain_effects(&self, parentchain_effects: Vec) -> Result<()> { - let integritee_calls: Vec = parentchain_effects + let integritee_calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_effects .iter() .filter_map(|parentchain_call| parentchain_call.as_integritee()) .collect(); - let target_a_calls: Vec = parentchain_effects + let target_a_calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_effects .iter() .filter_map(|parentchain_call| parentchain_call.as_target_a()) .collect(); - let target_b_calls: Vec = parentchain_effects + let target_b_calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_effects .iter() .filter_map(|parentchain_call| parentchain_call.as_target_b()) .collect(); @@ -204,10 +207,10 @@ impl< target_b_calls.len() ); if !target_a_calls.is_empty() { - warn!("sending extrinsics to target A unimplemented") + warn!("sending extrinsics to target A unimplemented for OCW") }; if !target_b_calls.is_empty() { - warn!("sending extrinsics to target B unimplemented") + warn!("sending extrinsics to target B unimplemented for OCW") }; let extrinsics = diff --git a/core/parentchain/block-importer/src/block_importer.rs b/core/parentchain/block-importer/src/block_importer.rs index becb9e9a6b..7302395e9c 100644 --- a/core/parentchain/block-importer/src/block_importer.rs +++ b/core/parentchain/block-importer/src/block_importer.rs @@ -28,12 +28,12 @@ use itp_extrinsics_factory::CreateExtrinsics; use itp_stf_executor::traits::StfUpdateState; use itp_stf_interface::ShardCreationInfo; use itp_types::{ - parentchain::{IdentifyParentchain, ParentchainId}, + parentchain::{GenericMortality, IdentifyParentchain, ParentchainId}, OpaqueCall, H256, }; use log::*; use sp_runtime::{ - generic::SignedBlock as SignedBlockG, + generic::{Era, SignedBlock as SignedBlockG}, traits::{Block as ParentchainBlockTrait, Header as HeaderT, NumberFor}, }; use std::{marker::PhantomData, sync::Arc, vec, vec::Vec}; @@ -118,7 +118,7 @@ impl< blocks_to_import: Vec, events_to_import: Vec>, ) -> Result<()> { - let mut calls = Vec::::new(); + let mut calls = Vec::<(OpaqueCall, GenericMortality)>::new(); let id = self.validator_accessor.parentchain_id(); debug!( @@ -172,7 +172,15 @@ impl< .execute_indirect_calls_in_extrinsics(&block, &raw_events) { Ok(Some(confirm_processed_parentchain_block_call)) => { - calls.push(confirm_processed_parentchain_block_call); + let opaque_call = confirm_processed_parentchain_block_call; + // if we have significant downtime, this mortality means we will not confirm all imported blocks + /* + let mortality = GenericMortality { + era: Era::Mortal(300, 0), + mortality_checkpoint: Some(block.hash()), + };*/ + let mortality = GenericMortality::immortal(); + calls.push((opaque_call, mortality)); }, Ok(None) => trace!("omitting confirmation call to non-integritee parentchain"), Err(e) => error!("[{:?}] Error executing relevant extrinsics: {:?}", id, e), @@ -186,7 +194,7 @@ impl< ); } - // Create extrinsics for all `unshielding` and `block processed` calls we've gathered. + // Create extrinsics for all `block processed` calls we've gathered. let parentchain_extrinsics = self.extrinsics_factory.create_extrinsics(calls.as_slice(), None)?; diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index f91a0ad7e4..72a8590d79 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -46,7 +46,7 @@ use itp_node_api::metadata::{ }; use itp_node_api_metadata::NodeMetadata; use itp_settings::worker::MR_ENCLAVE_SIZE; -use itp_types::OpaqueCall; +use itp_types::{parentchain::GenericMortality, OpaqueCall}; use itp_utils::write_slice_and_whitespace_pad; use log::*; use sgx_types::*; @@ -390,7 +390,8 @@ pub fn generate_ias_skip_ra_extrinsic_from_der_cert_internal( fn create_extrinsics(call: OpaqueCall) -> EnclaveResult { let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; - let extrinsics = extrinsics_factory.create_extrinsics(&[call], None)?; + let extrinsics = + extrinsics_factory.create_extrinsics(&[(call, GenericMortality::immortal())], None)?; Ok(extrinsics[0].clone()) } diff --git a/enclave-runtime/src/shard_config.rs b/enclave-runtime/src/shard_config.rs index a22e79eb0d..3ee7cf2e47 100644 --- a/enclave-runtime/src/shard_config.rs +++ b/enclave-runtime/src/shard_config.rs @@ -38,6 +38,7 @@ use itp_types::{ use itp_utils::hex::hex_encode; use log::*; +use itp_types::parentchain::GenericMortality; use teerex_primitives::EnclaveFingerprint; pub(crate) fn init_shard_config(shard: ShardIdentifier) -> EnclaveResult<()> { @@ -56,7 +57,7 @@ pub(crate) fn init_shard_config(shard: ShardIdentifier) -> EnclaveResult<()> { let opaque_call = OpaqueCall::from_tuple(&(call, shard, shard_config, BlockNumber::from(0u8))); debug!("encoded call: {}", hex_encode(opaque_call.encode().as_slice())); let xts = extrinsics_factory - .create_extrinsics(&[opaque_call], None) + .create_extrinsics(&[(opaque_call, GenericMortality::immortal())], None) .map_err(|e| Error::Other(e.into()))?; info!("Initializing or touching shard config on integritee network. awaiting inclusion before continuing"); diff --git a/enclave-runtime/src/shard_vault.rs b/enclave-runtime/src/shard_vault.rs index 0f2ea89d8b..e62ec64da2 100644 --- a/enclave-runtime/src/shard_vault.rs +++ b/enclave-runtime/src/shard_vault.rs @@ -43,7 +43,7 @@ use itp_sgx_crypto::key_repository::AccessKey; use itp_stf_interface::{parentchain_pallet::ParentchainPalletInstancesInterface, ShardVaultQuery}; use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; use itp_types::{ - parentchain::{AccountId, Address, Balance, ParentchainId, ProxyType}, + parentchain::{AccountId, Address, Balance, GenericMortality, ParentchainId, ProxyType}, OpaqueCall, ShardIdentifier, }; use log::*; @@ -189,7 +189,8 @@ pub(crate) fn init_proxied_shard_vault_internal( )); info!("[{:?}] vault funding call: 0x{}", parentchain_id, hex::encode(call.0.clone())); - let xts = enclave_extrinsics_factory.create_extrinsics(&[call], None)?; + let xts = enclave_extrinsics_factory + .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; //this extrinsic must be included in a block before we can move on. otherwise the next will fail ocall_api.send_to_parentchain(xts, &parentchain_id, true)?; @@ -212,7 +213,8 @@ pub(crate) fn init_proxied_shard_vault_internal( )); info!("[{:?}] add proxy call: 0x{}", parentchain_id, hex::encode(call.0.clone())); - let xts = vault_extrinsics_factory.create_extrinsics(&[call], None)?; + let xts = vault_extrinsics_factory + .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; ocall_api.send_to_parentchain(xts, &parentchain_id, false)?; Ok(()) @@ -266,7 +268,8 @@ pub(crate) fn add_shard_vault_proxy( )); info!("proxied add proxy call: 0x{}", hex::encode(call.0.clone())); - let xts = enclave_extrinsics_factory.create_extrinsics(&[call], None)?; + let xts = enclave_extrinsics_factory + .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, false)?; Ok(()) diff --git a/enclave-runtime/src/top_pool_execution.rs b/enclave-runtime/src/top_pool_execution.rs index e9dd8402d2..ed533a5117 100644 --- a/enclave-runtime/src/top_pool_execution.rs +++ b/enclave-runtime/src/top_pool_execution.rs @@ -56,7 +56,7 @@ use itp_sgx_crypto::key_repository::AccessKey; use itp_stf_state_handler::query_shard_state::QueryShardState; use itp_time_utils::duration_now; use itp_types::{ - parentchain::{ParentchainCall, ParentchainId, SidechainBlockConfirmation}, + parentchain::{GenericMortality, ParentchainCall, ParentchainId, SidechainBlockConfirmation}, Block, OpaqueCall, H256, }; use its_primitives::{ @@ -333,7 +333,7 @@ where debug!("Proposing {} sidechain block(s) (broadcasting to peers)", blocks.len()); ocall_api.propose_sidechain_blocks(blocks)?; - let calls: Vec = parentchain_calls + let calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_calls .iter() .filter_map(|parentchain_call| parentchain_call.as_integritee()) .collect(); @@ -344,7 +344,7 @@ where let validator_access = get_validator_accessor_from_integritee_solo_or_parachain()?; validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; } - let calls: Vec = parentchain_calls + let calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_calls .iter() .filter_map(|parentchain_call| parentchain_call.as_target_a()) .collect(); @@ -355,7 +355,7 @@ where let validator_access = get_validator_accessor_from_target_a_solo_or_parachain()?; validator_access.execute_mut_on_validator(|v| v.send_extrinsics(xts))?; } - let calls: Vec = parentchain_calls + let calls: Vec<(OpaqueCall, GenericMortality)> = parentchain_calls .iter() .filter_map(|parentchain_call| parentchain_call.as_target_b()) .collect(); diff --git a/sidechain/consensus/common/src/block_import_confirmation_handler.rs b/sidechain/consensus/common/src/block_import_confirmation_handler.rs index ec8a9f29da..7b0757d94e 100644 --- a/sidechain/consensus/common/src/block_import_confirmation_handler.rs +++ b/sidechain/consensus/common/src/block_import_confirmation_handler.rs @@ -23,7 +23,10 @@ use itp_extrinsics_factory::CreateExtrinsics; use itp_node_api_metadata::{pallet_sidechain::SidechainCallIndexes, NodeMetadataTrait}; use itp_node_api_metadata_provider::AccessNodeMetadata; use itp_settings::worker::BLOCK_NUMBER_FINALIZATION_DIFF; -use itp_types::{parentchain::SidechainBlockConfirmation, OpaqueCall, ShardIdentifier}; +use itp_types::{ + parentchain::{GenericMortality, SidechainBlockConfirmation}, + OpaqueCall, ShardIdentifier, +}; use its_primitives::traits::Header as HeaderTrait; use log::*; use sp_runtime::traits::Block as ParentchainBlockTrait; @@ -130,7 +133,7 @@ impl< let xts = self .extrinsics_factory - .create_extrinsics(&[opaque_call], None) + .create_extrinsics(&[(opaque_call, GenericMortality::immortal())], None) .map_err(|e| Error::Other(e.into()))?; debug!("Sending sidechain block import confirmation extrinsic.."); From 9714d8c9fa1a9269e1775277ccd9c46100eed8b8 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 5 Nov 2024 17:07:40 +0100 Subject: [PATCH 02/10] make Parentchain block confirmation mortal --- core/parentchain/block-importer/src/block_importer.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/parentchain/block-importer/src/block_importer.rs b/core/parentchain/block-importer/src/block_importer.rs index 7302395e9c..5681ec6a91 100644 --- a/core/parentchain/block-importer/src/block_importer.rs +++ b/core/parentchain/block-importer/src/block_importer.rs @@ -174,12 +174,10 @@ impl< Ok(Some(confirm_processed_parentchain_block_call)) => { let opaque_call = confirm_processed_parentchain_block_call; // if we have significant downtime, this mortality means we will not confirm all imported blocks - /* let mortality = GenericMortality { - era: Era::Mortal(300, 0), + era: Era::mortal(512, (*block.header().number()).into()), mortality_checkpoint: Some(block.hash()), - };*/ - let mortality = GenericMortality::immortal(); + }; calls.push((opaque_call, mortality)); }, Ok(None) => trace!("omitting confirmation call to non-integritee parentchain"), From 7b4bbef16e8f02d66c2feb19926a2b26f3c1db50 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 5 Nov 2024 17:36:24 +0100 Subject: [PATCH 03/10] make unshielding extrinsics mortal --- app-libs/stf/src/helpers.rs | 26 +++++++++++++++++++++++++- app-libs/stf/src/trusted_call.rs | 22 ++++++++-------------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/app-libs/stf/src/helpers.rs b/app-libs/stf/src/helpers.rs index 650d2e2173..9ea89fe7a0 100644 --- a/app-libs/stf/src/helpers.rs +++ b/app-libs/stf/src/helpers.rs @@ -23,9 +23,10 @@ use itp_stf_primitives::{ types::AccountId, }; use itp_storage::{storage_double_map_key, storage_map_key, storage_value_key, StorageHasher}; -use itp_types::parentchain::{Hash, ParentchainId}; +use itp_types::parentchain::{BlockNumber, GenericMortality, Hash, ParentchainId}; use itp_utils::stringify::account_id_to_string; use log::*; +use sp_runtime::generic::Era; use std::prelude::v1::*; pub fn get_storage_value( @@ -193,3 +194,26 @@ pub fn wrap_bytes(data: &[u8]) -> Vec { bytes_wrapped } + +pub fn get_mortality( + parentchain_id: ParentchainId, + blocks_to_live: BlockNumber, +) -> Option { + let (maybe_number, maybe_hash) = match parentchain_id { + ParentchainId::Integritee => + (ParentchainIntegritee::block_number(), ParentchainIntegritee::block_hash()), + ParentchainId::TargetA => + (ParentchainTargetA::block_number(), ParentchainTargetA::block_hash()), + ParentchainId::TargetB => + (ParentchainTargetB::block_number(), ParentchainTargetB::block_hash()), + }; + if let Some(number) = maybe_number { + if let Some(hash) = maybe_hash { + return Some(GenericMortality { + era: Era::mortal(blocks_to_live.into(), number.into()), + mortality_checkpoint: Some(hash), + }) + } + } + None +} diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index a2ec6b05d8..cd1ea5e2e1 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -26,7 +26,7 @@ use crate::evm_helpers::{create_code_hash, evm_create2_address, evm_create_addre use crate::{ guess_the_number::GuessTheNumberTrustedCall, helpers::{ - enclave_signer_account, ensure_enclave_signer_account, shard_vault, + enclave_signer_account, ensure_enclave_signer_account, get_mortality, shard_vault, shielding_target_genesis_hash, wrap_bytes, }, Getter, STF_SHIELDING_FEE_AMOUNT_DIVIDER, @@ -330,7 +330,7 @@ where Address::from(beneficiary), Compact(value), )); - let proxy_call = OpaqueCall::from_tuple(&( + let call = OpaqueCall::from_tuple(&( node_metadata_repo .get_from_metadata(|m| m.proxy_call_indexes()) .map_err(|_| StfError::InvalidMetadata)? @@ -339,19 +339,13 @@ where None::, vault_transfer_call, )); + let mortality = + get_mortality(parentchain_id, 32).unwrap_or_else(GenericMortality::immortal); + let parentchain_call = match parentchain_id { - ParentchainId::Integritee => ParentchainCall::Integritee { - call: proxy_call, - mortality: GenericMortality::immortal(), - }, - ParentchainId::TargetA => ParentchainCall::TargetA { - call: proxy_call, - mortality: GenericMortality::immortal(), - }, - ParentchainId::TargetB => ParentchainCall::TargetB { - call: proxy_call, - mortality: GenericMortality::immortal(), - }, + ParentchainId::Integritee => ParentchainCall::Integritee { call, mortality }, + ParentchainId::TargetA => ParentchainCall::TargetA { call, mortality }, + ParentchainId::TargetB => ParentchainCall::TargetB { call, mortality }, }; calls.push(parentchain_call); Ok(()) From 83d2f4a6727f5d3fcc0b7a1586b0dfedf67803a6 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 5 Nov 2024 17:41:20 +0100 Subject: [PATCH 04/10] fix tests --- core-primitives/extrinsics-factory/src/lib.rs | 11 ++++++++--- core-primitives/stf-executor/src/lib.rs | 8 +++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core-primitives/extrinsics-factory/src/lib.rs b/core-primitives/extrinsics-factory/src/lib.rs index 4dc9b964b0..89b5909a29 100644 --- a/core-primitives/extrinsics-factory/src/lib.rs +++ b/core-primitives/extrinsics-factory/src/lib.rs @@ -179,7 +179,10 @@ pub mod tests { node_metadata_repo, ); - let opaque_calls = [OpaqueCall(vec![3u8; 42]), OpaqueCall(vec![12u8, 78])]; + let opaque_calls = [ + (OpaqueCall(vec![3u8; 42]), GenericMortality::immortal()), + (OpaqueCall(vec![12u8, 78]), GenericMortality::immortal()), + ]; let xts = extrinsics_factory.create_extrinsics(&opaque_calls, None).unwrap(); assert_eq!(opaque_calls.len(), xts.len()); @@ -204,8 +207,10 @@ pub mod tests { StaticExtrinsicSigner::<_, PairSignature>::new(test_account2()), nonce_cache2.clone(), ); - - let opaque_calls = [OpaqueCall(vec![3u8; 42]), OpaqueCall(vec![12u8, 78])]; + let opaque_calls = [ + (OpaqueCall(vec![3u8; 42]), GenericMortality::immortal()), + (OpaqueCall(vec![12u8, 78]), GenericMortality::immortal()), + ]; let xts = extrinsics_factory.create_extrinsics(&opaque_calls, None).unwrap(); assert_eq!(opaque_calls.len(), xts.len()); diff --git a/core-primitives/stf-executor/src/lib.rs b/core-primitives/stf-executor/src/lib.rs index 08d9c9125e..622d7def2a 100644 --- a/core-primitives/stf-executor/src/lib.rs +++ b/core-primitives/stf-executor/src/lib.rs @@ -173,7 +173,7 @@ mod tests { use super::*; use itp_sgx_externalities::SgxExternalities; use itp_test::mock::stf_mock::{GetterMock, TrustedCallSignedMock}; - use itp_types::OpaqueCall; + use itp_types::{parentchain::GenericMortality, OpaqueCall}; #[test] fn is_success_works() { @@ -234,8 +234,10 @@ mod tests { int: u8, ) -> (ExecutedOperation, H256) { let hash = H256::from([int; 32]); - let opaque_call: Vec = - vec![ParentchainCall::Integritee(OpaqueCall(vec![int; 10]))]; + let opaque_call: Vec = vec![ParentchainCall::Integritee { + call: OpaqueCall(vec![int; 10]), + mortality: GenericMortality::immortal(), + }]; let operation = ExecutedOperation::success(hash, TrustedOperationOrHash::Hash(hash), opaque_call); (operation, hash) From 8820f187de32d23b06064efcbea3c2c6ec0de3fd Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 5 Nov 2024 18:09:09 +0100 Subject: [PATCH 05/10] make sidechain block import confirmation mortal --- .../src/block_import_confirmation_handler.rs | 21 ++++++++++++++----- .../consensus/common/src/peer_block_sync.rs | 5 +++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/sidechain/consensus/common/src/block_import_confirmation_handler.rs b/sidechain/consensus/common/src/block_import_confirmation_handler.rs index 7b0757d94e..6d9ab2fd63 100644 --- a/sidechain/consensus/common/src/block_import_confirmation_handler.rs +++ b/sidechain/consensus/common/src/block_import_confirmation_handler.rs @@ -25,20 +25,24 @@ use itp_node_api_metadata_provider::AccessNodeMetadata; use itp_settings::worker::BLOCK_NUMBER_FINALIZATION_DIFF; use itp_types::{ parentchain::{GenericMortality, SidechainBlockConfirmation}, - OpaqueCall, ShardIdentifier, + OpaqueCall, ShardIdentifier, H256, }; use its_primitives::traits::Header as HeaderTrait; use log::*; -use sp_runtime::traits::Block as ParentchainBlockTrait; +use sp_runtime::{ + generic::Era, + traits::{Block as ParentchainBlockTrait, Header}, +}; use std::{marker::PhantomData, sync::Arc}; /// Trait to confirm a sidechain block import. -pub trait ConfirmBlockImport { +pub trait ConfirmBlockImport { fn confirm_import( &self, header: &SidechainHeader, shard: &ShardIdentifier, maybe_last_sidechain_block_confirmation: &Option, + latest_parentchain_header: &::Header, ) -> Result<()>; } @@ -91,7 +95,7 @@ impl< NodeMetadataRepository, ExtrinsicsFactory, ValidatorAccessor, - > ConfirmBlockImport + > ConfirmBlockImport for BlockImportConfirmationHandler< ParentchainBlock, SidechainHeader, @@ -106,12 +110,15 @@ impl< NodeMetadataRepository::MetadataType: NodeMetadataTrait, ExtrinsicsFactory: CreateExtrinsics, ValidatorAccessor: ValidatorAccess + Send + Sync + 'static, + H256: From<::Hash>, + u64: From<<::Header as Header>::Number>, { fn confirm_import( &self, header: &SidechainHeader, shard: &ShardIdentifier, maybe_last_sidechain_block_confirmation: &Option, + latest_parentchain_block: &::Header, ) -> Result<()> { if header.block_number() == header.next_finalization_block_number() { let call = self @@ -131,9 +138,13 @@ impl< }, )); + let mortality = GenericMortality { + era: Era::mortal(16, (*latest_parentchain_block.number()).into()), + mortality_checkpoint: Some(latest_parentchain_block.hash().into()), + }; let xts = self .extrinsics_factory - .create_extrinsics(&[(opaque_call, GenericMortality::immortal())], None) + .create_extrinsics(&[(opaque_call, mortality)], None) .map_err(|e| Error::Other(e.into()))?; debug!("Sending sidechain block import confirmation extrinsic.."); diff --git a/sidechain/consensus/common/src/peer_block_sync.rs b/sidechain/consensus/common/src/peer_block_sync.rs index d105730ae9..aa93c714dd 100644 --- a/sidechain/consensus/common/src/peer_block_sync.rs +++ b/sidechain/consensus/common/src/peer_block_sync.rs @@ -91,6 +91,7 @@ impl< SidechainOCallApi: EnclaveSidechainOCallApi, ImportConfirmationHandler: ConfirmBlockImport< <::Block as BlockTrait>::HeaderType, + ParentchainBlock, >, { pub fn new( @@ -165,7 +166,7 @@ where <<::Block as BlockTrait>::BlockDataType as BlockData>::Public: Encode + Debug, BlockImporter: BlockImport, SidechainOCallApi: EnclaveSidechainOCallApi, - ImportConfirmationHandler: ConfirmBlockImport<<::Block as BlockTrait>::HeaderType>, + ImportConfirmationHandler: ConfirmBlockImport<<::Block as BlockTrait>::HeaderType, ParentchainBlock>, { fn import_or_sync_block( &self, @@ -220,7 +221,7 @@ where // We confirm the successful block import. Only in this case, not when we're in // on-boarding and importing blocks that were fetched from a peer. - if let Err(e) = self.import_confirmation_handler.confirm_import(sidechain_block.block().header(), &shard_identifier, maybe_latest_sidechain_block_confirmation) { + if let Err(e) = self.import_confirmation_handler.confirm_import(sidechain_block.block().header(), &shard_identifier, maybe_latest_sidechain_block_confirmation, &latest_parentchain_header) { error!("Failed to confirm sidechain block import: {:?}", e); } From 37a8c8487af8c1cd00c09f1e431b022260d722bd Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Wed, 6 Nov 2024 10:48:43 +0100 Subject: [PATCH 06/10] try to make attestation extrinsics mortal --- .../src/event_subscriber.rs | 1 + core-primitives/ocall-api/src/lib.rs | 4 +- core-primitives/test/src/mock/onchain_mock.rs | 4 +- core-primitives/types/src/lib.rs | 11 ++++-- enclave-runtime/src/attestation.rs | 37 ++++++++++++++++--- enclave-runtime/src/ocall/on_chain_ocall.rs | 9 +++-- .../test/mocks/propose_to_import_call_mock.rs | 9 +++-- service/src/ocall_bridge/bridge_api.rs | 2 + .../src/ocall_bridge/worker_on_chain_ocall.rs | 37 +++++++++++++++++-- sidechain/consensus/slots/src/slot_stream.rs | 1 + 10 files changed, 92 insertions(+), 23 deletions(-) diff --git a/app-libs/parentchain-interface/src/event_subscriber.rs b/app-libs/parentchain-interface/src/event_subscriber.rs index 45434ee663..de5765340f 100644 --- a/app-libs/parentchain-interface/src/event_subscriber.rs +++ b/app-libs/parentchain-interface/src/event_subscriber.rs @@ -14,6 +14,7 @@ limitations under the License. */ +extern crate alloc; use alloc::sync::Arc; use core::sync::atomic::{AtomicBool, Ordering}; use itp_api_client_types::ParentchainApi; diff --git a/core-primitives/ocall-api/src/lib.rs b/core-primitives/ocall-api/src/lib.rs index 37b74be59f..6dbcde3f9a 100644 --- a/core-primitives/ocall-api/src/lib.rs +++ b/core-primitives/ocall-api/src/lib.rs @@ -96,11 +96,11 @@ pub trait EnclaveOnChainOCallApi: Clone + Send + Sync { await_each_inclusion: bool, ) -> SgxResult<()>; - fn worker_request( + fn worker_request, V: Encode + Decode>( &self, req: Vec, parentchain_id: &ParentchainId, - ) -> SgxResult>>; + ) -> SgxResult>>; fn get_storage_verified, V: Decode>( &self, diff --git a/core-primitives/test/src/mock/onchain_mock.rs b/core-primitives/test/src/mock/onchain_mock.rs index ce2c8d4935..57c1d086a4 100644 --- a/core-primitives/test/src/mock/onchain_mock.rs +++ b/core-primitives/test/src/mock/onchain_mock.rs @@ -185,11 +185,11 @@ impl EnclaveOnChainOCallApi for OnchainMock { Ok(()) } - fn worker_request( + fn worker_request, V: Encode + Decode>( &self, _req: Vec, _: &ParentchainId, - ) -> SgxResult>> { + ) -> SgxResult>> { Ok(Vec::new()) } diff --git a/core-primitives/types/src/lib.rs b/core-primitives/types/src/lib.rs index 19563a7de5..b3f0e0b187 100644 --- a/core-primitives/types/src/lib.rs +++ b/core-primitives/types/src/lib.rs @@ -20,6 +20,7 @@ use crate::storage::StorageEntry; use codec::{Decode, Encode}; +use sp_runtime::traits::Header as HeaderTrait; use sp_std::vec::Vec; pub mod parentchain; @@ -113,17 +114,21 @@ pub enum TrustedOperationStatus { #[derive(Encode, Decode, Clone, Debug, PartialEq)] pub enum WorkerRequest { ChainStorage(Vec, Option), // (storage_key, at_block) + /// for awareness: we call it unverified because there is no way how the enclave could verify the correctness of the information + LatestParentchainHeaderUnverified, } #[derive(Encode, Decode, Clone, Debug, PartialEq)] -pub enum WorkerResponse { +pub enum WorkerResponse { ChainStorage(Vec, Option, Option>>), // (storage_key, storage_value, storage_proof) + LatestParentchainHeaderUnverified(H), } -impl From>> for StorageEntry> { - fn from(response: WorkerResponse>) -> Self { +impl From>> for StorageEntry> { + fn from(response: WorkerResponse>) -> Self { match response { WorkerResponse::ChainStorage(key, value, proof) => StorageEntry { key, value, proof }, + WorkerResponse::LatestParentchainHeaderUnverified(_) => StorageEntry::default(), } } } diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index 72a8590d79..e2c122da7b 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -28,7 +28,9 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - initialization::global_components::GLOBAL_ATTESTATION_HANDLER_COMPONENT, + initialization::global_components::{ + GLOBAL_ATTESTATION_HANDLER_COMPONENT, GLOBAL_OCALL_API_COMPONENT, + }, utils::{ get_extrinsic_factory_from_integritee_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, @@ -36,6 +38,7 @@ use crate::{ Error as EnclaveError, Result as EnclaveResult, }; use codec::{Decode, Encode}; +use ita_stf::ParentchainHeader; use itp_attestation_handler::{AttestationHandler, RemoteAttestationType, SgxQlQveCollateral}; use itp_component_container::ComponentGetter; use itp_extrinsics_factory::CreateExtrinsics; @@ -45,12 +48,16 @@ use itp_node_api::metadata::{ Error as MetadataError, }; use itp_node_api_metadata::NodeMetadata; +use itp_ocall_api::EnclaveOnChainOCallApi; use itp_settings::worker::MR_ENCLAVE_SIZE; -use itp_types::{parentchain::GenericMortality, OpaqueCall}; +use itp_types::{ + parentchain::{GenericMortality, ParentchainId}, + OpaqueCall, WorkerRequest, WorkerResponse, +}; use itp_utils::write_slice_and_whitespace_pad; use log::*; use sgx_types::*; -use sp_runtime::OpaqueExtrinsic; +use sp_runtime::{generic::Era, OpaqueExtrinsic}; use std::{prelude::v1::*, slice, vec::Vec}; use teerex_primitives::SgxAttestationMethod; @@ -390,8 +397,28 @@ pub fn generate_ias_skip_ra_extrinsic_from_der_cert_internal( fn create_extrinsics(call: OpaqueCall) -> EnclaveResult { let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; - let extrinsics = - extrinsics_factory.create_extrinsics(&[(call, GenericMortality::immortal())], None)?; + let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; + let response: Option>> = ocall_api + .worker_request( + [WorkerRequest::LatestParentchainHeaderUnverified].into(), + &ParentchainId::Integritee, + ) + .ok() + .iter() + .filter_map(|r| r.first().map(|v| v.clone())) + .next(); + let mortality = + if let Some(WorkerResponse::LatestParentchainHeaderUnverified(header)) = response { + info!("mortality checkpoint: {} {}", header.number, header.hash()); + GenericMortality { + era: Era::mortal(64, header.number.into()), + mortality_checkpoint: Some(header.hash), + } + } else { + GenericMortality::immortal() + }; + + let extrinsics = extrinsics_factory.create_extrinsics(&[(call, mortality)], None)?; Ok(extrinsics[0].clone()) } diff --git a/enclave-runtime/src/ocall/on_chain_ocall.rs b/enclave-runtime/src/ocall/on_chain_ocall.rs index e71fb72618..5a79edc09f 100644 --- a/enclave-runtime/src/ocall/on_chain_ocall.rs +++ b/enclave-runtime/src/ocall/on_chain_ocall.rs @@ -19,6 +19,7 @@ use crate::ocall::{ffi, OcallApi}; use codec::{Decode, Encode}; use frame_support::ensure; +use ita_stf::ParentchainHeader; use itc_parentchain::primitives::ParentchainId; use itp_ocall_api::{EnclaveOnChainOCallApi, Result}; use itp_storage::{verify_storage_entries, Error as StorageError}; @@ -56,11 +57,11 @@ impl EnclaveOnChainOCallApi for OcallApi { Ok(()) } - fn worker_request( + fn worker_request, V: Encode + Decode>( &self, req: Vec, parentchain_id: &ParentchainId, - ) -> SgxResult>> { + ) -> SgxResult>> { let mut rt: sgx_status_t = sgx_status_t::SGX_ERROR_UNEXPECTED; let mut resp: Vec = vec![0; 4196 * 4]; let request_encoded = req.encode(); @@ -81,7 +82,7 @@ impl EnclaveOnChainOCallApi for OcallApi { ensure!(rt == sgx_status_t::SGX_SUCCESS, rt); ensure!(res == sgx_status_t::SGX_SUCCESS, res); - let decoded_response: Vec> = Decode::decode(&mut resp.as_slice()) + let decoded_response: Vec> = Decode::decode(&mut resp.as_slice()) .map_err(|e| { error!("Failed to decode WorkerResponse: {}", e); sgx_status_t::SGX_ERROR_UNEXPECTED @@ -117,7 +118,7 @@ impl EnclaveOnChainOCallApi for OcallApi { .collect(); let storage_entries = self - .worker_request::>(requests, parentchain_id) + .worker_request::>(requests, parentchain_id) .map(|storages| verify_storage_entries(storages, header))??; Ok(storage_entries) diff --git a/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs b/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs index 3078bb43c1..9c0baeb769 100644 --- a/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs +++ b/enclave-runtime/src/test/mocks/propose_to_import_call_mock.rs @@ -27,7 +27,10 @@ use itp_types::{ use its_primitives::types::block::SignedBlock as SignedSidechainBlockType; use its_sidechain::consensus_common::BlockImport; use sgx_types::SgxResult; -use sp_runtime::{traits::Header as ParentchainHeaderTrait, OpaqueExtrinsic}; +use sp_runtime::{ + traits::{Header as ParentchainHeaderTrait, Header}, + OpaqueExtrinsic, +}; use std::{sync::Arc, vec::Vec}; /// OCallApi mock that routes the proposed sidechain blocks directly to the importer, @@ -57,11 +60,11 @@ impl EnclaveOnChainOCallApi for ProposeToImportOCallApi { Ok(()) } - fn worker_request( + fn worker_request( &self, _req: Vec, _: &ParentchainId, - ) -> SgxResult>> { + ) -> SgxResult>> { todo!() } diff --git a/service/src/ocall_bridge/bridge_api.rs b/service/src/ocall_bridge/bridge_api.rs index 7904362345..6e8f67c666 100644 --- a/service/src/ocall_bridge/bridge_api.rs +++ b/service/src/ocall_bridge/bridge_api.rs @@ -145,6 +145,8 @@ pub enum OCallBridgeError { TargetAParentchainNotInitialized, #[error("Target B parentchain not initialized")] TargetBParentchainNotInitialized, + #[error("An error with the substrate node api")] + NodeApiError, } impl From for sgx_status_t { diff --git a/service/src/ocall_bridge/worker_on_chain_ocall.rs b/service/src/ocall_bridge/worker_on_chain_ocall.rs index 5a16be596a..2705ebed09 100644 --- a/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -21,10 +21,13 @@ use chrono::Local; use codec::{Decode, Encode}; use itp_api_client_types::ParentchainApi; use itp_node_api::node_api_factory::CreateNodeApi; -use itp_types::{parentchain::ParentchainId, WorkerRequest, WorkerResponse}; +use itp_types::{ + parentchain::{Header as ParentchainHeader, ParentchainId}, + DigestItem, WorkerRequest, WorkerResponse, +}; use log::*; use sp_core::blake2_256; -use sp_runtime::OpaqueExtrinsic; +use sp_runtime::{Digest, OpaqueExtrinsic}; use std::{ fs::{create_dir_all, File}, io::{self, Write}, @@ -33,7 +36,9 @@ use std::{ vec::Vec, }; use substrate_api_client::{ - ac_primitives::serde_impls::StorageKey, GetStorage, SubmitAndWatch, SubmitExtrinsic, XtStatus, + ac_primitives, + ac_primitives::{serde_impls::StorageKey, SubstrateHeader}, + GetChainInfo, GetStorage, SubmitAndWatch, SubmitExtrinsic, XtStatus, }; pub struct WorkerOnChainOCall { @@ -97,8 +102,18 @@ where let parentchain_id = ParentchainId::decode(&mut parentchain_id.as_slice())?; let api = self.create_api(parentchain_id)?; + let last_finalized = + api.get_finalized_head().map_err(|_| OCallBridgeError::NodeApiError)?; + let header = if let Some(header) = + api.get_header(last_finalized).map_err(|_| OCallBridgeError::NodeApiError)? + { + header + } else { + warn!("failed to fetch parentchain header. can't answer WorkerRequest"); + return Ok(Vec::::new().encode()) + }; - let resp: Vec>> = requests + let resp: Vec>> = requests .into_iter() .map(|req| match req { WorkerRequest::ChainStorage(key, hash) => WorkerResponse::ChainStorage( @@ -108,6 +123,20 @@ where |read_proof| read_proof.proof.into_iter().map(|bytes| bytes.0).collect(), ), ), + WorkerRequest::LatestParentchainHeaderUnverified => { + WorkerResponse::LatestParentchainHeaderUnverified( + // todo: fix this dirty and incomplete type hack + ParentchainHeader { + parent_hash: header.parent_hash, + number: header.number, + state_root: header.state_root, + extrinsics_root: header.extrinsics_root, + digest: Digest { + logs: header.digest.logs.iter().map(|di| itp_types::DigestItem {}), + }, + }, + ) + }, }) .collect(); diff --git a/sidechain/consensus/slots/src/slot_stream.rs b/sidechain/consensus/slots/src/slot_stream.rs index 8d02940b12..330d498eca 100644 --- a/sidechain/consensus/slots/src/slot_stream.rs +++ b/sidechain/consensus/slots/src/slot_stream.rs @@ -21,6 +21,7 @@ //! time during which certain events can and/or must occur. This crate //! provides generic functionality for slots. +extern crate alloc; use crate::time_until_next_slot; use alloc::sync::Arc; use core::sync::atomic::{AtomicBool, Ordering}; From c8a6abd740ca768da172da4359d6f67af071b32a Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Wed, 6 Nov 2024 10:59:10 +0100 Subject: [PATCH 07/10] mortal attestation works --- enclave-runtime/src/attestation.rs | 2 +- service/src/ocall_bridge/worker_on_chain_ocall.rs | 12 ++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index e2c122da7b..1a6c272eb9 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -412,7 +412,7 @@ fn create_extrinsics(call: OpaqueCall) -> EnclaveResult { info!("mortality checkpoint: {} {}", header.number, header.hash()); GenericMortality { era: Era::mortal(64, header.number.into()), - mortality_checkpoint: Some(header.hash), + mortality_checkpoint: Some(header.hash()), } } else { GenericMortality::immortal() diff --git a/service/src/ocall_bridge/worker_on_chain_ocall.rs b/service/src/ocall_bridge/worker_on_chain_ocall.rs index 2705ebed09..4944ac0b71 100644 --- a/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -125,16 +125,8 @@ where ), WorkerRequest::LatestParentchainHeaderUnverified => { WorkerResponse::LatestParentchainHeaderUnverified( - // todo: fix this dirty and incomplete type hack - ParentchainHeader { - parent_hash: header.parent_hash, - number: header.number, - state_root: header.state_root, - extrinsics_root: header.extrinsics_root, - digest: Digest { - logs: header.digest.logs.iter().map(|di| itp_types::DigestItem {}), - }, - }, + // todo: fix this dirty type hack + ParentchainHeader::decode(&mut header.encode().as_slice()).unwrap(), ) }, }) From b01e0881f579cd9131498d28598d78db6b0b7e50 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Wed, 6 Nov 2024 11:15:24 +0100 Subject: [PATCH 08/10] mortal shard vault and config init --- enclave-runtime/src/attestation.rs | 32 ++++------------------------- enclave-runtime/src/lib.rs | 1 + enclave-runtime/src/shard_config.rs | 7 +++++-- enclave-runtime/src/shard_vault.rs | 16 +++++++-------- enclave-runtime/src/utils.rs | 31 ++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 38 deletions(-) diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index 1a6c272eb9..b7803f2e2b 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -33,12 +33,11 @@ use crate::{ }, utils::{ get_extrinsic_factory_from_integritee_solo_or_parachain, - get_node_metadata_repository_from_integritee_solo_or_parachain, + get_node_metadata_repository_from_integritee_solo_or_parachain, try_mortality, }, Error as EnclaveError, Result as EnclaveResult, }; use codec::{Decode, Encode}; -use ita_stf::ParentchainHeader; use itp_attestation_handler::{AttestationHandler, RemoteAttestationType, SgxQlQveCollateral}; use itp_component_container::ComponentGetter; use itp_extrinsics_factory::CreateExtrinsics; @@ -48,16 +47,12 @@ use itp_node_api::metadata::{ Error as MetadataError, }; use itp_node_api_metadata::NodeMetadata; -use itp_ocall_api::EnclaveOnChainOCallApi; use itp_settings::worker::MR_ENCLAVE_SIZE; -use itp_types::{ - parentchain::{GenericMortality, ParentchainId}, - OpaqueCall, WorkerRequest, WorkerResponse, -}; +use itp_types::OpaqueCall; use itp_utils::write_slice_and_whitespace_pad; use log::*; use sgx_types::*; -use sp_runtime::{generic::Era, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use std::{prelude::v1::*, slice, vec::Vec}; use teerex_primitives::SgxAttestationMethod; @@ -398,26 +393,7 @@ pub fn generate_ias_skip_ra_extrinsic_from_der_cert_internal( fn create_extrinsics(call: OpaqueCall) -> EnclaveResult { let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; - let response: Option>> = ocall_api - .worker_request( - [WorkerRequest::LatestParentchainHeaderUnverified].into(), - &ParentchainId::Integritee, - ) - .ok() - .iter() - .filter_map(|r| r.first().map(|v| v.clone())) - .next(); - let mortality = - if let Some(WorkerResponse::LatestParentchainHeaderUnverified(header)) = response { - info!("mortality checkpoint: {} {}", header.number, header.hash()); - GenericMortality { - era: Era::mortal(64, header.number.into()), - mortality_checkpoint: Some(header.hash()), - } - } else { - GenericMortality::immortal() - }; - + let mortality = try_mortality(64, &ocall_api); let extrinsics = extrinsics_factory.create_extrinsics(&[(call, mortality)], None)?; Ok(extrinsics[0].clone()) diff --git a/enclave-runtime/src/lib.rs b/enclave-runtime/src/lib.rs index b744156279..ae65a4ae48 100644 --- a/enclave-runtime/src/lib.rs +++ b/enclave-runtime/src/lib.rs @@ -28,6 +28,7 @@ #[cfg(not(target_env = "sgx"))] #[macro_use] extern crate sgx_tstd as std; +extern crate alloc; use crate::{ error::{Error, Result}, diff --git a/enclave-runtime/src/shard_config.rs b/enclave-runtime/src/shard_config.rs index 3ee7cf2e47..a6c5eafc9d 100644 --- a/enclave-runtime/src/shard_config.rs +++ b/enclave-runtime/src/shard_config.rs @@ -38,7 +38,8 @@ use itp_types::{ use itp_utils::hex::hex_encode; use log::*; -use itp_types::parentchain::GenericMortality; +use crate::{initialization::global_components::GLOBAL_OCALL_API_COMPONENT, utils::try_mortality}; +use itp_component_container::ComponentGetter; use teerex_primitives::EnclaveFingerprint; pub(crate) fn init_shard_config(shard: ShardIdentifier) -> EnclaveResult<()> { @@ -56,8 +57,10 @@ pub(crate) fn init_shard_config(shard: ShardIdentifier) -> EnclaveResult<()> { let opaque_call = OpaqueCall::from_tuple(&(call, shard, shard_config, BlockNumber::from(0u8))); debug!("encoded call: {}", hex_encode(opaque_call.encode().as_slice())); + let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; + let mortality = try_mortality(64, &ocall_api); let xts = extrinsics_factory - .create_extrinsics(&[(opaque_call, GenericMortality::immortal())], None) + .create_extrinsics(&[(opaque_call, mortality)], None) .map_err(|e| Error::Other(e.into()))?; info!("Initializing or touching shard config on integritee network. awaiting inclusion before continuing"); diff --git a/enclave-runtime/src/shard_vault.rs b/enclave-runtime/src/shard_vault.rs index e62ec64da2..a79cd476f7 100644 --- a/enclave-runtime/src/shard_vault.rs +++ b/enclave-runtime/src/shard_vault.rs @@ -26,7 +26,7 @@ use crate::{ get_extrinsic_factory_from_target_b_solo_or_parachain, get_node_metadata_repository_from_integritee_solo_or_parachain, get_node_metadata_repository_from_target_a_solo_or_parachain, - get_node_metadata_repository_from_target_b_solo_or_parachain, DecodeRaw, + get_node_metadata_repository_from_target_b_solo_or_parachain, try_mortality, DecodeRaw, }, }; use codec::{Compact, Decode, Encode}; @@ -43,7 +43,7 @@ use itp_sgx_crypto::key_repository::AccessKey; use itp_stf_interface::{parentchain_pallet::ParentchainPalletInstancesInterface, ShardVaultQuery}; use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; use itp_types::{ - parentchain::{AccountId, Address, Balance, GenericMortality, ParentchainId, ProxyType}, + parentchain::{AccountId, Address, Balance, ParentchainId, ProxyType}, OpaqueCall, ShardIdentifier, }; use log::*; @@ -189,8 +189,8 @@ pub(crate) fn init_proxied_shard_vault_internal( )); info!("[{:?}] vault funding call: 0x{}", parentchain_id, hex::encode(call.0.clone())); - let xts = enclave_extrinsics_factory - .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; + let mortality = try_mortality(64, &ocall_api); + let xts = enclave_extrinsics_factory.create_extrinsics(&[(call, mortality)], None)?; //this extrinsic must be included in a block before we can move on. otherwise the next will fail ocall_api.send_to_parentchain(xts, &parentchain_id, true)?; @@ -213,8 +213,8 @@ pub(crate) fn init_proxied_shard_vault_internal( )); info!("[{:?}] add proxy call: 0x{}", parentchain_id, hex::encode(call.0.clone())); - let xts = vault_extrinsics_factory - .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; + let mortality = try_mortality(64, &ocall_api); + let xts = vault_extrinsics_factory.create_extrinsics(&[(call, mortality)], None)?; ocall_api.send_to_parentchain(xts, &parentchain_id, false)?; Ok(()) @@ -268,8 +268,8 @@ pub(crate) fn add_shard_vault_proxy( )); info!("proxied add proxy call: 0x{}", hex::encode(call.0.clone())); - let xts = enclave_extrinsics_factory - .create_extrinsics(&[(call, GenericMortality::immortal())], None)?; + let mortality = try_mortality(64, &ocall_api); + let xts = enclave_extrinsics_factory.create_extrinsics(&[(call, mortality)], None)?; ocall_api.send_to_parentchain(xts, &ParentchainId::Integritee, false)?; Ok(()) diff --git a/enclave-runtime/src/utils.rs b/enclave-runtime/src/utils.rs index af8b049bba..d8406eb76a 100644 --- a/enclave-runtime/src/utils.rs +++ b/enclave-runtime/src/utils.rs @@ -27,10 +27,20 @@ use crate::{ GLOBAL_TARGET_A_SOLOCHAIN_HANDLER_COMPONENT, GLOBAL_TARGET_B_PARACHAIN_HANDLER_COMPONENT, GLOBAL_TARGET_B_SOLOCHAIN_HANDLER_COMPONENT, }, + ocall::OcallApi, }; +use alloc::vec::Vec; use codec::{Decode, Input}; +use ita_stf::ParentchainHeader; use itc_parentchain_block_import_dispatcher::BlockImportDispatcher; use itp_component_container::ComponentGetter; +use itp_ocall_api::EnclaveOnChainOCallApi; +use itp_types::{ + parentchain::{GenericMortality, ParentchainId}, + WorkerRequest, WorkerResponse, +}; +use log::*; +use sp_runtime::generic::Era; use std::{result::Result as StdResult, slice, sync::Arc}; /// Helper trait to transform the sgx-ffi pointers to any type that implements @@ -295,3 +305,24 @@ pub(crate) fn get_stf_enclave_signer_from_solo_or_parachain() -> Result GenericMortality { + let response: Option>> = ocall_api + .worker_request( + [WorkerRequest::LatestParentchainHeaderUnverified].into(), + &ParentchainId::Integritee, + ) + .ok() + .iter() + .filter_map(|r| r.first().map(|v| v.clone())) + .next(); + if let Some(WorkerResponse::LatestParentchainHeaderUnverified(header)) = response { + trace!("extrinsic mortality checkpoint: {} {}", header.number, header.hash()); + GenericMortality { + era: Era::mortal(blocks_to_live, header.number.into()), + mortality_checkpoint: Some(header.hash()), + } + } else { + GenericMortality::immortal() + } +} From 7263b951d086c7063fb0791e4de9e923af0260af Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Wed, 6 Nov 2024 11:31:03 +0100 Subject: [PATCH 09/10] all mortal. tests fixed --- app-libs/stf/src/trusted_call.rs | 4 +++- core-primitives/stf-executor/src/lib.rs | 3 ++- .../common/src/test/mocks/confirm_block_import_mock.rs | 7 +++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app-libs/stf/src/trusted_call.rs b/app-libs/stf/src/trusted_call.rs index cd1ea5e2e1..73685ae876 100644 --- a/app-libs/stf/src/trusted_call.rs +++ b/app-libs/stf/src/trusted_call.rs @@ -368,6 +368,8 @@ where shield_funds(who, value)?; // Send proof of execution on chain. + let mortality = + get_mortality(parentchain_id, 32).unwrap_or_else(GenericMortality::immortal); calls.push(ParentchainCall::Integritee { call: OpaqueCall::from_tuple(&( node_metadata_repo @@ -378,7 +380,7 @@ where Vec::::new(), b"shielded some funds!".to_vec(), )), - mortality: GenericMortality::immortal(), + mortality, }); Ok(()) }, diff --git a/core-primitives/stf-executor/src/lib.rs b/core-primitives/stf-executor/src/lib.rs index 622d7def2a..a3e22f4de7 100644 --- a/core-primitives/stf-executor/src/lib.rs +++ b/core-primitives/stf-executor/src/lib.rs @@ -174,6 +174,7 @@ mod tests { use itp_sgx_externalities::SgxExternalities; use itp_test::mock::stf_mock::{GetterMock, TrustedCallSignedMock}; use itp_types::{parentchain::GenericMortality, OpaqueCall}; + use sp_runtime::generic::Era; #[test] fn is_success_works() { @@ -236,7 +237,7 @@ mod tests { let hash = H256::from([int; 32]); let opaque_call: Vec = vec![ParentchainCall::Integritee { call: OpaqueCall(vec![int; 10]), - mortality: GenericMortality::immortal(), + mortality: GenericMortality { era: Era::mortal(0, 0), mortality_checkpoint: None }, }]; let operation = ExecutedOperation::success(hash, TrustedOperationOrHash::Hash(hash), opaque_call); diff --git a/sidechain/consensus/common/src/test/mocks/confirm_block_import_mock.rs b/sidechain/consensus/common/src/test/mocks/confirm_block_import_mock.rs index dc14661609..86cf5f8987 100644 --- a/sidechain/consensus/common/src/test/mocks/confirm_block_import_mock.rs +++ b/sidechain/consensus/common/src/test/mocks/confirm_block_import_mock.rs @@ -14,20 +14,23 @@ limitations under the License. */ - use crate::{error::Result, ConfirmBlockImport}; use itp_types::{parentchain::SidechainBlockConfirmation, ShardIdentifier}; use its_primitives::types::header::SidechainHeader; +use sp_runtime::traits::Block; /// Mock implementation of the `ConfirmBlockImport` trait. pub struct ConfirmBlockImportMock; -impl ConfirmBlockImport for ConfirmBlockImportMock { +impl ConfirmBlockImport + for ConfirmBlockImportMock +{ fn confirm_import( &self, _header: &SidechainHeader, _shard: &ShardIdentifier, _maybe_confirmation: &Option, + _latest_parentchain_header: &::Header, ) -> Result<()> { Ok(()) } From 48c62538b3baa45befaeb4cd466f1a408092da1a Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Wed, 6 Nov 2024 12:22:50 +0100 Subject: [PATCH 10/10] fix teeracle build --- enclave-runtime/src/teeracle/mod.rs | 18 +++++++++--------- enclave-runtime/src/utils.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/enclave-runtime/src/teeracle/mod.rs b/enclave-runtime/src/teeracle/mod.rs index 029c5fffd3..4f7ba17571 100644 --- a/enclave-runtime/src/teeracle/mod.rs +++ b/enclave-runtime/src/teeracle/mod.rs @@ -20,7 +20,7 @@ use crate::{ initialization::global_components::GLOBAL_OCALL_API_COMPONENT, utils::{ get_extrinsic_factory_from_integritee_solo_or_parachain, - get_node_metadata_repository_from_integritee_solo_or_parachain, + get_node_metadata_repository_from_integritee_solo_or_parachain, try_mortality, }, }; use codec::{Decode, Encode}; @@ -38,7 +38,7 @@ use ita_oracle::{ use itp_component_container::ComponentGetter; use itp_extrinsics_factory::CreateExtrinsics; use itp_node_api::metadata::{pallet_teeracle::TeeracleCallIndexes, provider::AccessNodeMetadata}; -use itp_types::OpaqueCall; +use itp_types::{parentchain::GenericMortality, OpaqueCall}; use itp_utils::write_slice_and_whitespace_pad; use log::*; use sgx_types::sgx_status_t; @@ -49,12 +49,12 @@ fn update_weather_data_internal(weather_info: WeatherInfo) -> Result = Vec::new(); - + let mut extrinsic_calls: Vec<(OpaqueCall, GenericMortality)> = Vec::new(); + let mortality = try_mortality(16, &ocall_api); let open_meteo_weather_oracle = create_open_meteo_weather_oracle(ocall_api); match get_longitude(weather_info, open_meteo_weather_oracle) { - Ok(opaque_call) => extrinsic_calls.push(opaque_call), + Ok(opaque_call) => extrinsic_calls.push((opaque_call, mortality)), Err(e) => { error!("[-] Failed to get the newest longitude from OpenMeteo. {:?}", e); }, @@ -211,15 +211,15 @@ fn update_market_data_internal( let extrinsics_factory = get_extrinsic_factory_from_integritee_solo_or_parachain()?; let ocall_api = GLOBAL_OCALL_API_COMPONENT.get()?; - let mut extrinsic_calls: Vec = Vec::new(); - + let mut extrinsic_calls: Vec<(OpaqueCall, GenericMortality)> = Vec::new(); + let mortality = try_mortality(16, &ocall_api); // Get the exchange rate let trading_pair = TradingPair { crypto_currency, fiat_currency }; let coin_gecko_oracle = create_coin_gecko_oracle(ocall_api.clone()); match get_exchange_rate(trading_pair.clone(), coin_gecko_oracle) { - Ok(opaque_call) => extrinsic_calls.push(opaque_call), + Ok(opaque_call) => extrinsic_calls.push((opaque_call, mortality.clone())), Err(e) => { error!("[-] Failed to get the newest exchange rate from CoinGecko. {:?}", e); }, @@ -227,7 +227,7 @@ fn update_market_data_internal( let coin_market_cap_oracle = create_coin_market_cap_oracle(ocall_api); match get_exchange_rate(trading_pair, coin_market_cap_oracle) { - Ok(oc) => extrinsic_calls.push(oc), + Ok(oc) => extrinsic_calls.push((oc, mortality)), Err(e) => { error!("[-] Failed to get the newest exchange rate from CoinMarketCap. {:?}", e); }, diff --git a/enclave-runtime/src/utils.rs b/enclave-runtime/src/utils.rs index d8406eb76a..a195b75847 100644 --- a/enclave-runtime/src/utils.rs +++ b/enclave-runtime/src/utils.rs @@ -314,7 +314,7 @@ pub(crate) fn try_mortality(blocks_to_live: u64, ocall_api: &OcallApi) -> Generi ) .ok() .iter() - .filter_map(|r| r.first().map(|v| v.clone())) + .filter_map(|r| r.first().cloned()) .next(); if let Some(WorkerResponse::LatestParentchainHeaderUnverified(header)) = response { trace!("extrinsic mortality checkpoint: {} {}", header.number, header.hash());