Skip to content

Commit

Permalink
Make enclave extrinsics mortal (#1637)
Browse files Browse the repository at this point in the history
* generic mortality. stay immortal for starters

* make Parentchain block confirmation mortal

* make unshielding extrinsics mortal

* fix tests

* make sidechain block import confirmation mortal

* try to make attestation extrinsics mortal

* mortal attestation works

* mortal shard vault and config init

* all mortal. tests fixed

* fix teeracle build
  • Loading branch information
brenzi authored Nov 6, 2024
1 parent 98accb3 commit 201dc5d
Show file tree
Hide file tree
Showing 28 changed files with 283 additions and 117 deletions.
1 change: 1 addition & 0 deletions app-libs/parentchain-interface/src/event_subscriber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 25 additions & 1 deletion app-libs/stf/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<V: Decode>(
Expand Down Expand Up @@ -193,3 +194,26 @@ pub fn wrap_bytes(data: &[u8]) -> Vec<u8> {

bytes_wrapped
}

pub fn get_mortality(
parentchain_id: ParentchainId,
blocks_to_live: BlockNumber,
) -> Option<GenericMortality> {
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
}
38 changes: 23 additions & 15 deletions app-libs/stf/src/trusted_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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)?
Expand All @@ -339,10 +339,13 @@ where
None::<ProxyType>,
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(proxy_call),
ParentchainId::TargetA => ParentchainCall::TargetA(proxy_call),
ParentchainId::TargetB => ParentchainCall::TargetB(proxy_call),
ParentchainId::Integritee => ParentchainCall::Integritee { call, mortality },
ParentchainId::TargetA => ParentchainCall::TargetA { call, mortality },
ParentchainId::TargetB => ParentchainCall::TargetB { call, mortality },
};
calls.push(parentchain_call);
Ok(())
Expand All @@ -365,15 +368,20 @@ 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::<itp_types::H256>::new(),
b"shielded some funds!".to_vec(),
))));
let mortality =
get_mortality(parentchain_id, 32).unwrap_or_else(GenericMortality::immortal);
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::<itp_types::H256>::new(),
b"shielded some funds!".to_vec(),
)),
mortality,
});
Ok(())
},
TrustedCall::timestamp_set(enclave_account, now, parentchain_id) => {
Expand Down
36 changes: 24 additions & 12 deletions core-primitives/extrinsics-factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -55,7 +58,7 @@ pub mod mock;
pub trait CreateExtrinsics {
fn create_extrinsics(
&self,
calls: &[OpaqueCall],
calls: &[(OpaqueCall, GenericMortality)],
extrinsics_params: Option<ParentchainAdditionalParams>,
) -> Result<Vec<OpaqueExtrinsic>>;
}
Expand Down Expand Up @@ -108,24 +111,28 @@ where
{
fn create_extrinsics(
&self,
calls: &[OpaqueCall],
calls: &[(OpaqueCall, GenericMortality)],
extrinsics_params: Option<ParentchainAdditionalParams>,
) -> Result<Vec<OpaqueExtrinsic>> {
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())
})?;

let extrinsics_buffer: Vec<OpaqueExtrinsic> = 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,
Expand Down Expand Up @@ -172,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());
Expand All @@ -197,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());
Expand Down
4 changes: 2 additions & 2 deletions core-primitives/extrinsics-factory/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -30,7 +30,7 @@ pub struct ExtrinsicsFactoryMock;
impl CreateExtrinsics for ExtrinsicsFactoryMock {
fn create_extrinsics(
&self,
_calls: &[OpaqueCall],
_calls: &[(OpaqueCall, GenericMortality)],
_additional_params: Option<ParentchainAdditionalParams>,
) -> Result<Vec<OpaqueExtrinsic>> {
// Intention was to map an OpaqueCall to some dummy OpaqueExtrinsic,
Expand Down
4 changes: 2 additions & 2 deletions core-primitives/ocall-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ pub trait EnclaveOnChainOCallApi: Clone + Send + Sync {
await_each_inclusion: bool,
) -> SgxResult<()>;

fn worker_request<V: Encode + Decode>(
fn worker_request<H: Header<Hash = H256>, V: Encode + Decode>(
&self,
req: Vec<WorkerRequest>,
parentchain_id: &ParentchainId,
) -> SgxResult<Vec<WorkerResponse<V>>>;
) -> SgxResult<Vec<WorkerResponse<H, V>>>;

fn get_storage_verified<H: Header<Hash = H256>, V: Decode>(
&self,
Expand Down
18 changes: 9 additions & 9 deletions core-primitives/stf-executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
),
}
}
Expand Down
9 changes: 6 additions & 3 deletions core-primitives/stf-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ 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};
use sp_runtime::generic::Era;

#[test]
fn is_success_works() {
Expand Down Expand Up @@ -234,8 +235,10 @@ mod tests {
int: u8,
) -> (ExecutedOperation<TrustedCallSignedMock, GetterMock>, H256) {
let hash = H256::from([int; 32]);
let opaque_call: Vec<ParentchainCall> =
vec![ParentchainCall::Integritee(OpaqueCall(vec![int; 10]))];
let opaque_call: Vec<ParentchainCall> = vec![ParentchainCall::Integritee {
call: OpaqueCall(vec![int; 10]),
mortality: GenericMortality { era: Era::mortal(0, 0), mortality_checkpoint: None },
}];
let operation =
ExecutedOperation::success(hash, TrustedOperationOrHash::Hash(hash), opaque_call);
(operation, hash)
Expand Down
4 changes: 2 additions & 2 deletions core-primitives/test/src/mock/onchain_mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,11 @@ impl EnclaveOnChainOCallApi for OnchainMock {
Ok(())
}

fn worker_request<V: Encode + Decode>(
fn worker_request<Header: HeaderTrait<Hash = H256>, V: Encode + Decode>(
&self,
_req: Vec<WorkerRequest>,
_: &ParentchainId,
) -> SgxResult<Vec<WorkerResponse<V>>> {
) -> SgxResult<Vec<WorkerResponse<Header, V>>> {
Ok(Vec::new())
}

Expand Down
11 changes: 8 additions & 3 deletions core-primitives/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -113,17 +114,21 @@ pub enum TrustedOperationStatus {
#[derive(Encode, Decode, Clone, Debug, PartialEq)]
pub enum WorkerRequest {
ChainStorage(Vec<u8>, Option<BlockHash>), // (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<V: Encode + Decode> {
pub enum WorkerResponse<H: HeaderTrait, V: Encode + Decode> {
ChainStorage(Vec<u8>, Option<V>, Option<Vec<Vec<u8>>>), // (storage_key, storage_value, storage_proof)
LatestParentchainHeaderUnverified(H),
}

impl From<WorkerResponse<Vec<u8>>> for StorageEntry<Vec<u8>> {
fn from(response: WorkerResponse<Vec<u8>>) -> Self {
impl<H: HeaderTrait> From<WorkerResponse<H, Vec<u8>>> for StorageEntry<Vec<u8>> {
fn from(response: WorkerResponse<H, Vec<u8>>) -> Self {
match response {
WorkerResponse::ChainStorage(key, value, proof) => StorageEntry { key, value, proof },
WorkerResponse::LatestParentchainHeaderUnverified(_) => StorageEntry::default(),
}
}
}
Expand Down
Loading

0 comments on commit 201dc5d

Please sign in to comment.