This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/develop by this push:
     new 2fa546e  [services] Unify Fusion Data and InputFile/OutputFile (#230)
2fa546e is described below

commit 2fa546e524b994bdf8640f08a5e732e87b5a69b5
Author: TX <[email protected]>
AuthorDate: Thu Feb 27 11:55:22 2020 -0800

    [services] Unify Fusion Data and InputFile/OutputFile (#230)
---
 services/frontend/enclave/src/service.rs           |  30 +-
 services/management/enclave/src/file.rs            | 108 -----
 services/management/enclave/src/function.rs        |  79 ----
 services/management/enclave/src/fusion_data.rs     |  70 ---
 services/management/enclave/src/lib.rs             |   4 +-
 services/management/enclave/src/service.rs         | 495 ++++++++++-----------
 services/management/enclave/src/task.rs            | 461 ++++++-------------
 services/proto/src/proto/teaclave_common.proto     |   9 +
 .../src/proto/teaclave_frontend_service.proto      |  52 ++-
 .../src/proto/teaclave_management_service.proto    |   4 +-
 services/proto/src/teaclave_common.rs              |  29 +-
 services/proto/src/teaclave_frontend_service.rs    | 359 ++++++++-------
 services/proto/src/teaclave_management_service.rs  |  12 +-
 .../enclave/src/teaclave_frontend_service.rs       |  90 +++-
 .../enclave/src/teaclave_management_service.rs     | 236 ++++++----
 types/src/file.rs                                  | 109 ++---
 types/src/function.rs                              |  58 +++
 types/src/lib.rs                                   |   8 +
 types/src/staged_task.rs                           |  84 ++++
 types/src/storage.rs                               |  37 ++
 types/src/task.rs                                  |  48 ++
 types/src/worker.rs                                |   6 +-
 22 files changed, 1220 insertions(+), 1168 deletions(-)

diff --git a/services/frontend/enclave/src/service.rs 
b/services/frontend/enclave/src/service.rs
index f4e50c3..dea5f81 100644
--- a/services/frontend/enclave/src/service.rs
+++ b/services/frontend/enclave/src/service.rs
@@ -10,11 +10,12 @@ use teaclave_proto::teaclave_common::UserCredential;
 use teaclave_proto::teaclave_frontend_service::{
     ApproveTaskRequest, ApproveTaskResponse, AssignDataRequest, 
AssignDataResponse,
     CreateTaskRequest, CreateTaskResponse, GetFunctionRequest, 
GetFunctionResponse,
-    GetFusionDataRequest, GetFusionDataResponse, GetOutputFileRequest, 
GetOutputFileResponse,
+    GetInputFileRequest, GetInputFileResponse, GetOutputFileRequest, 
GetOutputFileResponse,
     GetTaskRequest, GetTaskResponse, InvokeTaskRequest, InvokeTaskResponse,
-    RegisterFunctionRequest, RegisterFunctionResponse, 
RegisterInputFileRequest,
-    RegisterInputFileResponse, RegisterOutputFileRequest, 
RegisterOutputFileResponse,
-    TeaclaveFrontend,
+    RegisterFunctionRequest, RegisterFunctionResponse, 
RegisterFusionOutputRequest,
+    RegisterFusionOutputResponse, RegisterInputFileRequest, 
RegisterInputFileResponse,
+    RegisterInputFromOutputRequest, RegisterInputFromOutputResponse, 
RegisterOutputFileRequest,
+    RegisterOutputFileResponse, TeaclaveFrontend,
 };
 use teaclave_proto::teaclave_management_service::TeaclaveManagementClient;
 use teaclave_rpc::endpoint::Endpoint;
@@ -124,6 +125,19 @@ impl TeaclaveFrontend for TeaclaveFrontendService {
         authentication_and_forward_to_management!(self, request, 
register_output_file)
     }
 
+    fn register_fusion_output(
+        &self,
+        request: Request<RegisterFusionOutputRequest>,
+    ) -> TeaclaveServiceResponseResult<RegisterFusionOutputResponse> {
+        authentication_and_forward_to_management!(self, request, 
register_fusion_output)
+    }
+
+    fn register_input_from_output(
+        &self,
+        request: Request<RegisterInputFromOutputRequest>,
+    ) -> TeaclaveServiceResponseResult<RegisterInputFromOutputResponse> {
+        authentication_and_forward_to_management!(self, request, 
register_input_from_output)
+    }
     fn get_output_file(
         &self,
         request: Request<GetOutputFileRequest>,
@@ -131,11 +145,11 @@ impl TeaclaveFrontend for TeaclaveFrontendService {
         authentication_and_forward_to_management!(self, request, 
get_output_file)
     }
 
-    fn get_fusion_data(
+    fn get_input_file(
         &self,
-        request: Request<GetFusionDataRequest>,
-    ) -> TeaclaveServiceResponseResult<GetFusionDataResponse> {
-        authentication_and_forward_to_management!(self, request, 
get_fusion_data)
+        request: Request<GetInputFileRequest>,
+    ) -> TeaclaveServiceResponseResult<GetInputFileResponse> {
+        authentication_and_forward_to_management!(self, request, 
get_input_file)
     }
 
     fn register_function(
diff --git a/services/management/enclave/src/file.rs 
b/services/management/enclave/src/file.rs
deleted file mode 100644
index 6e398ef..0000000
--- a/services/management/enclave/src/file.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use anyhow::{anyhow, Result};
-use serde::{Deserialize, Serialize};
-use serde_json;
-use std::prelude::v1::*;
-use teaclave_types::TeaclaveFileCryptoInfo;
-use url::Url;
-use uuid::Uuid;
-
-const INPUT_FILE_PREFIX: &str = "input-file-";
-const OUTPUT_FILE_PREFIX: &str = "output-file-";
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct InputFile {
-    pub(crate) url: Url,
-    pub(crate) hash: String,
-    pub(crate) crypto_info: TeaclaveFileCryptoInfo,
-    pub(crate) owner: String,
-    pub(crate) data_id: String,
-}
-
-impl InputFile {
-    pub(crate) fn new(
-        url: Url,
-        hash: String,
-        crypto_info: TeaclaveFileCryptoInfo,
-        owner: String,
-    ) -> InputFile {
-        let data_id = format!("{}{}", INPUT_FILE_PREFIX, 
Uuid::new_v4().to_string());
-        InputFile {
-            url,
-            hash,
-            crypto_info,
-            owner,
-            data_id,
-        }
-    }
-
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        let ret: InputFile =
-            serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))?;
-        Ok(ret)
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
-    }
-
-    pub(crate) fn get_key_vec(&self) -> Vec<u8> {
-        self.data_id.as_bytes().to_vec()
-    }
-
-    pub(crate) fn is_input_file_id(id: &str) -> bool {
-        id.starts_with(INPUT_FILE_PREFIX)
-    }
-}
-
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct OutputFile {
-    pub(crate) url: Url,
-    pub(crate) hash: Option<String>,
-    pub(crate) crypto_info: TeaclaveFileCryptoInfo,
-    pub(crate) owner: String,
-    pub(crate) data_id: String,
-}
-
-impl OutputFile {
-    pub(crate) fn new(url: Url, crypto_info: TeaclaveFileCryptoInfo, owner: 
String) -> OutputFile {
-        let data_id = format!("{}{}", OUTPUT_FILE_PREFIX, 
Uuid::new_v4().to_string());
-        OutputFile {
-            url,
-            hash: None,
-            crypto_info,
-            owner,
-            data_id,
-        }
-    }
-
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
-    }
-
-    pub(crate) fn get_key_vec(&self) -> Vec<u8> {
-        self.data_id.as_bytes().to_vec()
-    }
-
-    pub(crate) fn is_output_file_id(id: &str) -> bool {
-        id.starts_with(OUTPUT_FILE_PREFIX)
-    }
-}
diff --git a/services/management/enclave/src/function.rs 
b/services/management/enclave/src/function.rs
deleted file mode 100644
index 4c7834e..0000000
--- a/services/management/enclave/src/function.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use anyhow::{anyhow, Result};
-use serde::{Deserialize, Serialize};
-use serde_json;
-use std::prelude::v1::*;
-use teaclave_proto::teaclave_frontend_service::{
-    FunctionInput, FunctionOutput, RegisterFunctionRequest,
-};
-
-use uuid::Uuid;
-const SCRIPT_PREFIX: &str = "function-";
-const NATIVE_PREFIX: &str = "native-";
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct Function {
-    pub(crate) function_id: String,
-    pub(crate) name: String,
-    pub(crate) description: String,
-    pub(crate) payload: Vec<u8>,
-    pub(crate) is_public: bool,
-    pub(crate) arg_list: Vec<String>,
-    pub(crate) input_list: Vec<FunctionInput>,
-    pub(crate) output_list: Vec<FunctionOutput>,
-    pub(crate) owner: String,
-    pub(crate) is_native: bool,
-}
-
-impl Function {
-    pub(crate) fn new_from_register_request(
-        request: RegisterFunctionRequest,
-        owner: String,
-    ) -> Function {
-        let function_id = format!("{}{}", SCRIPT_PREFIX, 
Uuid::new_v4().to_string());
-        Function {
-            function_id,
-            name: request.name,
-            description: request.description,
-            payload: request.payload,
-            is_public: request.is_public,
-            arg_list: request.arg_list,
-            input_list: request.input_list,
-            output_list: request.output_list,
-            owner,
-            is_native: false,
-        }
-    }
-
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        let ret: Function =
-            serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))?;
-        Ok(ret)
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
-    }
-
-    pub(crate) fn get_key_vec(&self) -> Vec<u8> {
-        self.function_id.as_bytes().to_vec()
-    }
-
-    pub(crate) fn is_function_id(id: &str) -> bool {
-        id.starts_with(NATIVE_PREFIX) || id.starts_with(SCRIPT_PREFIX)
-    }
-}
diff --git a/services/management/enclave/src/fusion_data.rs 
b/services/management/enclave/src/fusion_data.rs
deleted file mode 100644
index ad1216f..0000000
--- a/services/management/enclave/src/fusion_data.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-use anyhow::{anyhow, Result};
-use serde::{Deserialize, Serialize};
-use serde_json;
-use std::prelude::v1::*;
-use teaclave_types::TeaclaveFileCryptoInfo;
-use url::Url;
-use uuid::Uuid;
-
-const FUSION_DATA_PREFIX: &str = "fusion-data-";
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct FusionData {
-    pub(crate) url: Url,
-    pub(crate) hash: Option<String>,
-    pub(crate) crypto_info: TeaclaveFileCryptoInfo,
-    pub(crate) data_owner_id_list: Vec<String>,
-    pub(crate) data_id: String,
-}
-
-fn gen_url_for_fusion_data(data_id: &str) -> Result<Url> {
-    let url = format!("fusion://path/{}?token=fusion_token", data_id);
-    info!("{}", url);
-    Url::parse(&url).map_err(|_| anyhow!("invalid url"))
-}
-
-impl FusionData {
-    pub fn new(data_owner_id_list: Vec<String>) -> Result<Self> {
-        let data_id = format!("{}{}", FUSION_DATA_PREFIX, 
Uuid::new_v4().to_string());
-        let url = gen_url_for_fusion_data(&data_id)?;
-        let crypto_info = TeaclaveFileCryptoInfo::default();
-        Ok(FusionData {
-            url,
-            hash: None,
-            crypto_info,
-            data_owner_id_list,
-            data_id,
-        })
-    }
-
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
-    }
-
-    pub(crate) fn get_key_vec(&self) -> Vec<u8> {
-        self.data_id.as_bytes().to_vec()
-    }
-
-    pub(crate) fn is_fusion_data_id(id: &str) -> bool {
-        id.starts_with(FUSION_DATA_PREFIX)
-    }
-}
diff --git a/services/management/enclave/src/lib.rs 
b/services/management/enclave/src/lib.rs
index 2d9fbcc..5a8d8cd 100644
--- a/services/management/enclave/src/lib.rs
+++ b/services/management/enclave/src/lib.rs
@@ -41,8 +41,7 @@ use teaclave_rpc::server::SgxTrustedTlsServer;
 use teaclave_service_enclave_utils::ServiceEnclave;
 use teaclave_types::{EnclaveInfo, TeeServiceError, TeeServiceResult};
 
-mod function;
-mod fusion_data;
+//mod fusion_data;
 mod service;
 mod task;
 
@@ -161,7 +160,6 @@ pub mod tests {
         run_tests!(
             service::tests::handle_input_file,
             service::tests::handle_output_file,
-            service::tests::handle_fusion_data,
             service::tests::handle_function,
             service::tests::handle_task,
             service::tests::handle_staged_task,
diff --git a/services/management/enclave/src/service.rs 
b/services/management/enclave/src/service.rs
index 0d8a9b7..074a1b1 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -1,17 +1,21 @@
-use crate::function::Function;
-use crate::fusion_data::FusionData;
-use crate::task::{InputData, OutputData, StagedTask, Task};
+use crate::task::{
+    assign_input_to_task, assign_output_to_task, 
try_update_task_to_approved_status,
+    try_update_task_to_ready_status,
+};
 use anyhow::{anyhow, Result};
 use std::collections::HashMap;
+use std::collections::HashSet;
 use std::prelude::v1::*;
 use std::sync::{Arc, SgxMutex as Mutex};
 use teaclave_proto::teaclave_frontend_service::{
     ApproveTaskRequest, ApproveTaskResponse, AssignDataRequest, 
AssignDataResponse,
     CreateTaskRequest, CreateTaskResponse, GetFunctionRequest, 
GetFunctionResponse,
-    GetFusionDataRequest, GetFusionDataResponse, GetOutputFileRequest, 
GetOutputFileResponse,
+    GetInputFileRequest, GetInputFileResponse, GetOutputFileRequest, 
GetOutputFileResponse,
     GetTaskRequest, GetTaskResponse, InvokeTaskRequest, InvokeTaskResponse,
-    RegisterFunctionRequest, RegisterFunctionResponse, 
RegisterInputFileRequest,
-    RegisterInputFileResponse, RegisterOutputFileRequest, 
RegisterOutputFileResponse, TaskStatus,
+    RegisterFunctionRequest, RegisterFunctionResponse, 
RegisterFusionOutputRequest,
+    RegisterFusionOutputResponse, RegisterInputFileRequest, 
RegisterInputFileResponse,
+    RegisterInputFromOutputRequest, RegisterInputFromOutputResponse, 
RegisterOutputFileRequest,
+    RegisterOutputFileResponse,
 };
 use teaclave_proto::teaclave_management_service::TeaclaveManagement;
 use teaclave_proto::teaclave_storage_service::{
@@ -20,13 +24,13 @@ use teaclave_proto::teaclave_storage_service::{
 use teaclave_rpc::endpoint::Endpoint;
 use teaclave_rpc::Request;
 use teaclave_service_enclave_utils::teaclave_service;
+use teaclave_types::{Function, FunctionInput, FunctionOutput};
+use teaclave_types::{InputData, OutputData, StagedTask, Task, TaskStatus};
 use teaclave_types::{Storable, TeaclaveInputFile, TeaclaveOutputFile};
 use teaclave_types::{TeaclaveServiceResponseError, 
TeaclaveServiceResponseResult};
 use thiserror::Error;
 
 #[cfg(test_mode)]
-use core::str::FromStr;
-#[cfg(test_mode)]
 use uuid::Uuid;
 
 #[derive(Error, Debug)]
@@ -72,8 +76,10 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .to_string();
 
         let request = request.message;
+        let mut owner_list = HashSet::new();
+        owner_list.insert(user_id);
         let input_file =
-            TeaclaveInputFile::new(request.url, request.hash, 
request.crypto_info, user_id);
+            TeaclaveInputFile::new(request.url, request.hash, 
request.crypto_info, owner_list);
         self.write_to_db(&input_file)
             .map_err(|_| TeaclaveManagementError::StorageError)?;
         let response = RegisterInputFileResponse {
@@ -94,7 +100,9 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .to_string();
 
         let request = request.message;
-        let output_file = TeaclaveOutputFile::new(request.url, 
request.crypto_info, user_id);
+        let mut owner_list = HashSet::new();
+        owner_list.insert(user_id);
+        let output_file = TeaclaveOutputFile::new(request.url, 
request.crypto_info, owner_list);
         self.write_to_db(&output_file)
             .map_err(|_| TeaclaveManagementError::StorageError)?;
         let response = RegisterOutputFileResponse {
@@ -103,7 +111,65 @@ impl TeaclaveManagement for TeaclaveManagementService {
         Ok(response)
     }
 
-    // access control: output_file.owner == user_id
+    // access control: user_id in owner_list
+    fn register_fusion_output(
+        &self,
+        request: Request<RegisterFusionOutputRequest>,
+    ) -> TeaclaveServiceResponseResult<RegisterFusionOutputResponse> {
+        let user_id = request
+            .metadata
+            .get("id")
+            .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
+            .to_string();
+
+        let owner_list = request.message.owner_list;
+        if !owner_list.contains(&user_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+
+        let output_file = TeaclaveOutputFile::new_fusion_data(owner_list)
+            .map_err(|_| TeaclaveManagementError::DataError)?;
+        self.write_to_db(&output_file)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
+        let response = RegisterFusionOutputResponse {
+            data_id: output_file.external_id(),
+        };
+        Ok(response)
+    }
+
+    // access control:
+    // 1) user_id in output.owner
+    // 2) hash != none
+    fn register_input_from_output(
+        &self,
+        request: Request<RegisterInputFromOutputRequest>,
+    ) -> TeaclaveServiceResponseResult<RegisterInputFromOutputResponse> {
+        let user_id = request
+            .metadata
+            .get("id")
+            .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
+            .to_string();
+        if !TeaclaveOutputFile::match_prefix(&request.message.data_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let output: TeaclaveOutputFile = self
+            .read_from_db(request.message.data_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+        if !output.owner.contains(&user_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+
+        let input = TeaclaveInputFile::from_output(output)
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+        self.write_to_db(&input)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
+        let response = RegisterInputFromOutputResponse {
+            data_id: input.external_id(),
+        };
+        Ok(response)
+    }
+
+    // access control: output_file.owner contains user_id
     fn get_output_file(
         &self,
         request: Request<GetOutputFileRequest>,
@@ -122,32 +188,41 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .read_from_db(&request.message.data_id.as_bytes())
             .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
 
-        if output_file.owner != user_id {
+        if !output_file.owner.contains(&user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
         let response = GetOutputFileResponse {
+            owner: output_file.owner,
             hash: output_file.hash.unwrap_or_else(|| "".to_string()),
         };
         Ok(response)
     }
 
-    // access control: fusion_data.data_owner_id_list.contains(user_id)
-    fn get_fusion_data(
+    // access control: input_file.owner contains user_id
+    fn get_input_file(
         &self,
-        request: Request<GetFusionDataRequest>,
-    ) -> TeaclaveServiceResponseResult<GetFusionDataResponse> {
+        request: Request<GetInputFileRequest>,
+    ) -> TeaclaveServiceResponseResult<GetInputFileResponse> {
         let user_id = request
             .metadata
             .get("id")
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
-        let fusion_data = 
self.get_fusion_data_from_storage(&request.message.data_id)?;
-        if !fusion_data.data_owner_id_list.contains(&user_id) {
+
+        if !TeaclaveInputFile::match_prefix(&request.message.data_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+
+        let input_file: TeaclaveInputFile = self
+            .read_from_db(&request.message.data_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+
+        if !input_file.owner.contains(&user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
-        let response = GetFusionDataResponse {
-            hash: fusion_data.hash.unwrap_or_else(|| "".to_string()),
-            data_owner_id_list: fusion_data.data_owner_id_list,
+        let response = GetInputFileResponse {
+            owner: input_file.owner,
+            hash: input_file.hash,
         };
         Ok(response)
     }
@@ -164,16 +239,24 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .to_string();
 
         let request = request.message;
-        let function = Function::new_from_register_request(request, user_id);
-        let key = function.get_key_vec();
-        let value = function
-            .to_vec()
-            .map_err(|_| TeaclaveManagementError::DataError)?;
+        let function_id = Uuid::new_v4();
+        let function = Function {
+            function_id,
+            name: request.name,
+            description: request.description,
+            payload: request.payload,
+            is_public: request.is_public,
+            arg_list: request.arg_list,
+            input_list: request.input_list,
+            output_list: request.output_list,
+            owner: user_id,
+            is_native: false,
+        };
 
-        self.write_to_storage(&key, &value)
+        self.write_to_db(&function)
             .map_err(|_| TeaclaveManagementError::StorageError)?;
         let response = RegisterFunctionResponse {
-            function_id: function.function_id,
+            function_id: function.external_id(),
         };
         Ok(response)
     }
@@ -188,7 +271,13 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .get("id")
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
-        let function = 
self.get_function_from_storage(&request.message.function_id)?;
+        if !Function::match_prefix(&request.message.function_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+
+        let function: Function = self
+            .read_from_db(request.message.function_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
         if !(function.is_public || function.owner == user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
@@ -220,8 +309,10 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
         let request = request.message;
-        let function = self.get_function_from_storage(&request.function_id)?;
-        let mut task = Task::new(
+        let function: Function = self
+            .read_from_db(request.function_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+        let task = crate::task::create_task(
             function,
             user_id,
             request.arg_list,
@@ -229,19 +320,10 @@ impl TeaclaveManagement for TeaclaveManagementService {
             request.output_data_owner_list,
         )
         .map_err(|_| TeaclaveManagementError::BadTask)?;
-        // register fusion data
-        for (output_name, data_owner_id_list) in 
task.output_data_owner_list.iter() {
-            if data_owner_id_list.user_id_list.len() > 1 {
-                let user_id_list: Vec<String> =
-                    data_owner_id_list.user_id_list.iter().cloned().collect();
-                let fusion_data = self.alloc_fusion_data(user_id_list)?;
-                task.output_map
-                    .insert(output_name.to_string(), fusion_data.data_id);
-            }
-        }
-        self.insert_or_update_task_to_storage(&task)?;
+        self.write_to_db(&task)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
         Ok(CreateTaskResponse {
-            task_id: task.task_id,
+            task_id: task.external_id(),
         })
     }
 
@@ -255,12 +337,18 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .get("id")
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
-        let task: Task = self.get_task_from_storage(&request.message.task_id)?;
+
+        if !Task::match_prefix(&request.message.task_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let task: Task = self
+            .read_from_db(request.message.task_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
         if !task.participants.contains(&user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
         let response = GetTaskResponse {
-            task_id: task.task_id,
+            task_id: task.external_id(),
             creator: task.creator,
             function_id: task.function_id,
             function_owner: task.function_owner,
@@ -280,14 +368,12 @@ impl TeaclaveManagement for TeaclaveManagementService {
     // 1) task.participants.contains(user_id)
     // 2) task.status == Created
     // 3) user can use the data:
-    //    * input file: user_id == input_file.owner
-    //    * output file: user_id == output_file.owner && 
output_file.hash.is_none()
-    //    * fusion_data: fusion_data.owner_id_list.contains(user_id)
+    //    * input file: user_id == input_file.owner contains user_id
+    //    * output file: output_file.owner contains user_id && 
output_file.hash.is_none()
     // 4) the data can be assgined to the task:
     //    * input_data_owner_list or output_data_owner_list contains the data 
name
-    //    * input file: DataOwnerList has one user and user == user_id
-    //    * output file: DataOwnerList has one user and user == user_id
-    //    * fusion data: not output and DataOwnerList == 
fusion_data.owner_id_list
+    //    * input file: DataOwnerList match input_file.owner
+    //    * output file: DataOwnerList match output_file.owner
     fn assign_data(
         &self,
         request: Request<AssignDataRequest>,
@@ -298,7 +384,13 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
         let request = request.message;
-        let mut task: Task = self.get_task_from_storage(&request.task_id)?;
+        if !Task::match_prefix(&request.task_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let mut task: Task = self
+            .read_from_db(request.task_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+
         if !task.participants.contains(&user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
@@ -311,11 +403,7 @@ impl TeaclaveManagement for TeaclaveManagementService {
                 let input_file: TeaclaveInputFile = self
                     .read_from_db(data_id.as_bytes())
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
-                task.assign_input_file(data_name, &input_file, &user_id)
-                    .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
-            } else if FusionData::is_fusion_data_id(data_id) {
-                let fusion_data = self.get_fusion_data_from_storage(data_id)?;
-                task.assign_fusion_data(data_name, &fusion_data, &user_id)
+                assign_input_to_task(&mut task, data_name, &input_file, 
&user_id)
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
             } else {
                 return Err(TeaclaveManagementError::PermissionDenied.into());
@@ -326,14 +414,15 @@ impl TeaclaveManagement for TeaclaveManagementService {
                 let output_file: TeaclaveOutputFile = self
                     .read_from_db(data_id.as_bytes())
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
-                task.assign_output_file(data_name, &output_file, &user_id)
+                assign_output_to_task(&mut task, data_name, &output_file, 
&user_id)
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
             } else {
                 return Err(TeaclaveManagementError::PermissionDenied.into());
             }
         }
-        task.try_update_to_ready_status();
-        self.insert_or_update_task_to_storage(&task)?;
+        try_update_task_to_ready_status(&mut task);
+        self.write_to_db(&task)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
         Ok(AssignDataResponse)
     }
 
@@ -350,7 +439,13 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
         let request = request.message;
-        let mut task: Task = self.get_task_from_storage(&request.task_id)?;
+        if !Task::match_prefix(&request.task_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let mut task: Task = self
+            .read_from_db(request.task_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+
         if !task.participants.contains(&user_id) {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
@@ -359,8 +454,9 @@ impl TeaclaveManagement for TeaclaveManagementService {
             _ => return Err(TeaclaveManagementError::PermissionDenied.into()),
         }
         task.approved_user_list.insert(user_id);
-        task.try_update_to_approved_status();
-        self.insert_or_update_task_to_storage(&task)?;
+        try_update_task_to_approved_status(&mut task);
+        self.write_to_db(&task)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
         Ok(ApproveTaskResponse)
     }
 
@@ -377,7 +473,13 @@ impl TeaclaveManagement for TeaclaveManagementService {
             .ok_or_else(|| TeaclaveManagementError::InvalidRequest)?
             .to_string();
         let request = request.message;
-        let mut task: Task = self.get_task_from_storage(&request.task_id)?;
+        if !Task::match_prefix(&request.task_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let mut task: Task = self
+            .read_from_db(request.task_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+
         if task.creator != user_id {
             return Err(TeaclaveManagementError::PermissionDenied.into());
         }
@@ -385,21 +487,22 @@ impl TeaclaveManagement for TeaclaveManagementService {
             TaskStatus::Approved => {}
             _ => return Err(TeaclaveManagementError::PermissionDenied.into()),
         }
-        let function = self.get_function_from_storage(&task.function_id)?;
+        if !Function::match_prefix(&task.function_id) {
+            return Err(TeaclaveManagementError::PermissionDenied.into());
+        }
+        let function: Function = self
+            .read_from_db(task.function_id.as_bytes())
+            .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+
         let arg_list: HashMap<String, String> = task.arg_list.clone();
-        let mut input_map = HashMap::new();
-        let mut output_map = HashMap::new();
+        let mut input_map: HashMap<String, InputData> = HashMap::new();
+        let mut output_map: HashMap<String, OutputData> = HashMap::new();
         for (data_name, data_id) in task.input_map.iter() {
-            let input_data = if TeaclaveInputFile::match_prefix(data_id) {
+            let input_data: InputData = if 
TeaclaveInputFile::match_prefix(data_id) {
                 let input_file: TeaclaveInputFile = self
                     .read_from_db(data_id.as_bytes())
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
                 InputData::from_input_file(input_file)
-                    .map_err(|_| TeaclaveManagementError::PermissionDenied)?
-            } else if FusionData::is_fusion_data_id(data_id) {
-                let fusion_data = self.get_fusion_data_from_storage(data_id)?;
-                InputData::from_fusion_data(fusion_data)
-                    .map_err(|_| TeaclaveManagementError::PermissionDenied)?
             } else {
                 return Err(TeaclaveManagementError::PermissionDenied.into());
             };
@@ -407,26 +510,31 @@ impl TeaclaveManagement for TeaclaveManagementService {
         }
 
         for (data_name, data_id) in task.output_map.iter() {
-            let output_data = if TeaclaveOutputFile::match_prefix(data_id) {
+            let output_data: OutputData = if 
TeaclaveOutputFile::match_prefix(data_id) {
                 let output_file: TeaclaveOutputFile = self
                     .read_from_db(data_id.as_bytes())
                     .map_err(|_| TeaclaveManagementError::PermissionDenied)?;
+                if output_file.hash.is_some() {
+                    return 
Err(TeaclaveManagementError::PermissionDenied.into());
+                }
                 OutputData::from_output_file(output_file)
-                    .map_err(|_| TeaclaveManagementError::PermissionDenied)?
-            } else if FusionData::is_fusion_data_id(data_id) {
-                let fusion_data = self.get_fusion_data_from_storage(data_id)?;
-                OutputData::from_fusion_data(fusion_data)
-                    .map_err(|_| TeaclaveManagementError::PermissionDenied)?
             } else {
                 return Err(TeaclaveManagementError::PermissionDenied.into());
             };
             output_map.insert(data_name.to_string(), output_data);
         }
-        let staged_task = StagedTask::new(&task.task_id, function, arg_list, 
input_map, output_map);
 
-        self.enqueue_staged_task(&staged_task)?;
+        let staged_task = StagedTask::new(
+            task.task_id.to_owned(),
+            function,
+            arg_list,
+            input_map,
+            output_map,
+        );
+        self.enqueue_to_db(StagedTask::get_queue_key().as_bytes(), 
&staged_task)?;
         task.status = TaskStatus::Running;
-        self.insert_or_update_task_to_storage(&task)?;
+        self.write_to_db(&task)
+            .map_err(|_| TeaclaveManagementError::StorageError)?;
         Ok(InvokeTaskResponse)
     }
 }
@@ -434,30 +542,24 @@ impl TeaclaveManagement for TeaclaveManagementService {
 impl TeaclaveManagementService {
     #[cfg(test_mode)]
     fn add_mock_data(&self) -> Result<()> {
-        use teaclave_proto::teaclave_frontend_service::{FunctionInput, 
FunctionOutput};
-        use teaclave_types::TeaclaveFileCryptoInfo;
-        use url::Url;
-        let mut fusion_data =
-            FusionData::new(vec!["mock_user2".to_string(), 
"mock_user3".to_string()])?;
-        fusion_data.data_id = "fusion-data-mock-data".to_string();
-        fusion_data.hash = Some("deadbeef".to_string());
-        let key = fusion_data.get_key_vec();
-        let value = fusion_data.to_vec()?;
-        self.write_to_storage(&key, &value)?;
-
-        let mut fusion_data =
-            FusionData::new(vec!["mock_user1".to_string(), 
"mock_user2".to_string()])?;
-        fusion_data.data_id = "fusion-data-mock-data2".to_string();
-        let key = fusion_data.get_key_vec();
-        let value = fusion_data.to_vec()?;
-        self.write_to_storage(&key, &value)?;
-
-        let mut fusion_data =
-            FusionData::new(vec!["frontend_user".to_string(), 
"mock_user".to_string()])?;
-        fusion_data.data_id = "fusion-data-mock-frontend-data".to_string();
-        let key = fusion_data.get_key_vec();
-        let value = fusion_data.to_vec()?;
-        self.write_to_storage(&key, &value)?;
+        let mut owner = HashSet::new();
+        owner.insert("mock_user1".to_string());
+        owner.insert("frontend_user".to_string());
+        let mut output_file = TeaclaveOutputFile::new_fusion_data(owner)?;
+        output_file.uuid = 
Uuid::parse_str("00000000-0000-0000-0000-000000000001")?;
+        output_file.hash = Some("deadbeef".to_string());
+        self.write_to_db(&output_file)?;
+
+        let mut owner = HashSet::new();
+        owner.insert("mock_user2".to_string());
+        owner.insert("mock_user3".to_string());
+        let mut output_file = TeaclaveOutputFile::new_fusion_data(owner)?;
+        output_file.uuid = 
Uuid::parse_str("00000000-0000-0000-0000-000000000002")?;
+        output_file.hash = Some("deadbeef".to_string());
+        self.write_to_db(&output_file)?;
+        let mut input_file = TeaclaveInputFile::from_output(output_file)?;
+        input_file.uuid = 
Uuid::parse_str("00000000-0000-0000-0000-000000000002")?;
+        self.write_to_db(&input_file)?;
 
         let function_input = FunctionInput {
             name: "input".to_string(),
@@ -477,7 +579,7 @@ impl TeaclaveManagementService {
         };
 
         let native_function = Function {
-            function_id: "native-mock-native-func".to_string(),
+            function_id: 
Uuid::parse_str("00000000-0000-0000-0000-000000000001")?,
             name: "mock-native-func".to_string(),
             description: "mock-desc".to_string(),
             payload: b"mock-payload".to_vec(),
@@ -488,16 +590,15 @@ impl TeaclaveManagementService {
             owner: "teaclave".to_string(),
             is_native: true,
         };
-        let key = native_function.get_key_vec();
-        let value = native_function.to_vec()?;
-        self.write_to_storage(&key, &value)?;
+
+        self.write_to_db(&native_function)?;
 
         let function_output = FunctionOutput {
             name: "output".to_string(),
             description: "output_desc".to_string(),
         };
         let native_function = Function {
-            function_id: "native-mock-simple-func".to_string(),
+            function_id: 
Uuid::parse_str("00000000-0000-0000-0000-000000000002")?,
             name: "mock-native-func".to_string(),
             description: "mock-desc".to_string(),
             payload: b"mock-payload".to_vec(),
@@ -508,17 +609,7 @@ impl TeaclaveManagementService {
             owner: "teaclave".to_string(),
             is_native: true,
         };
-        let key = native_function.get_key_vec();
-        let value = native_function.to_vec()?;
-        self.write_to_storage(&key, &value)?;
-
-        let url = Url::parse("s3://bucket_id/path?token=mock_token").unwrap();
-        let user_id = "mock_user1".to_string();
-        let crypto_info = TeaclaveFileCryptoInfo::default();
-        let mut output_file = TeaclaveOutputFile::new(url, crypto_info, 
user_id);
-        output_file.hash = Some("deadbeef".to_string());
-        output_file.uuid = 
Uuid::from_str("00000000-0000-0000-0000-000000000001")?;
-        self.write_to_db(&output_file)?;
+        self.write_to_db(&native_function)?;
         Ok(())
     }
 
@@ -542,17 +633,6 @@ impl TeaclaveManagementService {
         Ok(service)
     }
 
-    fn write_to_storage(&self, key: &[u8], value: &[u8]) -> Result<()> {
-        let put_request = PutRequest::new(key, value);
-        let _put_response = self
-            .storage_client
-            .clone()
-            .lock()
-            .map_err(|_| anyhow!("Cannot lock storage client"))?
-            .put(put_request)?;
-        Ok(())
-    }
-
     fn write_to_db(&self, item: &impl Storable) -> Result<()> {
         let k = item.key();
         let v = item.to_vec()?;
@@ -577,87 +657,8 @@ impl TeaclaveManagementService {
         T::from_slice(get_response.value.as_slice())
     }
 
-    fn read_from_storage(&self, key: &[u8]) -> Result<Vec<u8>> {
-        let get_request = GetRequest::new(key);
-        let get_response = self
-            .storage_client
-            .clone()
-            .lock()
-            .map_err(|_| anyhow!("Cannot lock storage client"))?
-            .get(get_request)?;
-        Ok(get_response.value)
-    }
-
-    // avoid accessing other kinds of data: 1) check function_id 2) 
deserialization
-    fn get_function_from_storage(
-        &self,
-        function_id: &str,
-    ) -> TeaclaveServiceResponseResult<Function> {
-        if !Function::is_function_id(function_id) {
-            return Err(TeaclaveManagementError::PermissionDenied.into());
-        }
-        let function_key = function_id.as_bytes();
-        let function_bytes = self
-            .read_from_storage(function_key)
-            .map_err(|_| TeaclaveManagementError::StorageError)?;
-        Function::from_slice(&function_bytes).map_err(|_| 
TeaclaveManagementError::DataError.into())
-    }
-
-    fn alloc_fusion_data(
-        &self,
-        user_id_list: Vec<String>,
-    ) -> TeaclaveServiceResponseResult<FusionData> {
-        let fusion_data =
-            FusionData::new(user_id_list).map_err(|_| 
TeaclaveManagementError::DataError)?;
-        let data_key = fusion_data.get_key_vec();
-        let value = fusion_data
-            .to_vec()
-            .map_err(|_| TeaclaveManagementError::DataError)?;
-        self.write_to_storage(&data_key, &value)
-            .map_err(|_| TeaclaveManagementError::StorageError)?;
-        Ok(fusion_data)
-    }
-
-    // avoid accessing other kinds of data: 1) check task_id 2) deserialization
-    fn get_task_from_storage(&self, task_id: &str) -> 
TeaclaveServiceResponseResult<Task> {
-        if !Task::is_task_id(task_id) {
-            return Err(TeaclaveManagementError::PermissionDenied.into());
-        }
-        let task_key = task_id.as_bytes();
-        let task_bytes = self
-            .read_from_storage(task_key)
-            .map_err(|_| TeaclaveManagementError::StorageError)?;
-        Task::from_slice(&task_bytes).map_err(|_| 
TeaclaveManagementError::DataError.into())
-    }
-
-    // avoid accessing other kinds of data: 1) check fusion_data_id 2) 
deserialization
-    fn get_fusion_data_from_storage(
-        &self,
-        fusion_data_id: &str,
-    ) -> TeaclaveServiceResponseResult<FusionData> {
-        if !FusionData::is_fusion_data_id(&fusion_data_id) {
-            return Err(TeaclaveManagementError::PermissionDenied.into());
-        }
-        let key = fusion_data_id.as_bytes();
-        let value = self
-            .read_from_storage(key)
-            .map_err(|_| TeaclaveManagementError::StorageError)?;
-        FusionData::from_slice(&value).map_err(|_| 
TeaclaveManagementError::DataError.into())
-    }
-
-    fn insert_or_update_task_to_storage(&self, task: &Task) -> 
TeaclaveServiceResponseResult<()> {
-        let key = task.get_key_vec();
-        let value = task
-            .to_vec()
-            .map_err(|_| TeaclaveManagementError::DataError)?;
-        self.write_to_storage(&key, &value)
-            .map_err(|_| TeaclaveManagementError::StorageError)?;
-        Ok(())
-    }
-
-    fn enqueue_staged_task(&self, staged_task: &StagedTask) -> 
TeaclaveServiceResponseResult<()> {
-        let key = StagedTask::get_queue_key();
-        let value = staged_task
+    fn enqueue_to_db(&self, key: &[u8], item: &impl Storable) -> 
TeaclaveServiceResponseResult<()> {
+        let value = item
             .to_vec()
             .map_err(|_| TeaclaveManagementError::DataError)?;
         let enqueue_request = EnqueueRequest::new(key, value);
@@ -674,15 +675,17 @@ impl TeaclaveManagementService {
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
     use super::*;
-    use std::collections::HashMap;
-    use teaclave_proto::teaclave_frontend_service::{FunctionInput, 
FunctionOutput};
-    use teaclave_types::{TeaclaveFileCryptoInfo, TeaclaveFileRootKey128};
+    use std::collections::{HashMap, HashSet};
+    use teaclave_types::{
+        FunctionInput, FunctionOutput, TeaclaveFileCryptoInfo, 
TeaclaveFileRootKey128,
+    };
     use url::Url;
 
     pub fn handle_input_file() {
         let url = Url::parse("s3://bucket_id/path?token=mock_token").unwrap();
         let hash = 
"a6d604b5987b693a19d94704532b5d928c2729f24dfd40745f8d03ac9ac75a8b".to_string();
-        let user_id = "mock_user".to_string();
+        let mut user_id: HashSet<String> = HashSet::new();
+        user_id.insert("mock_user".to_string());
         let crypto_info = TeaclaveFileCryptoInfo::TeaclaveFileRootKey128(
             TeaclaveFileRootKey128::new(&[0; 16]).unwrap(),
         );
@@ -695,7 +698,8 @@ pub mod tests {
 
     pub fn handle_output_file() {
         let url = Url::parse("s3://bucket_id/path?token=mock_token").unwrap();
-        let user_id = "mock_user".to_string();
+        let mut user_id: HashSet<String> = HashSet::new();
+        user_id.insert("mock_user".to_string());
         let crypto_info = TeaclaveFileCryptoInfo::TeaclaveFileRootKey128(
             TeaclaveFileRootKey128::new(&[0; 16]).unwrap(),
         );
@@ -706,18 +710,6 @@ pub mod tests {
         info!("file: {:?}", deserialized_file);
     }
 
-    pub fn handle_fusion_data() {
-        let fusion_data =
-            FusionData::new(vec!["mock_user_a".to_string(), 
"mock_user_b".to_string()]).unwrap();
-        let key = fusion_data.get_key_vec();
-        let key_str = std::str::from_utf8(&key).unwrap();
-        info!("key: {}", key_str);
-        assert!(FusionData::is_fusion_data_id(key_str));
-        let value = fusion_data.to_vec().unwrap();
-        let deserialized_data = FusionData::from_slice(&value).unwrap();
-        info!("data: {:?}", deserialized_data);
-    }
-
     pub fn handle_function() {
         let function_input = FunctionInput {
             name: "input".to_string(),
@@ -727,7 +719,8 @@ pub mod tests {
             name: "output".to_string(),
             description: "output_desc".to_string(),
         };
-        let register_request = RegisterFunctionRequest {
+        let function = Function {
+            function_id: Uuid::new_v4(),
             name: "mock_function".to_string(),
             description: "mock function".to_string(),
             payload: b"python script".to_vec(),
@@ -735,34 +728,32 @@ pub mod tests {
             arg_list: vec!["arg".to_string()],
             input_list: vec![function_input],
             output_list: vec![function_output],
+            owner: "mock_user".to_string(),
+            is_native: false,
         };
-        let function =
-            Function::new_from_register_request(register_request, 
"mock_user".to_string());
-        let key = function.get_key_vec();
-        let key_str = std::str::from_utf8(&key).unwrap();
-        info!("key: {}", key_str);
-        assert!(Function::is_function_id(key_str));
+        assert!(Function::match_prefix(&function.key_string()));
         let value = function.to_vec().unwrap();
-        let deserialized_data = Function::from_slice(&value).unwrap();
-        info!("data: {:?}", deserialized_data);
+        let deserialized_function = Function::from_slice(&value).unwrap();
+        info!("function: {:?}", deserialized_function);
     }
 
     pub fn handle_task() {
-        let function_request = RegisterFunctionRequest {
+        let function = Function {
+            function_id: Uuid::new_v4(),
             name: "mock_function".to_string(),
             description: "mock function".to_string(),
             payload: b"python script".to_vec(),
-            is_public: false,
+            is_public: true,
             arg_list: vec!["arg".to_string()],
             input_list: vec![],
             output_list: vec![],
+            owner: "mock_user".to_string(),
+            is_native: false,
         };
-        let function =
-            Function::new_from_register_request(function_request, 
"mock_user".to_string());
         let mut arg_list = HashMap::new();
         arg_list.insert("arg".to_string(), "data".to_string());
 
-        let task = Task::new(
+        let task = crate::task::create_task(
             function,
             "mock_user".to_string(),
             arg_list,
@@ -771,18 +762,15 @@ pub mod tests {
         )
         .unwrap();
 
-        let key = task.get_key_vec();
-        let key_str = std::str::from_utf8(&key).unwrap();
-        info!("key: {}", key_str);
-        assert!(Task::is_task_id(key_str));
+        assert!(Task::match_prefix(&task.key_string()));
         let value = task.to_vec().unwrap();
-        let deserialized_data = Task::from_slice(&value).unwrap();
-        info!("data: {:?}", deserialized_data);
+        let deserialized_task = Task::from_slice(&value).unwrap();
+        info!("task: {:?}", deserialized_task);
     }
 
     pub fn handle_staged_task() {
         let function = Function {
-            function_id: "function-mock".to_string(),
+            function_id: Uuid::new_v4(),
             name: "mock".to_string(),
             description: "".to_string(),
             payload: b"python script".to_vec(),
@@ -812,7 +800,8 @@ pub mod tests {
         let mut output_map = HashMap::new();
         output_map.insert("output".to_string(), output_data);
 
-        let staged_task = StagedTask::new("task-mock", function, arg_list, 
input_map, output_map);
+        let staged_task =
+            StagedTask::new(Uuid::new_v4(), function, arg_list, input_map, 
output_map);
 
         let value = staged_task.to_vec().unwrap();
         let deserialized_data = StagedTask::from_slice(&value).unwrap();
diff --git a/services/management/enclave/src/task.rs 
b/services/management/enclave/src/task.rs
index 9171f49..d6e3729 100644
--- a/services/management/enclave/src/task.rs
+++ b/services/management/enclave/src/task.rs
@@ -14,352 +14,177 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-use crate::function::Function;
-use crate::fusion_data::FusionData;
 use anyhow::{anyhow, ensure, Result};
-use serde::{Deserialize, Serialize};
-use serde_json;
 use std::collections::HashMap;
 use std::collections::HashSet;
 use std::prelude::v1::*;
-use teaclave_proto::teaclave_frontend_service::{DataOwnerList, TaskStatus};
-use teaclave_types::TeaclaveFileCryptoInfo;
-use teaclave_types::{Storable, TeaclaveInputFile, TeaclaveOutputFile};
-use url::Url;
+use teaclave_types::Function;
+use teaclave_types::{
+    DataOwnerList, Storable, Task, TaskStatus, TeaclaveInputFile, 
TeaclaveOutputFile,
+};
 use uuid::Uuid;
 
-const TASK_PREFIX: &str = "task-";
-const STAGED_TASK_PREFIX: &str = "staged-"; // staged-task-uuid
-const QUEUE_KEY: &str = "staged-task";
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct Task {
-    pub(crate) task_id: String,
-    pub(crate) creator: String,
-    pub(crate) function_id: String,
-    pub(crate) function_owner: String,
-    pub(crate) arg_list: HashMap<String, String>,
-    pub(crate) input_data_owner_list: HashMap<String, DataOwnerList>,
-    pub(crate) output_data_owner_list: HashMap<String, DataOwnerList>,
-    pub(crate) participants: HashSet<String>,
-    pub(crate) approved_user_list: HashSet<String>,
-    pub(crate) input_map: HashMap<String, String>,
-    pub(crate) output_map: HashMap<String, String>,
-    pub(crate) status: TaskStatus,
+pub(crate) fn create_task(
+    function: Function,
+    creator: String,
+    arg_list: HashMap<String, String>,
+    input_data_owner_list: HashMap<String, DataOwnerList>,
+    output_data_owner_list: HashMap<String, DataOwnerList>,
+) -> Result<Task> {
+    let task_id = Uuid::new_v4();
+    let mut participants = HashSet::new();
+    if !function.is_public {
+        participants.insert(function.owner.clone());
+    }
+    participants.insert(creator.clone());
+    for (_, data_owner_list) in input_data_owner_list.iter() {
+        for user_id in data_owner_list.user_id_list.iter() {
+            participants.insert(user_id.clone());
+        }
+    }
+    for (_, data_owner_list) in output_data_owner_list.iter() {
+        for user_id in data_owner_list.user_id_list.iter() {
+            participants.insert(user_id.clone());
+        }
+    }
+    let task = Task {
+        task_id,
+        creator,
+        function_id: function.external_id(),
+        function_owner: function.owner,
+        arg_list,
+        input_data_owner_list,
+        output_data_owner_list,
+        participants,
+        approved_user_list: HashSet::new(),
+        input_map: HashMap::new(),
+        output_map: HashMap::new(),
+        status: TaskStatus::Created,
+    };
+    // check arguments
+    let function_args: HashSet<String> = 
function.arg_list.into_iter().collect();
+    let provide_args: HashSet<String> = 
task.arg_list.keys().cloned().collect();
+    let diff: HashSet<_> = function_args.difference(&provide_args).collect();
+    ensure!(diff.is_empty(), "bad arguments");
+
+    // check input
+    let input_args: HashSet<String> = function.input_list.into_iter().map(|f| 
f.name).collect();
+    let provide_args: HashSet<String> = 
task.input_data_owner_list.keys().cloned().collect();
+    let diff: HashSet<_> = input_args.difference(&provide_args).collect();
+    ensure!(diff.is_empty(), "bad input");
+
+    // check output
+    let output_args: HashSet<String> = 
function.output_list.into_iter().map(|f| f.name).collect();
+    let provide_args: HashSet<String> = 
task.output_data_owner_list.keys().cloned().collect();
+    let diff: HashSet<_> = output_args.difference(&provide_args).collect();
+    ensure!(diff.is_empty(), "bad output");
+
+    Ok(task)
 }
 
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct InputData {
-    pub(crate) url: Url,
-    pub(crate) hash: String,
-    pub(crate) crypto_info: TeaclaveFileCryptoInfo,
-}
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct OutputData {
-    pub(crate) url: Url,
-    pub(crate) crypto_info: TeaclaveFileCryptoInfo,
-}
-
-#[derive(Debug, Deserialize, Serialize)]
-pub(crate) struct StagedTask {
-    pub(crate) staged_task_id: String,
-    pub(crate) task_id: String,
-    pub(crate) function_id: String,
-    pub(crate) function_payload: Vec<u8>,
-    pub(crate) arg_list: HashMap<String, String>,
-    pub(crate) input_map: HashMap<String, InputData>,
-    pub(crate) output_map: HashMap<String, OutputData>,
-}
-
-impl Task {
-    pub(crate) fn new(
-        function: Function,
-        creator: String,
-        arg_list: HashMap<String, String>,
-        input_data_owner_list: HashMap<String, DataOwnerList>,
-        output_data_owner_list: HashMap<String, DataOwnerList>,
-    ) -> Result<Self> {
-        let task_id = format!("{}{}", TASK_PREFIX, Uuid::new_v4().to_string());
-        let mut participants = HashSet::new();
-        if !function.is_public {
-            participants.insert(function.owner.clone());
-        }
-        participants.insert(creator.clone());
-        for (_, data_owner_list) in input_data_owner_list.iter() {
-            for user_id in data_owner_list.user_id_list.iter() {
-                participants.insert(user_id.clone());
-            }
-        }
-        for (_, data_owner_list) in output_data_owner_list.iter() {
-            for user_id in data_owner_list.user_id_list.iter() {
-                participants.insert(user_id.clone());
+// access control:
+// 1) input_file.owner contains user_id
+// 2) input_data_owner_list contains the data name
+// 3) user_id_list == input_file.owner
+pub(crate) fn assign_input_to_task(
+    task: &mut Task,
+    data_name: &str,
+    file: &TeaclaveInputFile,
+    user_id: &str,
+) -> Result<()> {
+    if !file.owner.contains(&user_id.to_string()) {
+        return Err(anyhow!("no permission"));
+    }
+    match task.input_data_owner_list.get(data_name) {
+        Some(data_owner_list) => {
+            let user_id_list = &data_owner_list.user_id_list;
+            if user_id_list.len() != file.owner.len() {
+                return Err(anyhow!("no permission"));
             }
-        }
-        let task = Self {
-            task_id,
-            creator,
-            function_id: function.function_id,
-            function_owner: function.owner,
-            arg_list,
-            input_data_owner_list,
-            output_data_owner_list,
-            participants,
-            approved_user_list: HashSet::new(),
-            input_map: HashMap::new(),
-            output_map: HashMap::new(),
-            status: TaskStatus::Created,
-        };
-        // check arguments
-        let function_args: HashSet<String> = 
function.arg_list.into_iter().collect();
-        let provide_args: HashSet<String> = 
task.arg_list.keys().cloned().collect();
-        let diff: HashSet<_> = 
function_args.difference(&provide_args).collect();
-        ensure!(diff.is_empty(), "bad arguments");
-
-        // check input
-        let input_args: HashSet<String> = 
function.input_list.into_iter().map(|f| f.name).collect();
-        let provide_args: HashSet<String> = 
task.input_data_owner_list.keys().cloned().collect();
-        let diff: HashSet<_> = input_args.difference(&provide_args).collect();
-        ensure!(diff.is_empty(), "bad input");
-
-        // check output
-        let output_args: HashSet<String> =
-            function.output_list.into_iter().map(|f| f.name).collect();
-        let provide_args: HashSet<String> = 
task.output_data_owner_list.keys().cloned().collect();
-        let diff: HashSet<_> = output_args.difference(&provide_args).collect();
-        ensure!(diff.is_empty(), "bad output");
-
-        Ok(task)
-    }
-
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        let ret: Task =
-            serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))?;
-        Ok(ret)
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
-    }
-
-    pub(crate) fn get_key_vec(&self) -> Vec<u8> {
-        self.task_id.as_bytes().to_vec()
-    }
-
-    // access control:
-    // 1) user_id == input_file.owner
-    // 2) input_data_owner_list contains the data name
-    // 3) DataOwnerList has only one user
-    // 4) user_id_list == user_id
-    pub(crate) fn assign_input_file(
-        &mut self,
-        data_name: &str,
-        file: &TeaclaveInputFile,
-        user_id: &str,
-    ) -> Result<()> {
-        if file.owner != user_id {
-            return Err(anyhow!("no permission"));
-        }
-        match self.input_data_owner_list.get(data_name) {
-            Some(data_owner_list) => {
-                let user_id_list = &data_owner_list.user_id_list;
-                if user_id_list.len() != 1 {
-                    return Err(anyhow!("no permission"));
-                }
-                if !user_id_list.contains(user_id) {
+            for owner in user_id_list.iter() {
+                if !file.owner.contains(owner) {
                     return Err(anyhow!("no permission"));
                 }
             }
-            None => return Err(anyhow!("no such this input name")),
-        };
-        self.input_map
-            .insert(data_name.to_owned(), file.external_id());
-        Ok(())
-    }
-
-    // access control:
-    // 1) output_file is not used.
-    // 2) user_id == output_file.owner
-    // 3) output_data_owner_list contains the data name
-    // 4) DataOwnerList has only one user
-    // 5) user_id_list == user_id
-    pub(crate) fn assign_output_file(
-        &mut self,
-        data_name: &str,
-        file: &TeaclaveOutputFile,
-        user_id: &str,
-    ) -> Result<()> {
-        if file.hash.is_some() {
-            return Err(anyhow!("no permission"));
         }
-        if file.owner != user_id {
-            return Err(anyhow!("no permission"));
-        }
-        match self.output_data_owner_list.get(data_name) {
-            Some(data_owner_list) => {
-                let user_id_list = &data_owner_list.user_id_list;
-                if user_id_list.len() != 1 {
-                    return Err(anyhow!("no permission"));
-                }
-                if !user_id_list.contains(user_id) {
-                    return Err(anyhow!("no permission"));
-                }
-            }
-            None => return Err(anyhow!("no such this input name")),
-        };
-        self.output_map
-            .insert(data_name.to_owned(), file.external_id());
-        Ok(())
-    }
+        None => return Err(anyhow!("no such input name")),
+    };
+    task.input_map
+        .insert(data_name.to_owned(), file.external_id());
+    Ok(())
+}
 
-    // access control:
-    // 1) fusion_data: fusion_data.owner_id_list.contains(user_id)
-    // 2) DataOwnerList == fusion_data.owner_id_list
-    // 3) input_data_owner_list contains the data name
-    pub(crate) fn assign_fusion_data(
-        &mut self,
-        data_name: &str,
-        fusion_data: &FusionData,
-        user_id: &str,
-    ) -> Result<()> {
-        if !fusion_data
-            .data_owner_id_list
-            .contains(&user_id.to_string())
-        {
-            return Err(anyhow!("no permission"));
-        }
-        match self.input_data_owner_list.get(data_name) {
-            Some(data_owner_list) => {
-                let user_id_list = &data_owner_list.user_id_list;
-                if user_id_list.len() != fusion_data.data_owner_id_list.len() {
+// access control:
+// 1) output_file is not used.
+// 2) output_file.owner contains user_id
+// 3) output_data_owner_list contains the data name
+// 4) user_id_list == output_file.owner
+pub(crate) fn assign_output_to_task(
+    task: &mut Task,
+    data_name: &str,
+    file: &TeaclaveOutputFile,
+    user_id: &str,
+) -> Result<()> {
+    if file.hash.is_some() {
+        return Err(anyhow!("no permission"));
+    }
+    if !file.owner.contains(&user_id.to_string()) {
+        return Err(anyhow!("no permission"));
+    }
+    match task.output_data_owner_list.get(data_name) {
+        Some(data_owner_list) => {
+            let user_id_list = &data_owner_list.user_id_list;
+            if user_id_list.len() != file.owner.len() {
+                return Err(anyhow!("no permission"));
+            }
+            for owner in user_id_list.iter() {
+                if !file.owner.contains(owner) {
                     return Err(anyhow!("no permission"));
                 }
-                for owner in user_id_list.iter() {
-                    if !fusion_data.data_owner_id_list.contains(owner) {
-                        return Err(anyhow!("no permission"));
-                    }
-                }
             }
-            None => return Err(anyhow!("no such this input name")),
-        }
-        self.input_map
-            .insert(data_name.to_string(), fusion_data.data_id.to_owned());
-        Ok(())
-    }
-
-    pub(crate) fn is_task_id(id: &str) -> bool {
-        id.starts_with(TASK_PREFIX)
-    }
-
-    pub(crate) fn try_update_to_ready_status(&mut self) {
-        match self.status {
-            TaskStatus::Created => {}
-            _ => return,
-        }
-
-        // check input
-        let input_args: HashSet<String> = 
self.input_data_owner_list.keys().cloned().collect();
-        let assiged_inputs: HashSet<String> = 
self.input_map.keys().cloned().collect();
-        let diff: HashSet<_> = 
input_args.difference(&assiged_inputs).collect();
-        if !diff.is_empty() {
-            return;
-        }
-
-        // check output
-        let output_args: HashSet<String> = 
self.output_data_owner_list.keys().cloned().collect();
-        let assiged_outputs: HashSet<String> = 
self.output_map.keys().cloned().collect();
-        let diff: HashSet<_> = 
output_args.difference(&assiged_outputs).collect();
-        if !diff.is_empty() {
-            return;
         }
-        self.status = TaskStatus::Ready;
-    }
-
-    pub(crate) fn try_update_to_approved_status(&mut self) {
-        match self.status {
-            TaskStatus::Ready => {}
-            _ => return,
-        }
-        let participants: HashSet<&String> = 
self.participants.iter().collect();
-        let approved_users: HashSet<&String> = 
self.approved_user_list.iter().collect();
-
-        let diff: HashSet<_> = 
participants.difference(&approved_users).collect();
-        if !diff.is_empty() {
-            return;
-        }
-        self.status = TaskStatus::Approved;
-    }
+        None => return Err(anyhow!("no such output name")),
+    };
+    task.output_map
+        .insert(data_name.to_owned(), file.external_id());
+    Ok(())
 }
 
-impl StagedTask {
-    pub(crate) fn new(
-        task_id: &str,
-        function: Function,
-        arg_list: HashMap<String, String>,
-        input_map: HashMap<String, InputData>,
-        output_map: HashMap<String, OutputData>,
-    ) -> Self {
-        Self {
-            staged_task_id: format!("{}{}", STAGED_TASK_PREFIX, task_id),
-            task_id: task_id.to_owned(),
-            function_id: function.function_id,
-            function_payload: function.payload,
-            arg_list,
-            input_map,
-            output_map,
-        }
+pub(crate) fn try_update_task_to_ready_status(task: &mut Task) {
+    match task.status {
+        TaskStatus::Created => {}
+        _ => return,
     }
 
-    pub(crate) fn get_queue_key() -> Vec<u8> {
-        QUEUE_KEY.as_bytes().to_vec()
+    // check input
+    let input_args: HashSet<String> = 
task.input_data_owner_list.keys().cloned().collect();
+    let assiged_inputs: HashSet<String> = 
task.input_map.keys().cloned().collect();
+    let diff: HashSet<_> = input_args.difference(&assiged_inputs).collect();
+    if !diff.is_empty() {
+        return;
     }
 
-    #[cfg(any(test_mod, feature = "enclave_unit_test"))]
-    pub(crate) fn from_slice(bytes: &[u8]) -> Result<Self> {
-        let ret: StagedTask =
-            serde_json::from_slice(&bytes).map_err(|_| anyhow!("failed to 
Deserialize"))?;
-        Ok(ret)
-    }
-
-    pub(crate) fn to_vec(&self) -> Result<Vec<u8>> {
-        serde_json::to_vec(&self).map_err(|_| anyhow!("failed to Serialize"))
+    // check output
+    let output_args: HashSet<String> = 
task.output_data_owner_list.keys().cloned().collect();
+    let assiged_outputs: HashSet<String> = 
task.output_map.keys().cloned().collect();
+    let diff: HashSet<_> = output_args.difference(&assiged_outputs).collect();
+    if !diff.is_empty() {
+        return;
     }
+    task.status = TaskStatus::Ready;
 }
 
-impl InputData {
-    pub(crate) fn from_input_file(input: TeaclaveInputFile) -> 
Result<InputData> {
-        Ok(InputData {
-            url: input.url,
-            hash: input.hash,
-            crypto_info: input.crypto_info,
-        })
-    }
-
-    pub(crate) fn from_fusion_data(input: FusionData) -> Result<InputData> {
-        let hash = input.hash.ok_or_else(|| anyhow!("invalid fusion data"))?;
-        Ok(InputData {
-            url: input.url,
-            hash,
-            crypto_info: input.crypto_info,
-        })
+pub(crate) fn try_update_task_to_approved_status(task: &mut Task) {
+    match task.status {
+        TaskStatus::Ready => {}
+        _ => return,
     }
-}
+    let participants: HashSet<&String> = task.participants.iter().collect();
+    let approved_users: HashSet<&String> = 
task.approved_user_list.iter().collect();
 
-impl OutputData {
-    pub(crate) fn from_output_file(output: TeaclaveOutputFile) -> 
Result<OutputData> {
-        if output.hash.is_some() {
-            return Err(anyhow!("invalid output file"));
-        }
-        Ok(OutputData {
-            url: output.url,
-            crypto_info: output.crypto_info,
-        })
-    }
-    pub(crate) fn from_fusion_data(output: FusionData) -> Result<OutputData> {
-        if output.hash.is_some() {
-            return Err(anyhow!("invalid fusion data"));
-        }
-        Ok(OutputData {
-            url: output.url,
-            crypto_info: output.crypto_info,
-        })
+    let diff: HashSet<_> = participants.difference(&approved_users).collect();
+    if !diff.is_empty() {
+        return;
     }
+    task.status = TaskStatus::Approved;
 }
diff --git a/services/proto/src/proto/teaclave_common.proto 
b/services/proto/src/proto/teaclave_common.proto
index 9f3e2e8..6522d00 100644
--- a/services/proto/src/proto/teaclave_common.proto
+++ b/services/proto/src/proto/teaclave_common.proto
@@ -11,3 +11,12 @@ message FileCryptoInfo {
   bytes key = 2;
   bytes iv = 3;
 }
+
+enum TaskStatus {
+  Created = 0;
+  Ready = 1;
+  Approved = 2;
+  Running = 3;
+  Failed = 4;
+  Finished = 5;
+}
diff --git a/services/proto/src/proto/teaclave_frontend_service.proto 
b/services/proto/src/proto/teaclave_frontend_service.proto
index c24eba2..b2434f4 100644
--- a/services/proto/src/proto/teaclave_frontend_service.proto
+++ b/services/proto/src/proto/teaclave_frontend_service.proto
@@ -23,21 +23,38 @@ message RegisterOutputFileResponse {
   string data_id = 1;
 }
 
+message RegisterFusionOutputRequest {
+  repeated string owner_list = 1;
+}
+
+message RegisterFusionOutputResponse {
+  string data_id = 1;
+}
+
+message RegisterInputFromOutputRequest {
+  string data_id = 1;
+}
+
+message RegisterInputFromOutputResponse {
+  string data_id = 1;
+}
+
 message GetOutputFileRequest {
   string data_id = 1;
 }
 
 message GetOutputFileResponse {
-  string hash = 1;
+  repeated string owner = 1;
+  string hash = 2;
 }
 
-message GetFusionDataRequest {
+message GetInputFileRequest {
   string data_id = 1;
 }
 
-message GetFusionDataResponse {
-  string hash = 1;
-  repeated string data_owner_id_list = 2;
+message GetInputFileResponse {
+  repeated string owner = 1;
+  string hash = 2;
 }
 
 message FunctionInput {
@@ -50,6 +67,11 @@ message FunctionOutput {
   string description = 2;
 }
 
+message DataOwnerList {
+  string data_name = 1;
+  repeated string user_id_list = 2;
+}
+
 message RegisterFunctionRequest {
   string name = 1;
   string description = 2;
@@ -79,11 +101,6 @@ message GetFunctionResponse {
   repeated FunctionOutput output_list = 8;
 }
 
-message DataOwnerList {
-  string data_name = 1;
-  repeated string user_id_list = 2;
-}
-
 message DataMap {
   string data_name = 1;
   string data_id = 2;
@@ -109,15 +126,6 @@ message GetTaskRequest {
   string task_id = 1;
 }
 
-enum TaskStatus {
-  Created = 0;
-  Ready = 1;
-  Approved = 2;
-  Running = 3;
-  Failed = 4;
-  Finished = 5;
-}
-
 message GetTaskResponse {
   string task_id = 1;
   string creator = 2;
@@ -130,7 +138,7 @@ message GetTaskResponse {
   repeated string approved_user_list = 9;
   repeated DataMap input_map = 10;
   repeated DataMap output_map = 11;
-  TaskStatus status = 12;
+  teaclave_common_proto.TaskStatus status = 12;
 }
 
 message AssignDataRequest {
@@ -156,8 +164,10 @@ message InvokeTaskResponse { }
 service TeaclaveFrontend {
   rpc RegisterInputFile (RegisterInputFileRequest) returns 
(RegisterInputFileResponse);
   rpc RegisterOutputFile (RegisterOutputFileRequest) returns 
(RegisterOutputFileResponse);
+  rpc RegisterFusionOutput (RegisterFusionOutputRequest) returns 
(RegisterFusionOutputResponse);
+  rpc RegisterInputFromOutput (RegisterInputFromOutputRequest) returns 
(RegisterInputFromOutputResponse);
   rpc GetOutputFile (GetOutputFileRequest) returns (GetOutputFileResponse);
-  rpc GetFusionData (GetFusionDataRequest) returns (GetFusionDataResponse);
+  rpc GetInputFile (GetInputFileRequest) returns (GetInputFileResponse);
   rpc RegisterFunction (RegisterFunctionRequest) returns 
(RegisterFunctionResponse);
   rpc GetFunction (GetFunctionRequest) returns (GetFunctionResponse);
   rpc CreateTask (CreateTaskRequest) returns (CreateTaskResponse);
diff --git a/services/proto/src/proto/teaclave_management_service.proto 
b/services/proto/src/proto/teaclave_management_service.proto
index 443f6f6..b026b6f 100644
--- a/services/proto/src/proto/teaclave_management_service.proto
+++ b/services/proto/src/proto/teaclave_management_service.proto
@@ -7,8 +7,10 @@ import "teaclave_frontend_service.proto";
 service TeaclaveManagement {
   rpc RegisterInputFile 
(teaclave_frontend_service_proto.RegisterInputFileRequest) returns 
(teaclave_frontend_service_proto.RegisterInputFileResponse);
   rpc RegisterOutputFile 
(teaclave_frontend_service_proto.RegisterOutputFileRequest) returns 
(teaclave_frontend_service_proto.RegisterOutputFileResponse);
+  rpc RegisterFusionOutput 
(teaclave_frontend_service_proto.RegisterFusionOutputRequest) returns 
(teaclave_frontend_service_proto.RegisterFusionOutputResponse);
+  rpc RegisterInputFromOutput 
(teaclave_frontend_service_proto.RegisterInputFromOutputRequest) returns 
(teaclave_frontend_service_proto.RegisterInputFromOutputResponse);
   rpc GetOutputFile (teaclave_frontend_service_proto.GetOutputFileRequest) 
returns (teaclave_frontend_service_proto.GetOutputFileResponse);
-  rpc GetFusionData (teaclave_frontend_service_proto.GetFusionDataRequest) 
returns (teaclave_frontend_service_proto.GetFusionDataResponse);
+  rpc GetInputFile (teaclave_frontend_service_proto.GetInputFileRequest) 
returns (teaclave_frontend_service_proto.GetInputFileResponse);
   rpc RegisterFunction 
(teaclave_frontend_service_proto.RegisterFunctionRequest) returns 
(teaclave_frontend_service_proto.RegisterFunctionResponse);
   rpc GetFunction (teaclave_frontend_service_proto.GetFunctionRequest) returns 
(teaclave_frontend_service_proto.GetFunctionResponse);
   rpc CreateTask (teaclave_frontend_service_proto.CreateTaskRequest) returns 
(teaclave_frontend_service_proto.CreateTaskResponse);
diff --git a/services/proto/src/teaclave_common.rs 
b/services/proto/src/teaclave_common.rs
index 354f46a..4126579 100644
--- a/services/proto/src/teaclave_common.rs
+++ b/services/proto/src/teaclave_common.rs
@@ -2,9 +2,8 @@
 use std::prelude::v1::*;
 
 use crate::teaclave_common_proto as proto;
-use anyhow::{Error, Result};
-use teaclave_types::TeaclaveFileCryptoInfo;
-use teaclave_types::TeaclaveFileRootKey128;
+use anyhow::{anyhow, Error, Result};
+use teaclave_types::{TaskStatus, TeaclaveFileCryptoInfo, 
TeaclaveFileRootKey128};
 
 #[derive(Debug)]
 pub struct UserCredential {
@@ -84,3 +83,27 @@ impl std::convert::From<TeaclaveFileRootKey128> for 
proto::FileCryptoInfo {
         }
     }
 }
+
+pub fn i32_to_task_status(status: i32) -> Result<TaskStatus> {
+    let ret = match proto::TaskStatus::from_i32(status) {
+        Some(proto::TaskStatus::Created) => TaskStatus::Created,
+        Some(proto::TaskStatus::Ready) => TaskStatus::Ready,
+        Some(proto::TaskStatus::Approved) => TaskStatus::Approved,
+        Some(proto::TaskStatus::Running) => TaskStatus::Running,
+        Some(proto::TaskStatus::Failed) => TaskStatus::Failed,
+        Some(proto::TaskStatus::Finished) => TaskStatus::Finished,
+        None => return Err(anyhow!("invalid task status")),
+    };
+    Ok(ret)
+}
+
+pub fn i32_from_task_status(status: TaskStatus) -> i32 {
+    match status {
+        TaskStatus::Created => proto::TaskStatus::Created as i32,
+        TaskStatus::Ready => proto::TaskStatus::Ready as i32,
+        TaskStatus::Approved => proto::TaskStatus::Approved as i32,
+        TaskStatus::Running => proto::TaskStatus::Running as i32,
+        TaskStatus::Failed => proto::TaskStatus::Failed as i32,
+        TaskStatus::Finished => proto::TaskStatus::Finished as i32,
+    }
+}
diff --git a/services/proto/src/teaclave_frontend_service.rs 
b/services/proto/src/teaclave_frontend_service.rs
index de28fd4..e76b1ef 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -1,3 +1,4 @@
+use crate::teaclave_common::{i32_from_task_status, i32_to_task_status};
 use crate::teaclave_frontend_service_proto as proto;
 use crate::teaclave_management_service::TeaclaveManagementRequest;
 use crate::teaclave_management_service::TeaclaveManagementResponse;
@@ -5,11 +6,12 @@ use anyhow::anyhow;
 use anyhow::{Error, Result};
 use core::convert::TryInto;
 use core::iter::FromIterator;
-use serde::{Deserialize, Serialize};
 use std::collections::{HashMap, HashSet};
 use std::prelude::v1::*;
 use teaclave_rpc::into_request;
-use teaclave_types::TeaclaveFileCryptoInfo;
+use teaclave_types::{
+    DataOwnerList, FunctionInput, FunctionOutput, TaskStatus, 
TeaclaveFileCryptoInfo,
+};
 use url::Url;
 
 pub use proto::TeaclaveFrontend;
@@ -48,43 +50,62 @@ pub struct RegisterOutputFileResponse {
     pub data_id: String,
 }
 
-#[into_request(TeaclaveManagementRequest::GetOutputFile)]
-#[into_request(TeaclaveFrontendRequest::GetOutputFile)]
+#[into_request(TeaclaveFrontendRequest::RegisterFusionOutput)]
+#[into_request(TeaclaveManagementRequest::RegisterFusionOutput)]
 #[derive(Debug)]
-pub struct GetOutputFileRequest {
+pub struct RegisterFusionOutputRequest {
+    pub owner_list: HashSet<String>,
+}
+
+#[into_request(TeaclaveFrontendResponse::RegisterFusionOutput)]
+#[into_request(TeaclaveManagementResponse::RegisterFusionOutput)]
+#[derive(Debug)]
+pub struct RegisterFusionOutputResponse {
     pub data_id: String,
 }
 
-#[into_request(TeaclaveManagementResponse::GetOutputFile)]
+#[into_request(TeaclaveFrontendRequest::RegisterInputFromOutput)]
+#[into_request(TeaclaveManagementRequest::RegisterInputFromOutput)]
 #[derive(Debug)]
-pub struct GetOutputFileResponse {
-    pub hash: String,
+pub struct RegisterInputFromOutputRequest {
+    pub data_id: String,
 }
 
-#[into_request(TeaclaveManagementRequest::GetFusionData)]
-#[into_request(TeaclaveFrontendRequest::GetFusionData)]
+#[into_request(TeaclaveFrontendResponse::RegisterInputFromOutput)]
+#[into_request(TeaclaveManagementResponse::RegisterInputFromOutput)]
 #[derive(Debug)]
-pub struct GetFusionDataRequest {
+pub struct RegisterInputFromOutputResponse {
     pub data_id: String,
 }
 
-#[into_request(TeaclaveManagementResponse::GetFusionData)]
+#[into_request(TeaclaveFrontendRequest::GetInputFile)]
+#[into_request(TeaclaveManagementRequest::GetInputFile)]
 #[derive(Debug)]
-pub struct GetFusionDataResponse {
+pub struct GetInputFileRequest {
+    pub data_id: String,
+}
+
+#[into_request(TeaclaveFrontendResponse::GetInputFile)]
+#[into_request(TeaclaveManagementResponse::GetInputFile)]
+#[derive(Debug)]
+pub struct GetInputFileResponse {
+    pub owner: HashSet<String>,
     pub hash: String,
-    pub data_owner_id_list: Vec<String>,
 }
 
-#[derive(Debug, Deserialize, Serialize)]
-pub struct FunctionInput {
-    pub name: String,
-    pub description: String,
+#[into_request(TeaclaveFrontendRequest::GetOutputFile)]
+#[into_request(TeaclaveManagementRequest::GetOutputFile)]
+#[derive(Debug)]
+pub struct GetOutputFileRequest {
+    pub data_id: String,
 }
 
-#[derive(Debug, Deserialize, Serialize)]
-pub struct FunctionOutput {
-    pub name: String,
-    pub description: String,
+#[into_request(TeaclaveFrontendResponse::GetOutputFile)]
+#[into_request(TeaclaveManagementResponse::GetOutputFile)]
+#[derive(Debug)]
+pub struct GetOutputFileResponse {
+    pub owner: HashSet<String>,
+    pub hash: String,
 }
 
 #[into_request(TeaclaveManagementRequest::RegisterFunction)]
@@ -126,11 +147,6 @@ pub struct GetFunctionResponse {
     pub output_list: Vec<FunctionOutput>,
 }
 
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct DataOwnerList {
-    pub user_id_list: HashSet<String>,
-}
-
 #[into_request(TeaclaveManagementRequest::CreateTask)]
 #[into_request(TeaclaveFrontendRequest::CreateTask)]
 #[derive(Debug)]
@@ -147,22 +163,6 @@ pub struct CreateTaskResponse {
     pub task_id: String,
 }
 
-#[derive(Debug)]
-pub struct DataMap {
-    pub data_name: String,
-    pub data_id: String,
-}
-
-#[derive(Debug, Deserialize, Serialize, std::cmp::PartialEq)]
-pub enum TaskStatus {
-    Created,
-    Ready,
-    Approved,
-    Running,
-    Failed,
-    Finished,
-}
-
 #[into_request(TeaclaveManagementRequest::GetTask)]
 #[into_request(TeaclaveFrontendRequest::GetTask)]
 #[derive(Debug)]
@@ -219,67 +219,6 @@ pub struct InvokeTaskRequest {
 #[derive(Debug)]
 pub struct InvokeTaskResponse;
 
-fn arg_list_from_proto(vector: Vec<proto::Argument>) -> Result<HashMap<String, 
String>> {
-    let mut ret = HashMap::with_capacity(vector.len());
-    for item in vector.into_iter() {
-        ret.insert(item.arg_name, item.arg_value);
-    }
-    Ok(ret)
-}
-
-fn arg_list_to_proto(map: HashMap<String, String>) -> Vec<proto::Argument> {
-    let mut ret = Vec::with_capacity(map.len());
-    for (arg_name, arg_value) in map.into_iter() {
-        let argument = proto::Argument {
-            arg_name,
-            arg_value,
-        };
-        ret.push(argument);
-    }
-    ret
-}
-
-fn data_map_to_proto(map: HashMap<String, String>) -> Vec<proto::DataMap> {
-    let mut ret = Vec::with_capacity(map.len());
-    for (data_name, data_id) in map.into_iter() {
-        let data_map = proto::DataMap { data_name, data_id };
-        ret.push(data_map);
-    }
-    ret
-}
-
-fn data_map_from_proto(vector: Vec<proto::DataMap>) -> Result<HashMap<String, 
String>> {
-    let mut ret = HashMap::with_capacity(vector.len());
-    for item in vector.into_iter() {
-        ret.insert(item.data_name, item.data_id);
-    }
-    Ok(ret)
-}
-
-fn data_owner_list_from_proto(
-    vector: Vec<proto::DataOwnerList>,
-) -> Result<HashMap<String, DataOwnerList>> {
-    let mut ret = HashMap::with_capacity(vector.len());
-    for item in vector.into_iter() {
-        let data_owner_list = DataOwnerList {
-            user_id_list: HashSet::from_iter(item.user_id_list.into_iter()),
-        };
-        ret.insert(item.data_name, data_owner_list);
-    }
-    Ok(ret)
-}
-
-fn data_owner_list_to_proto(map: HashMap<String, DataOwnerList>) -> 
Vec<proto::DataOwnerList> {
-    let mut ret = Vec::with_capacity(map.len());
-    for (data_name, data_owner_list) in map.into_iter() {
-        let data_owner_list = proto::DataOwnerList {
-            data_name,
-            user_id_list: data_owner_list.user_id_list.into_iter().collect(),
-        };
-        ret.push(data_owner_list);
-    }
-    ret
-}
 impl std::convert::TryFrom<proto::RegisterInputFileRequest> for 
RegisterInputFileRequest {
     type Error = Error;
 
@@ -368,10 +307,50 @@ impl From<RegisterOutputFileResponse> for 
proto::RegisterOutputFileResponse {
     }
 }
 
-impl std::convert::TryFrom<proto::GetOutputFileRequest> for 
GetOutputFileRequest {
+impl std::convert::TryFrom<proto::RegisterFusionOutputRequest> for 
RegisterFusionOutputRequest {
     type Error = Error;
 
-    fn try_from(proto: proto::GetOutputFileRequest) -> Result<Self> {
+    fn try_from(proto: proto::RegisterFusionOutputRequest) -> Result<Self> {
+        let ret = Self {
+            owner_list: proto.owner_list.into_iter().collect(),
+        };
+
+        Ok(ret)
+    }
+}
+
+impl From<RegisterFusionOutputRequest> for proto::RegisterFusionOutputRequest {
+    fn from(request: RegisterFusionOutputRequest) -> Self {
+        Self {
+            owner_list: request.owner_list.into_iter().collect(),
+        }
+    }
+}
+
+impl std::convert::TryFrom<proto::RegisterFusionOutputResponse> for 
RegisterFusionOutputResponse {
+    type Error = Error;
+
+    fn try_from(proto: proto::RegisterFusionOutputResponse) -> Result<Self> {
+        Ok(Self {
+            data_id: proto.data_id,
+        })
+    }
+}
+
+impl From<RegisterFusionOutputResponse> for 
proto::RegisterFusionOutputResponse {
+    fn from(request: RegisterFusionOutputResponse) -> Self {
+        Self {
+            data_id: request.data_id,
+        }
+    }
+}
+
+impl std::convert::TryFrom<proto::RegisterInputFromOutputRequest>
+    for RegisterInputFromOutputRequest
+{
+    type Error = Error;
+
+    fn try_from(proto: proto::RegisterInputFromOutputRequest) -> Result<Self> {
         let ret = Self {
             data_id: proto.data_id,
         };
@@ -380,34 +359,78 @@ impl std::convert::TryFrom<proto::GetOutputFileRequest> 
for GetOutputFileRequest
     }
 }
 
-impl From<GetOutputFileRequest> for proto::GetOutputFileRequest {
-    fn from(request: GetOutputFileRequest) -> Self {
+impl From<RegisterInputFromOutputRequest> for 
proto::RegisterInputFromOutputRequest {
+    fn from(request: RegisterInputFromOutputRequest) -> Self {
         Self {
             data_id: request.data_id,
         }
     }
 }
 
-impl std::convert::TryFrom<proto::GetOutputFileResponse> for 
GetOutputFileResponse {
+impl std::convert::TryFrom<proto::RegisterInputFromOutputResponse>
+    for RegisterInputFromOutputResponse
+{
     type Error = Error;
 
-    fn try_from(proto: proto::GetOutputFileResponse) -> Result<Self> {
-        Ok(Self { hash: proto.hash })
+    fn try_from(proto: proto::RegisterInputFromOutputResponse) -> Result<Self> 
{
+        Ok(Self {
+            data_id: proto.data_id,
+        })
     }
 }
 
-impl From<GetOutputFileResponse> for proto::GetOutputFileResponse {
-    fn from(response: GetOutputFileResponse) -> Self {
+impl From<RegisterInputFromOutputResponse> for 
proto::RegisterInputFromOutputResponse {
+    fn from(request: RegisterInputFromOutputResponse) -> Self {
+        Self {
+            data_id: request.data_id,
+        }
+    }
+}
+
+impl std::convert::TryFrom<proto::GetInputFileRequest> for GetInputFileRequest 
{
+    type Error = Error;
+
+    fn try_from(proto: proto::GetInputFileRequest) -> Result<Self> {
+        let ret = Self {
+            data_id: proto.data_id,
+        };
+
+        Ok(ret)
+    }
+}
+
+impl From<GetInputFileRequest> for proto::GetInputFileRequest {
+    fn from(request: GetInputFileRequest) -> Self {
         Self {
-            hash: response.hash,
+            data_id: request.data_id,
         }
     }
 }
 
-impl std::convert::TryFrom<proto::GetFusionDataRequest> for 
GetFusionDataRequest {
+impl std::convert::TryFrom<proto::GetInputFileResponse> for 
GetInputFileResponse {
     type Error = Error;
 
-    fn try_from(proto: proto::GetFusionDataRequest) -> Result<Self> {
+    fn try_from(proto: proto::GetInputFileResponse) -> Result<Self> {
+        Ok(Self {
+            owner: proto.owner.into_iter().collect(),
+            hash: proto.hash,
+        })
+    }
+}
+
+impl From<GetInputFileResponse> for proto::GetInputFileResponse {
+    fn from(request: GetInputFileResponse) -> Self {
+        Self {
+            owner: request.owner.into_iter().collect(),
+            hash: request.hash,
+        }
+    }
+}
+
+impl std::convert::TryFrom<proto::GetOutputFileRequest> for 
GetOutputFileRequest {
+    type Error = Error;
+
+    fn try_from(proto: proto::GetOutputFileRequest) -> Result<Self> {
         let ret = Self {
             data_id: proto.data_id,
         };
@@ -416,30 +439,30 @@ impl std::convert::TryFrom<proto::GetFusionDataRequest> 
for GetFusionDataRequest
     }
 }
 
-impl From<GetFusionDataRequest> for proto::GetFusionDataRequest {
-    fn from(request: GetFusionDataRequest) -> Self {
+impl From<GetOutputFileRequest> for proto::GetOutputFileRequest {
+    fn from(request: GetOutputFileRequest) -> Self {
         Self {
             data_id: request.data_id,
         }
     }
 }
 
-impl std::convert::TryFrom<proto::GetFusionDataResponse> for 
GetFusionDataResponse {
+impl std::convert::TryFrom<proto::GetOutputFileResponse> for 
GetOutputFileResponse {
     type Error = Error;
 
-    fn try_from(proto: proto::GetFusionDataResponse) -> Result<Self> {
+    fn try_from(proto: proto::GetOutputFileResponse) -> Result<Self> {
         Ok(Self {
+            owner: proto.owner.into_iter().collect(),
             hash: proto.hash,
-            data_owner_id_list: proto.data_owner_id_list,
         })
     }
 }
 
-impl From<GetFusionDataResponse> for proto::GetFusionDataResponse {
-    fn from(response: GetFusionDataResponse) -> Self {
+impl From<GetOutputFileResponse> for proto::GetOutputFileResponse {
+    fn from(request: GetOutputFileResponse) -> Self {
         Self {
-            hash: response.hash,
-            data_owner_id_list: response.data_owner_id_list,
+            owner: request.owner.into_iter().collect(),
+            hash: request.hash,
         }
     }
 }
@@ -637,6 +660,53 @@ impl From<GetFunctionResponse> for 
proto::GetFunctionResponse {
     }
 }
 
+pub fn data_owner_list_from_proto(
+    vector: Vec<proto::DataOwnerList>,
+) -> Result<HashMap<String, DataOwnerList>> {
+    let mut ret = HashMap::with_capacity(vector.len());
+    for item in vector.into_iter() {
+        let data_owner_list = DataOwnerList {
+            user_id_list: HashSet::from_iter(item.user_id_list.into_iter()),
+        };
+        ret.insert(item.data_name, data_owner_list);
+    }
+    Ok(ret)
+}
+
+pub fn data_owner_list_to_proto<S: std::hash::BuildHasher>(
+    map: HashMap<String, DataOwnerList, S>,
+) -> Vec<proto::DataOwnerList> {
+    let mut ret = Vec::with_capacity(map.len());
+    for (data_name, data_owner_list) in map.into_iter() {
+        let data_owner_list = proto::DataOwnerList {
+            data_name,
+            user_id_list: data_owner_list.user_id_list.into_iter().collect(),
+        };
+        ret.push(data_owner_list);
+    }
+    ret
+}
+
+fn arg_list_from_proto(vector: Vec<proto::Argument>) -> Result<HashMap<String, 
String>> {
+    let mut ret = HashMap::with_capacity(vector.len());
+    for item in vector.into_iter() {
+        ret.insert(item.arg_name, item.arg_value);
+    }
+    Ok(ret)
+}
+
+fn arg_list_to_proto(map: HashMap<String, String>) -> Vec<proto::Argument> {
+    let mut ret = Vec::with_capacity(map.len());
+    for (arg_name, arg_value) in map.into_iter() {
+        let argument = proto::Argument {
+            arg_name,
+            arg_value,
+        };
+        ret.push(argument);
+    }
+    ret
+}
+
 impl std::convert::TryFrom<proto::CreateTaskRequest> for CreateTaskRequest {
     type Error = Error;
 
@@ -689,34 +759,21 @@ impl From<CreateTaskResponse> for 
proto::CreateTaskResponse {
     }
 }
 
-impl std::convert::TryFrom<i32> for TaskStatus {
-    type Error = Error;
-
-    fn try_from(status: i32) -> Result<Self> {
-        let ret = match proto::TaskStatus::from_i32(status) {
-            Some(proto::TaskStatus::Created) => TaskStatus::Created,
-            Some(proto::TaskStatus::Ready) => TaskStatus::Ready,
-            Some(proto::TaskStatus::Approved) => TaskStatus::Approved,
-            Some(proto::TaskStatus::Running) => TaskStatus::Running,
-            Some(proto::TaskStatus::Failed) => TaskStatus::Failed,
-            Some(proto::TaskStatus::Finished) => TaskStatus::Finished,
-            None => return Err(anyhow!("invalid task status")),
-        };
-        Ok(ret)
+fn data_map_to_proto(map: HashMap<String, String>) -> Vec<proto::DataMap> {
+    let mut ret = Vec::with_capacity(map.len());
+    for (data_name, data_id) in map.into_iter() {
+        let data_map = proto::DataMap { data_name, data_id };
+        ret.push(data_map);
     }
+    ret
 }
 
-impl From<TaskStatus> for i32 {
-    fn from(status: TaskStatus) -> i32 {
-        match status {
-            TaskStatus::Created => proto::TaskStatus::Created as i32,
-            TaskStatus::Ready => proto::TaskStatus::Ready as i32,
-            TaskStatus::Approved => proto::TaskStatus::Approved as i32,
-            TaskStatus::Running => proto::TaskStatus::Running as i32,
-            TaskStatus::Failed => proto::TaskStatus::Failed as i32,
-            TaskStatus::Finished => proto::TaskStatus::Finished as i32,
-        }
+fn data_map_from_proto(vector: Vec<proto::DataMap>) -> Result<HashMap<String, 
String>> {
+    let mut ret = HashMap::with_capacity(vector.len());
+    for item in vector.into_iter() {
+        ret.insert(item.data_name, item.data_id);
     }
+    Ok(ret)
 }
 
 impl std::convert::TryFrom<proto::GetTaskRequest> for GetTaskRequest {
@@ -748,7 +805,7 @@ impl std::convert::TryFrom<proto::GetTaskResponse> for 
GetTaskResponse {
         let output_data_owner_list = 
data_owner_list_from_proto(proto.output_data_owner_list)?;
         let input_map = data_map_from_proto(proto.input_map)?;
         let output_map = data_map_from_proto(proto.output_map)?;
-        let status = TaskStatus::try_from(proto.status)?;
+        let status = i32_to_task_status(proto.status)?;
 
         let ret = Self {
             task_id: proto.task_id,
@@ -776,7 +833,7 @@ impl From<GetTaskResponse> for proto::GetTaskResponse {
         let output_data_owner_list = 
data_owner_list_to_proto(response.output_data_owner_list);
         let input_map = data_map_to_proto(response.input_map);
         let output_map = data_map_to_proto(response.output_map);
-        let status = i32::from(response.status);
+        let status = i32_from_task_status(response.status);
         Self {
             task_id: response.task_id,
             creator: response.creator,
diff --git a/services/proto/src/teaclave_management_service.rs 
b/services/proto/src/teaclave_management_service.rs
index 9b5013b..55edd23 100644
--- a/services/proto/src/teaclave_management_service.rs
+++ b/services/proto/src/teaclave_management_service.rs
@@ -9,10 +9,18 @@ pub type RegisterInputFileRequest = 
crate::teaclave_frontend_service::RegisterIn
 pub type RegisterInputFileResponse = 
crate::teaclave_frontend_service::RegisterInputFileResponse;
 pub type RegisterOutputFileRequest = 
crate::teaclave_frontend_service::RegisterOutputFileRequest;
 pub type RegisterOutputFileResponse = 
crate::teaclave_frontend_service::RegisterOutputFileResponse;
+pub type RegisterFusionOutputRequest =
+    crate::teaclave_frontend_service::RegisterFusionOutputRequest;
+pub type RegisterFusionOutputResponse =
+    crate::teaclave_frontend_service::RegisterFusionOutputResponse;
+pub type RegisterInputFromOutputRequest =
+    crate::teaclave_frontend_service::RegisterInputFromOutputRequest;
+pub type RegisterInputFromOutputResponse =
+    crate::teaclave_frontend_service::RegisterInputFromOutputResponse;
+pub type GetInputFileRequest = 
crate::teaclave_frontend_service::GetInputFileRequest;
+pub type GetInputFileResponse = 
crate::teaclave_frontend_service::GetInputFileResponse;
 pub type GetOutputFileRequest = 
crate::teaclave_frontend_service::GetOutputFileRequest;
 pub type GetOutputFileResponse = 
crate::teaclave_frontend_service::GetOutputFileResponse;
-pub type GetFusionDataRequest = 
crate::teaclave_frontend_service::GetFusionDataRequest;
-pub type GetFusionDataResponse = 
crate::teaclave_frontend_service::GetFusionDataResponse;
 pub type RegisterFunctionRequest = 
crate::teaclave_frontend_service::RegisterFunctionRequest;
 pub type RegisterFunctionResponse = 
crate::teaclave_frontend_service::RegisterFunctionResponse;
 pub type GetFunctionRequest = 
crate::teaclave_frontend_service::GetFunctionRequest;
diff --git a/tests/functional/enclave/src/teaclave_frontend_service.rs 
b/tests/functional/enclave/src/teaclave_frontend_service.rs
index ca2e2a3..a67e75d 100644
--- a/tests/functional/enclave/src/teaclave_frontend_service.rs
+++ b/tests/functional/enclave/src/teaclave_frontend_service.rs
@@ -17,8 +17,10 @@ pub fn run_tests() -> bool {
     run_tests!(
         test_register_input_file,
         test_register_output_file,
+        test_register_fusion_output,
+        test_register_input_from_output,
         test_get_output_file,
-        test_get_fusion_data,
+        test_get_input_file,
         test_register_function,
         test_get_function,
         test_create_task,
@@ -123,6 +125,51 @@ fn test_register_output_file() {
     assert!(response.is_err());
 }
 
+fn test_register_fusion_output() {
+    let mut client = get_client();
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["frontend_user", "mock_user"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+    let response = client.register_fusion_output(request);
+    assert!(response.is_ok());
+    assert!(!response.unwrap().data_id.is_empty());
+
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["frontend_user", "mock_user"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+    client
+        .metadata_mut()
+        .insert("token".to_string(), "wrong token".to_string());
+    let response = client.register_fusion_output(request);
+    assert!(response.is_err());
+}
+
+fn test_register_input_from_output() {
+    let mut client = get_client();
+    let data_id = "output-file-00000000-0000-0000-0000-000000000001";
+    let request = RegisterInputFromOutputRequest {
+        data_id: data_id.to_string(),
+    };
+    let response = client.register_input_from_output(request);
+    assert!(response.is_ok());
+    assert!(!response.unwrap().data_id.is_empty());
+
+    let request = RegisterInputFromOutputRequest {
+        data_id: data_id.to_string(),
+    };
+    client
+        .metadata_mut()
+        .insert("token".to_string(), "wrong token".to_string());
+    let response = client.register_input_from_output(request);
+    assert!(response.is_err());
+}
+
 fn test_get_output_file() {
     let request = RegisterOutputFileRequest {
         url: 
Url::parse("s3://s3.us-west-2.amazonaws.com/mybucket/puppy.jpg.enc?key-id=deadbeefdeadbeef&key=deadbeefdeadbeef").unwrap(),
@@ -148,23 +195,29 @@ fn test_get_output_file() {
     assert!(response.is_err());
 }
 
-fn test_get_fusion_data() {
+fn test_get_input_file() {
+    let request = RegisterInputFileRequest {
+        url: 
Url::parse("s3://s3.us-west-2.amazonaws.com/mybucket/puppy.jpg.enc?key-id=deadbeefdeadbeef&key=deadbeefdeadbeef").unwrap(),
+        hash: "deadbeef".to_string(),
+        crypto_info: TeaclaveFileCryptoInfo::default(),
+    };
+
     let mut client = get_client();
+    let response = client.register_input_file(request);
+    let data_id = response.unwrap().data_id;
 
-    let request = GetFusionDataRequest {
-        data_id: "fusion-data-mock-frontend-data".to_string(),
+    let request = GetInputFileRequest {
+        data_id: data_id.clone(),
     };
-    let response = client.get_fusion_data(request);
+    let response = client.get_input_file(request);
     assert!(response.is_ok());
-    assert!(response.unwrap().hash.is_empty());
+    assert!(!response.unwrap().hash.is_empty());
 
-    let request = GetFusionDataRequest {
-        data_id: "fusion-data-mock-frontend-data".to_string(),
-    };
+    let request = GetInputFileRequest { data_id };
     client
         .metadata_mut()
         .insert("token".to_string(), "wrong token".to_string());
-    let response = client.get_fusion_data(request);
+    let response = client.get_input_file(request);
     assert!(response.is_err());
 }
 
@@ -204,14 +257,14 @@ fn test_get_function() {
     let mut client = get_client();
 
     let request = GetFunctionRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000001".to_string(),
     };
     let response = client.get_function(request);
     assert!(response.is_ok());
     assert!(!response.unwrap().name.is_empty());
 
     let request = GetFunctionRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000001".to_string(),
     };
     client
         .metadata_mut()
@@ -228,10 +281,11 @@ fn test_create_task() {
             .into_iter()
             .collect(),
     };
+    let function_id = "function-00000000-0000-0000-0000-000000000002";
     let mut output_data_owner_list = HashMap::new();
     output_data_owner_list.insert("output".to_string(), data_owner_id_list);
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: function_id.to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
@@ -243,7 +297,7 @@ fn test_create_task() {
     assert!(!response.unwrap().task_id.is_empty());
 
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: function_id.to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
@@ -268,7 +322,7 @@ fn test_get_task() {
     let mut output_data_owner_list = HashMap::new();
     output_data_owner_list.insert("output".to_string(), data_owner_id_list);
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000002".to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
@@ -302,7 +356,7 @@ fn test_assign_data() {
     let mut output_data_owner_list = HashMap::new();
     output_data_owner_list.insert("output".to_string(), data_owner_id_list);
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000002".to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
@@ -356,7 +410,7 @@ fn test_approve_task() {
     let mut output_data_owner_list = HashMap::new();
     output_data_owner_list.insert("output".to_string(), data_owner_id_list);
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000002".to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
@@ -409,7 +463,7 @@ fn test_invoke_task() {
     let mut output_data_owner_list = HashMap::new();
     output_data_owner_list.insert("output".to_string(), data_owner_id_list);
     let request = CreateTaskRequest {
-        function_id: "native-mock-simple-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000002".to_string(),
         arg_list: vec![("arg1".to_string(), "data1".to_string())]
             .into_iter()
             .collect(),
diff --git a/tests/functional/enclave/src/teaclave_management_service.rs 
b/tests/functional/enclave/src/teaclave_management_service.rs
index 6508b15..625df54 100644
--- a/tests/functional/enclave/src/teaclave_management_service.rs
+++ b/tests/functional/enclave/src/teaclave_management_service.rs
@@ -3,9 +3,9 @@ use std::prelude::v1::*;
 use teaclave_attestation::verifier;
 use teaclave_config::RuntimeConfig;
 use teaclave_config::BUILD_CONFIG;
-use teaclave_proto::teaclave_frontend_service::{
-    DataOwnerList, FunctionInput, FunctionOutput, TaskStatus,
-};
+//use teaclave_proto::teaclave_frontend_service::{
+//    DataOwnerList, FunctionInput, FunctionOutput, TaskStatus,
+//};
 use teaclave_proto::teaclave_management_service::*;
 use teaclave_rpc::config::SgxTrustedTlsClientConfig;
 use teaclave_rpc::endpoint::Endpoint;
@@ -18,11 +18,13 @@ pub fn run_tests() -> bool {
     run_tests!(
         test_register_input_file,
         test_register_output_file,
-        test_register_function,
-        test_create_task,
+        test_register_fusion_output,
+        test_register_input_from_output,
+        test_get_input_file,
         test_get_output_file,
-        test_get_fusion_data,
+        test_register_function,
         test_get_function,
+        test_create_task,
         test_get_task,
         test_assign_data,
         test_approve_task,
@@ -91,13 +93,67 @@ fn test_register_output_file() {
     assert!(response.is_ok());
 }
 
+fn test_register_fusion_output() {
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["mock_user", "mock_user_b"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+
+    let mut client = get_client("mock_user");
+    let response = client.register_fusion_output(request);
+
+    assert!(response.is_ok());
+
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["mock_user_c", "mock_user_b"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+
+    let mut client = get_client("mock_user");
+    let response = client.register_fusion_output(request);
+    assert!(response.is_err());
+}
+
+fn test_register_input_from_output() {
+    // not a owner
+    let mut client = get_client("mock_user_c");
+    let data_id = "output-file-00000000-0000-0000-0000-000000000001";
+    let request = RegisterInputFromOutputRequest {
+        data_id: data_id.to_string(),
+    };
+    let response = client.register_input_from_output(request);
+    assert!(response.is_err());
+
+    // output not ready
+    let mut client = get_client("mock_user1");
+    let request = RegisterOutputFileRequest {
+        url: 
Url::parse("s3://s3.us-west-2.amazonaws.com/mybucket/puppy.jpg.enc?key-id=deadbeefdeadbeef&key=deadbeefdeadbeef").unwrap(),
+        crypto_info: TeaclaveFileCryptoInfo::default(),
+    };
+    let response = client.register_output_file(request);
+    assert!(response.is_ok());
+    let request = RegisterInputFromOutputRequest {
+        data_id: response.unwrap().data_id,
+    };
+    let response = client.register_input_from_output(request);
+    assert!(response.is_err());
+
+    let request = RegisterInputFromOutputRequest {
+        data_id: data_id.to_string(),
+    };
+    let response = client.register_input_from_output(request);
+    assert!(response.is_ok());
+    info!("{:?}", response);
+}
+
 fn test_get_output_file() {
     let request = RegisterOutputFileRequest {
         url: 
Url::parse("s3://s3.us-west-2.amazonaws.com/mybucket/puppy.jpg.enc?key-id=deadbeefdeadbeef&key=deadbeefdeadbeef").unwrap(),
-        crypto_info: TeaclaveFileCryptoInfo::AesGcm128(AesGcm128CryptoInfo {
-            key: [0x90u8; 16],
-            iv: [0x89u8; 12],
-        }),
+        crypto_info: TeaclaveFileCryptoInfo::default(),
     };
 
     let mut client = get_client("mock_user");
@@ -114,32 +170,24 @@ fn test_get_output_file() {
     assert!(response.is_err());
 }
 
-fn test_get_fusion_data() {
-    let mut client = get_client("mock_user2");
-    let request = GetFusionDataRequest {
-        data_id: "fusion-data-mock-data".to_string(),
+fn test_get_input_file() {
+    let request = RegisterInputFileRequest {
+        url: 
Url::parse("s3://s3.us-west-2.amazonaws.com/mybucket/puppy.jpg.enc?key-id=deadbeefdeadbeef&key=deadbeefdeadbeef").unwrap(),
+        hash: "deadbeef".to_string(),
+        crypto_info: TeaclaveFileCryptoInfo::default(),
     };
-    let response = client.get_fusion_data(request);
-    assert!(response.is_ok());
 
-    let mut client = get_client("mock_user3");
-    let request = GetFusionDataRequest {
-        data_id: "fusion-data-mock-data".to_string(),
+    let mut client = get_client("mock_user");
+    let response = client.register_input_file(request).unwrap();
+    let data_id = response.data_id;
+    let request = GetInputFileRequest {
+        data_id: data_id.clone(),
     };
-    let response = client.get_fusion_data(request);
+    let response = client.get_input_file(request);
     assert!(response.is_ok());
-    let response = response.unwrap();
-    assert!(!response.hash.is_empty());
-    assert_eq!(
-        response.data_owner_id_list,
-        ["mock_user2".to_string(), "mock_user3".to_string()]
-    );
-
-    let mut client = get_client("mock_user_c");
-    let request = GetFusionDataRequest {
-        data_id: "fusion-data-mock-data".to_string(),
-    };
-    let response = client.get_fusion_data(request);
+    let mut client = get_client("mock_another_user");
+    let request = GetInputFileRequest { data_id };
+    let response = client.get_input_file(request);
     assert!(response.is_err());
 }
 
@@ -202,7 +250,7 @@ fn test_get_function() {
     let response = client.get_function(request);
     assert!(response.is_err());
     let request = GetFunctionRequest {
-        function_id: "native-mock-native-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000001".to_string(),
     };
     let response = client.get_function(request);
     assert!(response.is_ok());
@@ -229,7 +277,7 @@ fn get_correct_create_task() -> CreateTaskRequest {
     output_data_owner_list.insert("output2".to_string(), data_owner_id_list2);
 
     CreateTaskRequest {
-        function_id: "native-mock-native-func".to_string(),
+        function_id: 
"function-00000000-0000-0000-0000-000000000001".to_string(),
         arg_list,
         input_data_owner_list,
         output_data_owner_list,
@@ -284,7 +332,6 @@ fn test_get_task() {
         assert!(response.participants.contains(&name.to_string()));
     }
     assert!(response.participants.len() == 4);
-    assert!(response.output_map.len() == 1);
 }
 
 fn test_assign_data() {
@@ -307,7 +354,7 @@ fn test_assign_data() {
     let response = unknown_client.assign_data(request);
     assert!(response.is_err());
 
-    // user_id != input_file.owner
+    // !input_file.owner.contains(user_id)
     let request = RegisterInputFileRequest {
         url: Url::parse("input://path").unwrap(),
         hash: "deadbeefdeadbeef".to_string(),
@@ -327,7 +374,7 @@ fn test_assign_data() {
     let response = client1.assign_data(request);
     assert!(response.is_err());
 
-    // user_id != output_file.owner
+    // !output_file.owner.contains(user_id)
     let request = RegisterOutputFileRequest {
         url: Url::parse("output://path").unwrap(),
         crypto_info: TeaclaveFileCryptoInfo::default(),
@@ -372,9 +419,10 @@ fn test_assign_data() {
         input_map: HashMap::new(),
         output_map: HashMap::new(),
     };
-    request
-        .input_map
-        .insert("input".to_string(), "fusion-data-mock-data".to_string());
+    request.input_map.insert(
+        "input".to_string(),
+        "input-file-00000000-0000-0000-0000-000000000002".to_string(),
+    );
     let response = client1.assign_data(request);
     assert!(response.is_err());
 
@@ -402,7 +450,7 @@ fn test_assign_data() {
     let response = client2.assign_data(request);
     assert!(response.is_err());
 
-    //input file: DataOwnerList has one user
+    //input file: DataOwnerList != user_id
     let mut request = AssignDataRequest {
         task_id: task_id.clone(),
         input_map: HashMap::new(),
@@ -426,7 +474,7 @@ fn test_assign_data() {
     let response = client2.assign_data(request);
     assert!(response.is_err());
 
-    // output file DataOwnerList has one user
+    // output file DataOwnerList != user_id_list
     let mut request = AssignDataRequest {
         task_id: task_id.clone(),
         input_map: HashMap::new(),
@@ -438,7 +486,7 @@ fn test_assign_data() {
     let response = client2.assign_data(request);
     assert!(response.is_err());
 
-    // output file: DataOwnerList != user_id
+    // output file: DataOwnerList != user_id_list
     let mut request = AssignDataRequest {
         task_id: task_id.clone(),
         input_map: HashMap::new(),
@@ -450,30 +498,6 @@ fn test_assign_data() {
     let response = client2.assign_data(request);
     assert!(response.is_err());
 
-    // fusion_data in output_map
-    let mut request = AssignDataRequest {
-        task_id: task_id.clone(),
-        input_map: HashMap::new(),
-        output_map: HashMap::new(),
-    };
-    request
-        .output_map
-        .insert("output2".to_string(), "fusion-data-mock-data".to_string());
-    let response = client2.assign_data(request);
-    assert!(response.is_err());
-
-    // fusion_data: DataOwnerList == fusion_data.owner_id_list
-    let mut request = AssignDataRequest {
-        task_id: task_id.clone(),
-        input_map: HashMap::new(),
-        output_map: HashMap::new(),
-    };
-    request
-        .output_map
-        .insert("output2".to_string(), "fusion-data-mock-data2".to_string());
-    let response = client2.assign_data(request);
-    assert!(response.is_err());
-
     // assign all the data
     let request = RegisterInputFileRequest {
         url: Url::parse("input://path").unwrap(),
@@ -509,9 +533,29 @@ fn test_assign_data() {
         input_map: HashMap::new(),
         output_map: HashMap::new(),
     };
+    request.input_map.insert(
+        "input2".to_string(),
+        "input-file-00000000-0000-0000-0000-000000000002".to_string(),
+    );
+    let response = client3.assign_data(request);
+    assert!(response.is_ok());
+
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["mock_user2", "mock_user3"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+    let response = client3.register_fusion_output(request);
+    let fusion_output = response.unwrap().data_id;
+    let mut request = AssignDataRequest {
+        task_id: task_id.clone(),
+        input_map: HashMap::new(),
+        output_map: HashMap::new(),
+    };
     request
-        .input_map
-        .insert("input2".to_string(), "fusion-data-mock-data".to_string());
+        .output_map
+        .insert("output2".to_string(), fusion_output);
     let response = client3.assign_data(request);
     assert!(response.is_ok());
 
@@ -519,7 +563,6 @@ fn test_assign_data() {
         task_id: task_id.clone(),
     };
     let response = client3.get_task(request);
-    info!("{:?}", response);
     assert_eq!(response.unwrap().status, TaskStatus::Ready);
 
     // task.status != Created
@@ -585,12 +628,32 @@ fn test_approve_task() {
         input_map: HashMap::new(),
         output_map: HashMap::new(),
     };
-    request
-        .input_map
-        .insert("input2".to_string(), "fusion-data-mock-data".to_string());
+    request.input_map.insert(
+        "input2".to_string(),
+        "input-file-00000000-0000-0000-0000-000000000002".to_string(),
+    );
     let response = client2.assign_data(request);
     assert!(response.is_ok());
 
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["mock_user2", "mock_user3"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+    let response = client3.register_fusion_output(request);
+    let fusion_output = response.unwrap().data_id;
+    let mut request = AssignDataRequest {
+        task_id: task_id.clone(),
+        input_map: HashMap::new(),
+        output_map: HashMap::new(),
+    };
+    request
+        .output_map
+        .insert("output2".to_string(), fusion_output);
+    let response = client3.assign_data(request);
+    assert!(response.is_ok());
+
     let request = GetTaskRequest {
         task_id: task_id.clone(),
     };
@@ -672,10 +735,31 @@ fn test_invoke_task() {
         input_map: HashMap::new(),
         output_map: HashMap::new(),
     };
+    request.input_map.insert(
+        "input2".to_string(),
+        "input-file-00000000-0000-0000-0000-000000000002".to_string(),
+    );
+    let response = client2.assign_data(request);
+    assert!(response.is_ok());
+
+    let request = RegisterFusionOutputRequest {
+        owner_list: vec!["mock_user2", "mock_user3"]
+            .into_iter()
+            .map(|s| s.to_string())
+            .collect(),
+    };
+    let response = client3.register_fusion_output(request);
+    let fusion_output = response.unwrap().data_id;
+    let mut request = AssignDataRequest {
+        task_id: task_id.clone(),
+        input_map: HashMap::new(),
+        output_map: HashMap::new(),
+    };
     request
-        .input_map
-        .insert("input2".to_string(), "fusion-data-mock-data".to_string());
-    client2.assign_data(request).unwrap();
+        .output_map
+        .insert("output2".to_string(), fusion_output);
+    let response = client3.assign_data(request);
+    assert!(response.is_ok());
 
     // task status != Approved
     let request = InvokeTaskRequest {
diff --git a/types/src/file.rs b/types/src/file.rs
index 085dfe8..80b2795 100644
--- a/types/src/file.rs
+++ b/types/src/file.rs
@@ -14,10 +14,11 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
+use crate::storage::Storable;
 use crate::TeaclaveFileCryptoInfo;
-use anyhow;
+use anyhow::{anyhow, Result};
 use serde::{Deserialize, Serialize};
-use serde_json;
+use std::collections::HashSet;
 use std::prelude::v1::*;
 use url::Url;
 use uuid::Uuid;
@@ -34,7 +35,16 @@ pub struct TeaclaveInputFile {
     pub url: Url,
     pub hash: String,
     pub crypto_info: TeaclaveFileCryptoInfo,
-    pub owner: String,
+    pub owner: HashSet<String>,
+    pub uuid: Uuid,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct TeaclaveOutputFile {
+    pub url: Url,
+    pub hash: Option<String>,
+    pub crypto_info: TeaclaveFileCryptoInfo,
+    pub owner: HashSet<String>,
     pub uuid: Uuid,
 }
 
@@ -43,7 +53,7 @@ impl TeaclaveInputFile {
         url: Url,
         hash: String,
         crypto_info: TeaclaveFileCryptoInfo,
-        owner: String,
+        owner: HashSet<String>,
     ) -> TeaclaveInputFile {
         TeaclaveInputFile {
             url,
@@ -53,37 +63,18 @@ impl TeaclaveInputFile {
             uuid: create_uuid(),
         }
     }
-}
-
-pub trait Storable: Serialize + for<'de> Deserialize<'de> {
-    fn key_prefix() -> &'static str;
-
-    fn uuid(&self) -> Uuid;
-
-    fn key_string(&self) -> String {
-        format!("{}-{}", Self::key_prefix(), self.uuid().to_string())
-    }
-
-    fn key(&self) -> Vec<u8> {
-        self.key_string().into_bytes()
-    }
 
-    fn match_prefix(key: &str) -> bool {
-        key.starts_with(Self::key_prefix())
-    }
-
-    fn to_vec(&self) -> anyhow::Result<Vec<u8>> {
-        let bytes = serde_json::to_vec(self)?;
-        Ok(bytes)
-    }
-
-    fn from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
-        let obj = serde_json::from_slice(bytes)?;
-        Ok(obj)
-    }
-
-    fn external_id(&self) -> String {
-        self.key_string()
+    pub fn from_output(output: TeaclaveOutputFile) -> 
Result<TeaclaveInputFile> {
+        let input = TeaclaveInputFile {
+            url: output.url,
+            hash: output
+                .hash
+                .ok_or_else(|| anyhow!("output is not finished"))?,
+            crypto_info: output.crypto_info,
+            owner: output.owner,
+            uuid: output.uuid,
+        };
+        Ok(input)
     }
 }
 
@@ -97,27 +88,12 @@ impl Storable for TeaclaveInputFile {
     }
 }
 
-impl Storable for TeaclaveOutputFile {
-    fn key_prefix() -> &'static str {
-        OUTPUT_FILE_PREFIX
-    }
-
-    fn uuid(&self) -> Uuid {
-        self.uuid
-    }
-}
-
-#[derive(Debug, Deserialize, Serialize)]
-pub struct TeaclaveOutputFile {
-    pub url: Url,
-    pub hash: Option<String>,
-    pub crypto_info: TeaclaveFileCryptoInfo,
-    pub owner: String,
-    pub uuid: Uuid,
-}
-
 impl TeaclaveOutputFile {
-    pub fn new(url: Url, crypto_info: TeaclaveFileCryptoInfo, owner: String) 
-> TeaclaveOutputFile {
+    pub fn new(
+        url: Url,
+        crypto_info: TeaclaveFileCryptoInfo,
+        owner: HashSet<String>,
+    ) -> TeaclaveOutputFile {
         TeaclaveOutputFile {
             url,
             hash: None,
@@ -126,4 +102,29 @@ impl TeaclaveOutputFile {
             uuid: create_uuid(),
         }
     }
+
+    pub fn new_fusion_data(owner: HashSet<String>) -> 
Result<TeaclaveOutputFile> {
+        let uuid = create_uuid();
+        let url = format!("fusion://path/{}?token=fusion_token", 
uuid.to_string());
+        let url = Url::parse(&url).map_err(|_| anyhow!("invalid url"))?;
+        let crypto_info = TeaclaveFileCryptoInfo::default();
+
+        Ok(TeaclaveOutputFile {
+            url,
+            hash: None,
+            crypto_info,
+            owner,
+            uuid,
+        })
+    }
+}
+
+impl Storable for TeaclaveOutputFile {
+    fn key_prefix() -> &'static str {
+        OUTPUT_FILE_PREFIX
+    }
+
+    fn uuid(&self) -> Uuid {
+        self.uuid
+    }
 }
diff --git a/types/src/function.rs b/types/src/function.rs
new file mode 100644
index 0000000..a125825
--- /dev/null
+++ b/types/src/function.rs
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::Storable;
+use serde::{Deserialize, Serialize};
+use std::prelude::v1::*;
+use uuid::Uuid;
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct FunctionInput {
+    pub name: String,
+    pub description: String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct FunctionOutput {
+    pub name: String,
+    pub description: String,
+}
+
+const FUNCION_PREFIX: &str = "function";
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Function {
+    pub function_id: Uuid,
+    pub name: String,
+    pub description: String,
+    pub payload: Vec<u8>,
+    pub is_public: bool,
+    pub arg_list: Vec<String>,
+    pub input_list: Vec<FunctionInput>,
+    pub output_list: Vec<FunctionOutput>,
+    pub owner: String,
+    pub is_native: bool,
+}
+
+impl Storable for Function {
+    fn key_prefix() -> &'static str {
+        FUNCION_PREFIX
+    }
+
+    fn uuid(&self) -> Uuid {
+        self.function_id
+    }
+}
diff --git a/types/src/lib.rs b/types/src/lib.rs
index 282014c..a459022 100644
--- a/types/src/lib.rs
+++ b/types/src/lib.rs
@@ -21,6 +21,14 @@ mod worker;
 pub use worker::*;
 mod file;
 pub use file::*;
+mod function;
+pub use function::*;
+mod staged_task;
+pub use staged_task::*;
+mod storage;
+pub use storage::Storable;
+mod task;
+pub use task::*;
 
 /// Status for Ecall
 #[repr(C)]
diff --git a/types/src/staged_task.rs b/types/src/staged_task.rs
new file mode 100644
index 0000000..3c846be
--- /dev/null
+++ b/types/src/staged_task.rs
@@ -0,0 +1,84 @@
+use crate::{Function, Storable, TeaclaveFileCryptoInfo, TeaclaveInputFile, 
TeaclaveOutputFile};
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::prelude::v1::*;
+use url::Url;
+use uuid::Uuid;
+
+const STAGED_TASK_PREFIX: &str = "staged-"; // staged-task-uuid
+pub const QUEUE_KEY: &str = "staged-task";
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct InputData {
+    pub url: Url,
+    pub hash: String,
+    pub crypto_info: TeaclaveFileCryptoInfo,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct OutputData {
+    pub url: Url,
+    pub crypto_info: TeaclaveFileCryptoInfo,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct StagedTask {
+    pub task_id: Uuid,
+    pub function_id: String,
+    pub function_payload: Vec<u8>,
+    pub arg_list: HashMap<String, String>,
+    pub input_map: HashMap<String, InputData>,
+    pub output_map: HashMap<String, OutputData>,
+}
+
+impl Storable for StagedTask {
+    fn key_prefix() -> &'static str {
+        STAGED_TASK_PREFIX
+    }
+
+    fn uuid(&self) -> Uuid {
+        self.task_id
+    }
+}
+
+impl InputData {
+    pub fn from_input_file(file: TeaclaveInputFile) -> InputData {
+        InputData {
+            url: file.url,
+            hash: file.hash,
+            crypto_info: file.crypto_info,
+        }
+    }
+}
+
+impl OutputData {
+    pub fn from_output_file(file: TeaclaveOutputFile) -> OutputData {
+        OutputData {
+            url: file.url,
+            crypto_info: file.crypto_info,
+        }
+    }
+}
+
+impl StagedTask {
+    pub fn new(
+        task_id: Uuid,
+        function: Function,
+        arg_list: HashMap<String, String>,
+        input_map: HashMap<String, InputData>,
+        output_map: HashMap<String, OutputData>,
+    ) -> Self {
+        Self {
+            task_id: task_id.to_owned(),
+            function_id: function.external_id(),
+            function_payload: function.payload,
+            arg_list,
+            input_map,
+            output_map,
+        }
+    }
+
+    pub fn get_queue_key() -> &'static str {
+        QUEUE_KEY
+    }
+}
diff --git a/types/src/storage.rs b/types/src/storage.rs
new file mode 100644
index 0000000..778681e
--- /dev/null
+++ b/types/src/storage.rs
@@ -0,0 +1,37 @@
+use anyhow;
+use serde::{Deserialize, Serialize};
+use serde_json;
+use std::prelude::v1::*;
+use uuid::Uuid;
+
+pub trait Storable: Serialize + for<'de> Deserialize<'de> {
+    fn key_prefix() -> &'static str;
+
+    fn uuid(&self) -> Uuid;
+
+    fn key_string(&self) -> String {
+        format!("{}-{}", Self::key_prefix(), self.uuid().to_string())
+    }
+
+    fn key(&self) -> Vec<u8> {
+        self.key_string().into_bytes()
+    }
+
+    fn match_prefix(key: &str) -> bool {
+        key.starts_with(Self::key_prefix())
+    }
+
+    fn to_vec(&self) -> anyhow::Result<Vec<u8>> {
+        let bytes = serde_json::to_vec(self)?;
+        Ok(bytes)
+    }
+
+    fn from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
+        let obj = serde_json::from_slice(bytes)?;
+        Ok(obj)
+    }
+
+    fn external_id(&self) -> String {
+        self.key_string()
+    }
+}
diff --git a/types/src/task.rs b/types/src/task.rs
new file mode 100644
index 0000000..013cf71
--- /dev/null
+++ b/types/src/task.rs
@@ -0,0 +1,48 @@
+use crate::Storable;
+use serde::{Deserialize, Serialize};
+use std::collections::{HashMap, HashSet};
+use std::prelude::v1::*;
+use uuid::Uuid;
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct DataOwnerList {
+    pub user_id_list: HashSet<String>,
+}
+
+#[derive(Debug, Deserialize, Serialize, std::cmp::PartialEq)]
+pub enum TaskStatus {
+    Created,
+    Ready,
+    Approved,
+    Running,
+    Failed,
+    Finished,
+}
+
+const TASK_PREFIX: &str = "task-";
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct Task {
+    pub task_id: Uuid,
+    pub creator: String,
+    pub function_id: String,
+    pub function_owner: String,
+    pub arg_list: HashMap<String, String>,
+    pub input_data_owner_list: HashMap<String, DataOwnerList>,
+    pub output_data_owner_list: HashMap<String, DataOwnerList>,
+    pub participants: HashSet<String>,
+    pub approved_user_list: HashSet<String>,
+    pub input_map: HashMap<String, String>,
+    pub output_map: HashMap<String, String>,
+    pub status: TaskStatus,
+}
+
+impl Storable for Task {
+    fn key_prefix() -> &'static str {
+        TASK_PREFIX
+    }
+
+    fn uuid(&self) -> Uuid {
+        self.task_id
+    }
+}
diff --git a/types/src/worker.rs b/types/src/worker.rs
index 16981b3..351ff09 100644
--- a/types/src/worker.rs
+++ b/types/src/worker.rs
@@ -55,13 +55,13 @@ impl std::fmt::Display for TeaclaveExecutorSelector {
 }
 
 #[derive(Debug)]
-pub struct InputData {
+pub struct WorkerInputData {
     pub path: std::path::PathBuf,
     pub hash: String,
     pub crypto_info: TeaclaveFileCryptoInfo,
 }
 #[derive(Debug)]
-pub struct OutputData {
+pub struct WorkerOutputData {
     pub path: std::path::PathBuf,
     pub hash: String,
     pub crypto_info: TeaclaveFileCryptoInfo,
@@ -157,7 +157,7 @@ pub fn read_all_bytes(path: impl AsRef<std::path::Path>) -> 
anyhow::Result<Vec<u
 }
 
 pub fn convert_encrypted_input_file(
-    src: InputData,
+    src: WorkerInputData,
     dst: &str,
 ) -> anyhow::Result<TeaclaveWorkerInputFileInfo> {
     let path = src.path;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to