Skip to content

Commit

Permalink
Add pRPC AllowHandoverTo
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Dec 27, 2023
1 parent e11e27a commit 41591a2
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 58 deletions.
2 changes: 1 addition & 1 deletion crates/phactory/api/proto
Submodule proto updated 1 files
+21 −1 pruntime_rpc.proto
69 changes: 36 additions & 33 deletions crates/phactory/api/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ impl From<CodecError> for SignatureVerifyError {
}
}

#[derive(Default, Clone, Encode, Decode, Debug)]
pub enum MessageType {
Certificate { ttl: u32 },
#[default]
ContractQuery,
}

Expand Down Expand Up @@ -216,38 +218,39 @@ impl CertificateBody {
sig_type: SignatureType,
signature: &[u8],
) -> Result<AccountId32, SignatureVerifyError> {
let signer = match sig_type {
SignatureType::Ed25519 => {
recover::<sp_core::ed25519::Pair>(&self.pubkey, signature, msg)?.into()
}
SignatureType::Sr25519 => {
recover::<sp_core::sr25519::Pair>(&self.pubkey, signature, msg)?.into()
}
SignatureType::Ecdsa => account_id_from_evm_pubkey(recover::<sp_core::ecdsa::Pair>(
&self.pubkey,
signature,
msg,
)?),
SignatureType::Ed25519WrapBytes => {
let wrapped = wrap_bytes(msg);
recover::<sp_core::ed25519::Pair>(&self.pubkey, signature, &wrapped)?.into()
}
SignatureType::Sr25519WrapBytes => {
let wrapped = wrap_bytes(msg);
recover::<sp_core::sr25519::Pair>(&self.pubkey, signature, &wrapped)?.into()
}
SignatureType::EcdsaWrapBytes => {
let wrapped = wrap_bytes(msg);
account_id_from_evm_pubkey(recover::<sp_core::ecdsa::Pair>(
&self.pubkey,
signature,
&wrapped,
)?)
}
SignatureType::Eip712 => {
account_id_from_evm_pubkey(eip712::recover(&self.pubkey, signature, msg, msg_type)?)
}
};
Ok(signer)
recover_signer_account(&self.pubkey, msg, msg_type, sig_type, signature)
}
}

pub fn recover_signer_account(
pubkey: &[u8],
msg: &[u8],
msg_type: MessageType,
sig_type: SignatureType,
signature: &[u8],
) -> Result<AccountId32, SignatureVerifyError> {
use account_id_from_evm_pubkey as evm_account;
let signer = match sig_type {
SignatureType::Ed25519 => recover::<sp_core::ed25519::Pair>(pubkey, signature, msg)?.into(),
SignatureType::Sr25519 => recover::<sp_core::sr25519::Pair>(pubkey, signature, msg)?.into(),
SignatureType::Ecdsa => {
evm_account(recover::<sp_core::ecdsa::Pair>(pubkey, signature, msg)?)
}
SignatureType::Ed25519WrapBytes => {
let wrapped = wrap_bytes(msg);
recover::<sp_core::ed25519::Pair>(pubkey, signature, &wrapped)?.into()
}
SignatureType::Sr25519WrapBytes => {
let wrapped = wrap_bytes(msg);
recover::<sp_core::sr25519::Pair>(pubkey, signature, &wrapped)?.into()
}
SignatureType::EcdsaWrapBytes => {
let wrapped = wrap_bytes(msg);
evm_account(recover::<sp_core::ecdsa::Pair>(
pubkey, signature, &wrapped,
)?)
}
SignatureType::Eip712 => evm_account(eip712::recover(pubkey, signature, msg, msg_type)?),
};
Ok(signer)
}
6 changes: 6 additions & 0 deletions crates/phactory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ pub struct Phactory<Platform> {
#[serde(skip)]
#[serde(default = "sidevm_helper::create_sidevm_service_default")]
sidevm_spawner: sidevm::service::Spawner,

/// The pRuntime measurement that allowed by the Council.
#[codec(skip)]
#[serde(skip)]
allow_handover_to: Option<Vec<u8>>,
}

mod sidevm_helper {
Expand Down Expand Up @@ -409,6 +414,7 @@ impl<Platform: pal::Platform> Phactory<Platform> {
args.cores as _,
create_sidevm_outgoing_channel(weak_self),
),
allow_handover_to: None,
};
me.init(args);
me
Expand Down
87 changes: 64 additions & 23 deletions crates/phactory/src/prpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1592,24 +1592,7 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
}
// 5. verify pruntime launch date, never handover to old pruntime
if !dev_mode && in_sgx {
let my_la_report = {
// target_info and reportdata not important, we just need the report metadata
let target_info =
sgx_api_lite::target_info().expect("should not fail in SGX; qed.");
sgx_api_lite::report(&target_info, &[0; 64])
.map_err(|_| from_display("Cannot read server pRuntime info"))?
};
let my_runtime_hash = {
let ias_fields = IasFields {
mr_enclave: my_la_report.body.mr_enclave.m,
mr_signer: my_la_report.body.mr_signer.m,
isv_prod_id: my_la_report.body.isv_prod_id.to_ne_bytes(),
isv_svn: my_la_report.body.isv_svn.to_ne_bytes(),
report_data: [0; 64],
confidence_level: 0,
};
ias_fields.extend_mrenclave()
};
let my_runtime_hash = my_measurement()?;
let runtime_state = phactory.runtime_state()?;
let my_runtime_timestamp = runtime_state
.chain_storage
Expand All @@ -1633,13 +1616,15 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
collateral: _,
} => todo!(),
};
let req_runtime_timestamp = runtime_state
if let Some(req_runtime_timestamp) = runtime_state
.chain_storage
.get_pruntime_added_at(&runtime_hash)
.ok_or_else(|| from_display("Client pRuntime not allowed on chain"))?;

if my_runtime_timestamp >= req_runtime_timestamp {
return Err(from_display("No handover for old pRuntime"));
{
if my_runtime_timestamp >= req_runtime_timestamp {
return Err(from_display("No handover for old pRuntime"));
}
} else if phactory.allow_handover_to != Some(runtime_hash) {
return Err(from_display("Client pRuntime not allowed on chain"));
}
} else {
info!("Skip pRuntime timestamp check in dev mode");
Expand Down Expand Up @@ -2046,4 +2031,60 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
cluster.on_idle(block_number);
Ok(())
}

async fn allow_handover_to(
&mut self,
request: pb::AllowHandoverToRequest,
) -> Result<(), prpc::server::Error> {
let mut phactory = self.lock_phactory(false, true)?;
let runtime_state = phactory.runtime_state()?;
let council_members = runtime_state.chain_storage.council_members();
let genesis_hash = hex::encode(runtime_state.genesis_block_hash);
let mr_to = hex::encode(&request.measurement);
let mr_from = hex::encode(my_measurement()?);
let signed_message = format!("Allow pRuntime to handover from 0x{mr_from} to 0x{mr_to} on chain of genesis 0x{genesis_hash}").into_bytes();
for sig in &request.signatures {
let sig_type = pb::SignatureType::from_i32(sig.signature_type)
.ok_or_else(|| from_display("Invalid signature type"))?;
let signer = crypto::recover_signer_account(
&sig.pubkey,
&signed_message,
Default::default(),
sig_type,
&sig.signature,
)
.map_err(|_| from_display("Invalid signature"))?;
if !council_members.contains(&signer) {
return Err(from_display("Not a council member"));
}
}
let percent = request.signatures.len() * 100 / council_members.len();
if percent < 50 {
return Err(from_display("Not enough signatures"));
}
phactory.allow_handover_to = Some(request.measurement);
Ok(())
}
}

fn my_measurement() -> Result<Vec<u8>, RpcError> {
let my_la_report = {
// target_info and reportdata not important, we just need the report metadata
let target_info =
sgx_api_lite::target_info().or(Err(from_display("Failed to get SGX info")))?;
sgx_api_lite::report(&target_info, &[0; 64])
.or(Err(from_display("Cannot read server pRuntime info")))?
};
let mrenclave = {
let ias_fields = IasFields {
mr_enclave: my_la_report.body.mr_enclave.m,
mr_signer: my_la_report.body.mr_signer.m,
isv_prod_id: my_la_report.body.isv_prod_id.to_ne_bytes(),
isv_svn: my_la_report.body.isv_svn.to_ne_bytes(),
report_data: [0; 64],
confidence_level: 0,
};
ias_fields.extend_mrenclave()
};
Ok(mrenclave)
}
6 changes: 5 additions & 1 deletion crates/phactory/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl BlockValidator for LightValidation<chain::Runtime> {

mod storage_ext {
use crate::chain;
use chain::{pallet_computation, pallet_mq, pallet_phat, pallet_registry};
use chain::{pallet_computation, pallet_mq, pallet_phat, pallet_registry, AccountId};
use phala_mq::{ContractClusterId, Message, MessageOrigin};
use phala_trie_storage::TrieStorage;
use phala_types::messaging::TokenomicParameters;
Expand Down Expand Up @@ -178,5 +178,9 @@ mod storage_ext {
) -> Option<ContractClusterId> {
self.execute_with(|| pallet_phat::ClusterByWorkers::<chain::Runtime>::get(worker))
}

pub(crate) fn council_members(&self) -> Vec<AccountId> {
self.execute_with(chain::Council::members)
}
}
}
2 changes: 2 additions & 0 deletions standalone/pruntime/src/api_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ fn rpc_type(method: &str) -> RpcType {
SaveClusterState => Public,
LoadClusterState => Private,
TryUpgradePinkRuntime => Private,
AllowHandoverTo => Private,
},
}
}
Expand Down Expand Up @@ -254,6 +255,7 @@ fn default_payload_limit_for_method(method: PhactoryAPIMethod) -> ByteUnit {
SaveClusterState => 1.kibibytes(),
LoadClusterState => 1.kibibytes(),
TryUpgradePinkRuntime => 1.kibibytes(),
AllowHandoverTo => 64.kibibytes(),
}
}

Expand Down

0 comments on commit 41591a2

Please sign in to comment.