Skip to content

Commit

Permalink
Upload sidevm code via pRPC
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Oct 12, 2022
1 parent 06ed49a commit c7896f9
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 15 deletions.
2 changes: 1 addition & 1 deletion crates/phactory/api/proto
Submodule proto updated 1 files
+13 −0 pruntime_rpc.proto
42 changes: 37 additions & 5 deletions crates/phactory/src/contracts/support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ struct SidevmInfo {
handle: Arc<Mutex<SidevmHandle>>,
}

pub(crate) enum SidevmCode {
Hash(H256),
Code(Vec<u8>),
}

#[derive(Serialize, Deserialize)]
pub struct FatContract {
#[serde(with = "more::scale_bytes")]
Expand Down Expand Up @@ -232,24 +237,50 @@ impl FatContract {
pub(crate) fn start_sidevm(
&mut self,
spawner: &sidevm::service::Spawner,
code: Vec<u8>,
auto_restart: bool,
code: SidevmCode,
check_hash: bool,
) -> Result<()> {
if let Some(info) = &self.sidevm_info {
if let SidevmHandle::Running(_) = &*info.handle.lock().unwrap() {
bail!("Sidevm can only be started once");
}
}
let handle = do_start_sidevm(spawner, &code, self.contract_id.0, self.weight)?;

let code_hash = sp_core::blake2_256(&code).into();
let (code, code_hash) = match code {
SidevmCode::Hash(hash) => (vec![], hash),
SidevmCode::Code(code) => {
let actual_hash = sp_core::blake2_256(&code).into();
if check_hash {
let expected_hash = self
.sidevm_info
.as_ref()
.ok_or(anyhow!("No sidevm info"))?
.code_hash;
if actual_hash != expected_hash {
bail!(
"Code hash mismatch, expected: {expected_hash:?}, actual: {actual_hash:?}"
);
}
}
(code, actual_hash)
}
};

let handle = if code.is_empty() {
Arc::new(Mutex::new(SidevmHandle::Terminated(
ExitReason::WaitingForCode,
)))
} else {
do_start_sidevm(spawner, &code, self.contract_id.0, self.weight)?
};

let start_time = chrono::Utc::now().to_rfc3339();
self.sidevm_info = Some(SidevmInfo {
code,
code_hash,
start_time,
handle,
auto_restart,
auto_restart: true,
});
Ok(())
}
Expand All @@ -272,6 +303,7 @@ impl FatContract {
ExitReason::OcallAborted(OcallAborted::GasExhausted) => false,
ExitReason::OcallAborted(OcallAborted::Stifled) => true,
ExitReason::Restore => true,
ExitReason::WaitingForCode => false,
};
if !need_restart {
return Ok(());
Expand Down
21 changes: 20 additions & 1 deletion crates/phactory/src/prpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,12 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> Phactory<Platform>
.collect();
Ok(pb::GetClusterInfoResponse { clusters })
}

pub fn upload_sidevm_code(&mut self, contract_id: ContractId, code: Vec<u8>) -> RpcResult<()> {
self.system()?
.upload_sidevm_code(contract_id, code)
.map_err(from_display)
}
}

#[derive(Clone)]
Expand Down Expand Up @@ -1388,7 +1394,8 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
&mut self,
request: pb::GetContractInfoRequest,
) -> Result<pb::GetContractInfoResponse, prpc::server::Error> {
self.lock_phactory().get_contract_info(&request.contract_ids)
self.lock_phactory()
.get_contract_info(&request.contract_ids)
}

async fn get_cluster_info(
Expand All @@ -1397,6 +1404,18 @@ impl<Platform: pal::Platform + Serialize + DeserializeOwned> PhactoryApi for Rpc
) -> Result<pb::GetClusterInfoResponse, prpc::server::Error> {
self.lock_phactory().get_cluster_info()
}

async fn upload_sidevm_code(
&mut self,
request: pb::SidevmCode,
) -> Result<(), prpc::server::Error> {
let contract_id: [u8; 32] = request
.contract
.try_into()
.or(Err(from_display("Invalid contract id")))?;
self.lock_phactory()
.upload_sidevm_code(contract_id.into(), request.code)
}
}

fn try_decode_hex(hex_str: &str) -> Result<Vec<u8>, hex::FromHexError> {
Expand Down
26 changes: 18 additions & 8 deletions crates/phactory/src/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod side_tasks;

use crate::{
benchmark,
contracts::{pink::cluster::Cluster, AnyContract, ContractsKeeper, ExecuteEnv},
contracts::{pink::cluster::Cluster, AnyContract, ContractsKeeper, ExecuteEnv, SidevmCode},
pink::{cluster::ClusterKeeper, ContractEventCallback, Pink},
secret_channel::{ecdh_serde, SecretReceiver},
types::{BlockInfo, OpaqueError, OpaqueQuery, OpaqueReply},
Expand Down Expand Up @@ -1626,6 +1626,19 @@ impl<P: pal::Platform> System<P> {
&self.sidevm_spawner,
);
}

pub(crate) fn upload_sidevm_code(
&mut self,
contract_id: ContractId,
code: Vec<u8>,
) -> Result<()> {
let contract = self
.contracts
.get_mut(&contract_id)
.ok_or_else(|| anyhow!("Contract not found"))?;

contract.start_sidevm(&self.sidevm_spawner, SidevmCode::Code(code), true)
}
}

pub fn handle_contract_command_result(
Expand Down Expand Up @@ -1809,14 +1822,11 @@ pub(crate) fn apply_pink_events(
let vmid = sidevm::ShortId(target_contract.as_ref());
let target_contract = get_contract!(&target_contract);
let code_hash = code_hash.into();
let wasm_code = match cluster.get_resource(ResourceType::SidevmCode, &code_hash) {
Some(code) => code,
None => {
error!(target: "sidevm", "[{vmid}] Start sidevm failed: code not found, code_hash={code_hash:?}");
continue;
}
let code = match cluster.get_resource(ResourceType::SidevmCode, &code_hash) {
Some(code) => SidevmCode::Code(code),
None => SidevmCode::Hash(code_hash),
};
if let Err(err) = target_contract.start_sidevm(&spawner, wasm_code, true) {
if let Err(err) = target_contract.start_sidevm(&spawner, code, false) {
error!(target: "sidevm", "[{vmid}] Start sidevm failed: {:?}", err);
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/sidevm/host-runtime/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub enum ExitReason {
OcallAborted(OcallAborted),
/// When a previous running instance restored from a checkpoint.
Restore,
/// The sidevm was deployed without code, so it it waiting to a custom code uploading.
WaitingForCode,
}

pub enum Command {
Expand Down
2 changes: 2 additions & 0 deletions standalone/pruntime/src/api_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ fn default_payload_limit_for_method(method: PhactoryAPIMethod) -> ByteUnit {
HttpFetch => 100.mebibytes(),
GetContractInfo => 100.kibibytes(),
GetClusterInfo => 1.kibibytes(),
UploadSidevmCode => 32.mebibytes(),
}
}

Expand Down Expand Up @@ -227,6 +228,7 @@ async fn prpc_proxy_acl(method: String, data: Data<'_>, limits: &Limits) -> Cust
"PhactoryAPI.GetInfo",
"PhactoryAPI.GetContractInfo",
"PhactoryAPI.GetClusterInfo",
"PhactoryAPI.UploadSidevmCode",
];
if !permitted_method.contains(&&method[..]) {
error!("prpc_acl: access denied");
Expand Down

0 comments on commit c7896f9

Please sign in to comment.