[task] Wrap types for Task fields (#284)

diff --git a/services/management/enclave/src/service.rs b/services/management/enclave/src/service.rs
index 7fd767a..fd5fac1 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -38,9 +38,9 @@
 use teaclave_rpc::Request;
 use teaclave_service_enclave_utils::{ensure, teaclave_service};
 use teaclave_types::{
-    ExternalID, FileCrypto, Function, FunctionInputFile, FunctionOutputFile, OwnerList, StagedTask,
-    Storable, Task, TaskStatus, TeaclaveInputFile, TeaclaveOutputFile,
-    TeaclaveServiceResponseError, TeaclaveServiceResponseResult, UserID,
+    ExternalID, FileCrypto, Function, OwnerList, StagedTask, Storable, Task, TaskStatus,
+    TeaclaveInputFile, TeaclaveOutputFile, TeaclaveServiceResponseError,
+    TeaclaveServiceResponseResult, UserID,
 };
 use thiserror::Error;
 use url::Url;
@@ -272,8 +272,8 @@
             user_id,
             request.executor,
             request.function_arguments,
-            request.input_owners_map,
-            request.output_owners_map,
+            request.inputs_ownership,
+            request.outputs_ownership,
             function,
         )
         .map_err(|_| ServiceError::BadTask)?;
@@ -310,12 +310,12 @@
             function_id: task.function_id,
             function_owner: task.function_owner,
             function_arguments: task.function_arguments,
-            input_owners_map: task.input_owners_map,
-            output_owners_map: task.output_owners_map,
+            inputs_ownership: task.inputs_ownership,
+            outputs_ownership: task.outputs_ownership,
             participants: task.participants,
             approved_users: task.approved_users,
-            input_map: task.input_map,
-            output_map: task.output_map,
+            assigned_inputs: task.assigned_inputs.external_ids(),
+            assigned_outputs: task.assigned_outputs.external_ids(),
             result: task.result,
             status: task.status,
         };
@@ -329,7 +329,7 @@
     //    * input file: user_id == input_file.owner contains user_id
     //    * output file: output_file.owner contains user_id && output_file.cmac.is_none()
     // 4) the data can be assgined to the task:
-    //    * input_owners_map or output_owners_map contains the data name
+    //    * inputs_ownership or outputs_ownership contains the data name
     //    * input file: OwnerList match input_file.owner
     //    * output file: OwnerList match output_file.owner
     fn assign_data(
@@ -349,19 +349,19 @@
             ServiceError::PermissionDenied
         );
 
-        for (data_name, data_id) in request.input_map.iter() {
+        for (data_name, data_id) in request.inputs.iter() {
             let file: TeaclaveInputFile = self
                 .read_from_db(&data_id)
                 .map_err(|_| ServiceError::PermissionDenied)?;
-            task.assign_input(&user_id, data_name, &file)
+            task.assign_input(&user_id, data_name, file)
                 .map_err(|_| ServiceError::PermissionDenied)?;
         }
 
-        for (data_name, data_id) in request.output_map.iter() {
+        for (data_name, data_id) in request.outputs.iter() {
             let file: TeaclaveOutputFile = self
                 .read_from_db(&data_id)
                 .map_err(|_| ServiceError::PermissionDenied)?;
-            task.assign_output(&user_id, data_name, &file)
+            task.assign_output(&user_id, data_name, file)
                 .map_err(|_| ServiceError::PermissionDenied)?;
         }
 
@@ -427,26 +427,7 @@
 
         log::info!("InvokeTask: get function: {:?}", function);
 
-        let mut input_map: HashMap<String, FunctionInputFile> = HashMap::new();
-        for (data_name, data_id) in task.input_map.iter() {
-            let input_file: TeaclaveInputFile = self
-                .read_from_db(&data_id)
-                .map_err(|_| ServiceError::PermissionDenied)?;
-            let input_data = FunctionInputFile::from_teaclave_input_file(&input_file);
-            input_map.insert(data_name.to_string(), input_data);
-        }
-
-        let mut output_map: HashMap<String, FunctionOutputFile> = HashMap::new();
-        for (data_name, data_id) in task.output_map.iter() {
-            let output_file: TeaclaveOutputFile = self
-                .read_from_db(&data_id)
-                .map_err(|_| ServiceError::PermissionDenied)?;
-            ensure!(output_file.cmac.is_none(), ServiceError::PermissionDenied);
-            let output_data = FunctionOutputFile::from_teaclave_output_file(&output_file);
-            output_map.insert(data_name.to_string(), output_data);
-        }
-
-        let staged_task = task.stage_for_running(&user_id, function, input_map, output_map)?;
+        let staged_task = task.stage_for_running(&user_id, function)?;
 
         log::info!("InvokeTask: staged task: {:?}", staged_task);
 
@@ -602,7 +583,7 @@
     use std::collections::HashMap;
     use teaclave_types::{
         hashmap, Executor, FileAuthTag, FileCrypto, FunctionArguments, FunctionInput,
-        FunctionOutput,
+        FunctionInputFile, FunctionOutput, FunctionOutputFile,
     };
     use url::Url;
 
diff --git a/services/proto/src/proto/teaclave_frontend_service.proto b/services/proto/src/proto/teaclave_frontend_service.proto
index 3957b1e..6a3dcb3 100644
--- a/services/proto/src/proto/teaclave_frontend_service.proto
+++ b/services/proto/src/proto/teaclave_frontend_service.proto
@@ -112,8 +112,8 @@
   string function_id = 1;
   map<string, string> function_arguments = 2;
   string executor = 3;
-  repeated OwnerList input_owners_map = 10;
-  repeated OwnerList output_owners_map = 11;
+  repeated OwnerList inputs_ownership = 10;
+  repeated OwnerList outputs_ownership= 11;
 }
 
 message CreateTaskResponse {
@@ -130,20 +130,20 @@
   string function_id = 3;
   string function_owner = 4;
   map<string, string> function_arguments = 5;
-  repeated OwnerList input_owners_map = 6;
-  repeated OwnerList output_owners_map = 7;
+  repeated OwnerList inputs_ownership = 6;
+  repeated OwnerList outputs_ownership = 7;
   repeated string participants = 8;
   repeated string approved_users = 9;
-  repeated DataMap input_map = 10;
-  repeated DataMap output_map = 11;
+  repeated DataMap assigned_inputs = 10;
+  repeated DataMap assigned_outputs = 11;
   teaclave_common_proto.TaskStatus status = 20;
   teaclave_common_proto.TaskResult result = 21;
 }
 
 message AssignDataRequest {
   string task_id = 1;
-  repeated DataMap input_map = 2;
-  repeated DataMap output_map = 3;
+  repeated DataMap inputs = 2;
+  repeated DataMap outputs = 3;
 }
 
 message AssignDataResponse { }
diff --git a/services/proto/src/teaclave_frontend_service.rs b/services/proto/src/teaclave_frontend_service.rs
index 9ca53ff..cf36589 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -27,7 +27,8 @@
 use teaclave_rpc::into_request;
 use teaclave_types::{
     Executor, ExecutorType, ExternalID, FileAuthTag, FileCrypto, Function, FunctionArguments,
-    FunctionInput, FunctionOutput, OwnerList, TaskResult, TaskStatus, UserID, UserList,
+    FunctionInput, FunctionOutput, OwnerList, TaskFileOwners, TaskResult, TaskStatus, UserID,
+    UserList,
 };
 use url::Url;
 use uuid::Uuid;
@@ -342,8 +343,8 @@
     pub function_id: ExternalID,
     pub function_arguments: FunctionArguments,
     pub executor: Executor,
-    pub input_owners_map: HashMap<String, OwnerList>,
-    pub output_owners_map: HashMap<String, OwnerList>,
+    pub inputs_ownership: TaskFileOwners,
+    pub outputs_ownership: TaskFileOwners,
 }
 
 impl CreateTaskRequest {
@@ -372,16 +373,16 @@
         }
     }
 
-    pub fn input_owners_map(self, map: HashMap<String, OwnerList>) -> Self {
+    pub fn inputs_ownership(self, map: impl Into<TaskFileOwners>) -> Self {
         Self {
-            input_owners_map: map,
+            inputs_ownership: map.into(),
             ..self
         }
     }
 
-    pub fn output_owners_map(self, map: HashMap<String, OwnerList>) -> Self {
+    pub fn outputs_ownership(self, map: impl Into<TaskFileOwners>) -> Self {
         Self {
-            output_owners_map: map,
+            outputs_ownership: map.into(),
             ..self
         }
     }
@@ -420,12 +421,12 @@
     pub function_id: ExternalID,
     pub function_owner: UserID,
     pub function_arguments: FunctionArguments,
-    pub input_owners_map: HashMap<String, OwnerList>,
-    pub output_owners_map: HashMap<String, OwnerList>,
+    pub inputs_ownership: TaskFileOwners,
+    pub outputs_ownership: TaskFileOwners,
     pub participants: UserList,
     pub approved_users: UserList,
-    pub input_map: HashMap<String, ExternalID>,
-    pub output_map: HashMap<String, ExternalID>,
+    pub assigned_inputs: HashMap<String, ExternalID>,
+    pub assigned_outputs: HashMap<String, ExternalID>,
     pub status: TaskStatus,
     pub result: TaskResult,
 }
@@ -435,20 +436,20 @@
 #[derive(Debug)]
 pub struct AssignDataRequest {
     pub task_id: ExternalID,
-    pub input_map: HashMap<String, ExternalID>,
-    pub output_map: HashMap<String, ExternalID>,
+    pub inputs: HashMap<String, ExternalID>,
+    pub outputs: HashMap<String, ExternalID>,
 }
 
 impl AssignDataRequest {
     pub fn new(
         task_id: ExternalID,
-        input_map: HashMap<String, ExternalID>,
-        output_map: HashMap<String, ExternalID>,
+        inputs: HashMap<String, ExternalID>,
+        outputs: HashMap<String, ExternalID>,
     ) -> Self {
         Self {
             task_id,
-            input_map,
-            output_map,
+            inputs,
+            outputs,
         }
     }
 }
@@ -936,29 +937,21 @@
     }
 }
 
-pub fn data_owner_map_from_proto(
-    vector: Vec<proto::OwnerList>,
-) -> Result<HashMap<String, OwnerList>> {
-    let mut ret = HashMap::with_capacity(vector.len());
-    for item in vector.into_iter() {
-        let owner_list = item.uids.into();
-        ret.insert(item.data_name, owner_list);
-    }
-    Ok(ret)
+fn from_proto_ownership(proto: Vec<proto::OwnerList>) -> TaskFileOwners {
+    proto
+        .into_iter()
+        .map(|ol| (ol.data_name, ol.uids))
+        .collect()
 }
 
-pub fn data_owner_map_to_proto<S: std::hash::BuildHasher>(
-    map: HashMap<String, OwnerList, S>,
-) -> Vec<proto::OwnerList> {
-    let mut ret = Vec::with_capacity(map.len());
-    for (data_name, owner_list) in map.into_iter() {
-        let owner_list = proto::OwnerList {
-            data_name,
-            uids: owner_list.into(),
-        };
-        ret.push(owner_list);
-    }
-    ret
+fn to_proto_ownership(ownership: TaskFileOwners) -> Vec<proto::OwnerList> {
+    ownership
+        .into_iter()
+        .map(|(name, ol)| proto::OwnerList {
+            data_name: name,
+            uids: ol.into(),
+        })
+        .collect()
 }
 
 impl std::convert::TryFrom<proto::CreateTaskRequest> for CreateTaskRequest {
@@ -966,8 +959,8 @@
 
     fn try_from(proto: proto::CreateTaskRequest) -> Result<Self> {
         let function_arguments = proto.function_arguments.into();
-        let input_owners_map = data_owner_map_from_proto(proto.input_owners_map)?;
-        let output_owners_map = data_owner_map_from_proto(proto.output_owners_map)?;
+        let inputs_ownership = from_proto_ownership(proto.inputs_ownership);
+        let outputs_ownership = from_proto_ownership(proto.outputs_ownership);
         let function_id = proto.function_id.try_into()?;
         let executor = proto.executor.try_into()?;
 
@@ -975,8 +968,8 @@
             function_id,
             function_arguments,
             executor,
-            input_owners_map,
-            output_owners_map,
+            inputs_ownership,
+            outputs_ownership,
         };
         Ok(ret)
     }
@@ -985,15 +978,15 @@
 impl From<CreateTaskRequest> for proto::CreateTaskRequest {
     fn from(request: CreateTaskRequest) -> Self {
         let function_arguments = request.function_arguments.into();
-        let input_owners_map = data_owner_map_to_proto(request.input_owners_map);
-        let output_owners_map = data_owner_map_to_proto(request.output_owners_map);
+        let inputs_ownership = to_proto_ownership(request.inputs_ownership);
+        let outputs_ownership = to_proto_ownership(request.outputs_ownership);
 
         Self {
             function_id: request.function_id.to_string(),
             function_arguments,
             executor: request.executor.to_string(),
-            input_owners_map,
-            output_owners_map,
+            inputs_ownership,
+            outputs_ownership,
         }
     }
 }
@@ -1017,25 +1010,25 @@
     }
 }
 
-fn data_map_to_proto(map: HashMap<String, ExternalID>) -> 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: data_id.to_string(),
-        };
-        ret.push(data_map);
-    }
-    ret
+fn to_proto_file_ids(map: HashMap<String, ExternalID>) -> Vec<proto::DataMap> {
+    map.into_iter()
+        .map(|(name, ext_id)| proto::DataMap {
+            data_name: name,
+            data_id: ext_id.to_string(),
+        })
+        .collect()
 }
 
-fn data_map_from_proto(vector: Vec<proto::DataMap>) -> Result<HashMap<String, ExternalID>> {
-    let mut ret = HashMap::with_capacity(vector.len());
-    for item in vector.into_iter() {
-        let data_id = item.data_id.try_into()?;
-        ret.insert(item.data_name, data_id);
-    }
-    Ok(ret)
+fn from_proto_file_ids(vector: Vec<proto::DataMap>) -> Result<HashMap<String, ExternalID>> {
+    vector
+        .into_iter()
+        .map(|item| {
+            item.data_id
+                .clone()
+                .try_into()
+                .map(|ext_id| (item.data_name, ext_id))
+        })
+        .collect()
 }
 
 impl std::convert::TryFrom<proto::GetTaskRequest> for GetTaskRequest {
@@ -1062,10 +1055,10 @@
 
     fn try_from(proto: proto::GetTaskResponse) -> Result<Self> {
         let function_arguments = proto.function_arguments.into();
-        let input_owners_map = data_owner_map_from_proto(proto.input_owners_map)?;
-        let output_owners_map = data_owner_map_from_proto(proto.output_owners_map)?;
-        let input_map = data_map_from_proto(proto.input_map)?;
-        let output_map = data_map_from_proto(proto.output_map)?;
+        let inputs_ownership = from_proto_ownership(proto.inputs_ownership);
+        let outputs_ownership = from_proto_ownership(proto.outputs_ownership);
+        let assigned_inputs = from_proto_file_ids(proto.assigned_inputs)?;
+        let assigned_outputs = from_proto_file_ids(proto.assigned_outputs)?;
         let status = i32_to_task_status(proto.status)?;
         let function_id = proto.function_id.try_into()?;
         let task_id = proto.task_id.try_into()?;
@@ -1077,12 +1070,12 @@
             function_id,
             function_owner: proto.function_owner.into(),
             function_arguments,
-            input_owners_map,
-            output_owners_map,
+            inputs_ownership,
+            outputs_ownership,
             participants: UserList::new(proto.participants),
             approved_users: UserList::new(proto.approved_users),
-            input_map,
-            output_map,
+            assigned_inputs,
+            assigned_outputs,
             status,
             result,
         };
@@ -1094,10 +1087,10 @@
 impl From<GetTaskResponse> for proto::GetTaskResponse {
     fn from(response: GetTaskResponse) -> Self {
         let function_arguments = response.function_arguments.into();
-        let input_owners_map = data_owner_map_to_proto(response.input_owners_map);
-        let output_owners_map = data_owner_map_to_proto(response.output_owners_map);
-        let input_map = data_map_to_proto(response.input_map);
-        let output_map = data_map_to_proto(response.output_map);
+        let inputs_ownership = to_proto_ownership(response.inputs_ownership);
+        let outputs_ownership = to_proto_ownership(response.outputs_ownership);
+        let assigned_inputs = to_proto_file_ids(response.assigned_inputs);
+        let assigned_outputs = to_proto_file_ids(response.assigned_outputs);
         let status = i32_from_task_status(response.status);
         Self {
             task_id: response.task_id.to_string(),
@@ -1105,12 +1098,12 @@
             function_id: response.function_id.to_string(),
             function_owner: response.function_owner.to_string(),
             function_arguments,
-            input_owners_map,
-            output_owners_map,
+            inputs_ownership,
+            outputs_ownership,
             participants: response.participants.into(),
             approved_users: response.approved_users.into(),
-            input_map,
-            output_map,
+            assigned_inputs,
+            assigned_outputs,
             status,
             result: Some(response.result.into()),
         }
@@ -1121,13 +1114,13 @@
     type Error = Error;
 
     fn try_from(proto: proto::AssignDataRequest) -> Result<Self> {
-        let input_map = data_map_from_proto(proto.input_map)?;
-        let output_map = data_map_from_proto(proto.output_map)?;
+        let inputs = from_proto_file_ids(proto.inputs)?;
+        let outputs = from_proto_file_ids(proto.outputs)?;
         let task_id = proto.task_id.try_into()?;
         let ret = Self {
             task_id,
-            input_map,
-            output_map,
+            inputs,
+            outputs,
         };
 
         Ok(ret)
@@ -1136,12 +1129,12 @@
 
 impl From<AssignDataRequest> for proto::AssignDataRequest {
     fn from(request: AssignDataRequest) -> Self {
-        let input_map = data_map_to_proto(request.input_map);
-        let output_map = data_map_to_proto(request.output_map);
+        let inputs = to_proto_file_ids(request.inputs);
+        let outputs = to_proto_file_ids(request.outputs);
         Self {
             task_id: request.task_id.to_string(),
-            input_map,
-            output_map,
+            inputs,
+            outputs,
         }
     }
 }
diff --git a/services/scheduler/enclave/src/service.rs b/services/scheduler/enclave/src/service.rs
index fd8a438..01a88c9 100644
--- a/services/scheduler/enclave/src/service.rs
+++ b/services/scheduler/enclave/src/service.rs
@@ -30,7 +30,7 @@
 use teaclave_rpc::Request;
 use teaclave_service_enclave_utils::teaclave_service;
 use teaclave_types::{
-    ExternalID, OutputsTags, StagedTask, Storable, Task, TaskResult, TaskStatus,
+    ExternalID, OutputsTags, StagedTask, Storable, Task, TaskFiles, TaskResult, TaskStatus,
     TeaclaveOutputFile, TeaclaveServiceResponseError, TeaclaveServiceResponseResult,
 };
 use uuid::Uuid;
@@ -127,26 +127,6 @@
             .put(put_request)?;
         Ok(())
     }
-
-    fn update_outputs_cmac(
-        &self,
-        task_output_map: &HashMap<String, ExternalID>,
-        tags_map: &OutputsTags,
-    ) -> Result<()> {
-        anyhow::ensure!(
-            task_output_map.len() == tags_map.len(),
-            "Error: task result output tags count"
-        );
-        for (key, id) in task_output_map.iter() {
-            let mut outfile: TeaclaveOutputFile = self.get_from_db(id)?;
-            let auth_tag = tags_map
-                .get(key)
-                .ok_or_else(|| anyhow::anyhow!("Missing result in task result outpt tags"))?;
-            outfile.assign_cmac(auth_tag)?;
-            self.put_into_db(&outfile)?;
-        }
-        Ok(())
-    }
 }
 
 impl TeaclaveScheduler for TeaclaveSchedulerService {
@@ -207,7 +187,10 @@
         let mut task = self.get_task(&request.task_id)?;
 
         if let TaskResult::Ok(outputs) = &request.task_result {
-            self.update_outputs_cmac(&task.output_map, &outputs.tags_map)?;
+            for (key, auth_tag) in outputs.tags_map.iter() {
+                let outfile = task.assigned_outputs.update_cmac(key, auth_tag)?;
+                self.put_into_db(outfile)?;
+            }
         };
 
         // Updating task result means we have finished execution
diff --git a/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs b/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
index 86258ee..2eae2bf 100644
--- a/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
+++ b/tests/functional/enclave/src/end_to_end/builtin_gbdt_train.rs
@@ -117,8 +117,8 @@
             "loss"                  => "LAD",
             "training_optimization_level" => "2"
         ))
-        .input_owners_map(hashmap!("training_data" => vec![USERNAME]))
-        .output_owners_map(hashmap!("trained_model" => vec![USERNAME]));
+        .inputs_ownership(hashmap!("training_data" => vec![USERNAME]))
+        .outputs_ownership(hashmap!("trained_model" => vec![USERNAME]));
 
     let response = client.create_task(request).unwrap();
     log::info!("Create task: {:?}", response);
diff --git a/tests/functional/enclave/src/end_to_end/mesapy_data_fusion.rs b/tests/functional/enclave/src/end_to_end/mesapy_data_fusion.rs
index 327ffd5..0630ef5 100644
--- a/tests/functional/enclave/src/end_to_end/mesapy_data_fusion.rs
+++ b/tests/functional/enclave/src/end_to_end/mesapy_data_fusion.rs
@@ -97,11 +97,11 @@
 ) -> ExternalID {
     let request = CreateTaskRequest::new()
         .function_id(function_id.to_owned())
-        .input_owners_map(hashmap!(
+        .inputs_ownership(hashmap!(
             "InPartyA" => vec![USERNAME1],
             "InPartyB" => vec![USERNAME2]
         ))
-        .output_owners_map(hashmap!("OutFusionData" => vec![USERNAME1, USERNAME2]))
+        .outputs_ownership(hashmap!("OutFusionData" => vec![USERNAME1, USERNAME2]))
         .executor(Executor::MesaPy);
     let response = client.create_task(request).unwrap();
     log::info!("Create task: {:?}", response);
@@ -175,8 +175,8 @@
     let task = get_task(&mut c2, &task_id);
     assert!(task.status == TaskStatus::Finished);
 
-    let fusion_id = task.output_map.get("OutFusionData").unwrap();
-    let fusion_owners = task.output_owners_map.get("OutFusionData").unwrap();
+    let fusion_id = task.assigned_outputs.get("OutFusionData").unwrap();
+    let fusion_owners = task.outputs_ownership.get("OutFusionData").unwrap();
 
     let fusion_input = register_fusion_input_from_output(&mut c2, &fusion_id);
     let function_id = register_word_count_function(&mut c2);
@@ -251,7 +251,7 @@
     let request = CreateTaskRequest::new()
         .function_id(function_id.to_owned())
         .function_arguments(hashmap!("query" => "teaclave"))
-        .input_owners_map(hashmap!(
+        .inputs_ownership(hashmap!(
             "InputData" => owners.to_owned()
         ))
         .executor(Executor::MesaPy);
diff --git a/tests/functional/enclave/src/frontend_service.rs b/tests/functional/enclave/src/frontend_service.rs
index 1508c6d..9ec42bf 100644
--- a/tests/functional/enclave/src/frontend_service.rs
+++ b/tests/functional/enclave/src/frontend_service.rs
@@ -163,7 +163,7 @@
         .function_id(function_id.clone())
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" =>  vec!["frontend_user", "mock_user"]));
+        .outputs_ownership(hashmap!("output" =>  vec!["frontend_user", "mock_user"]));
     let response = authorized_client().create_task(request);
     assert!(response.is_ok());
 
@@ -171,7 +171,7 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" => vec!["frontend_user", "mock_user"]));
+        .outputs_ownership(hashmap!("output" => vec!["frontend_user", "mock_user"]));
     let response = unauthorized_client().create_task(request);
     assert!(response.is_err());
 }
@@ -186,7 +186,7 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" => vec!["frontend_user", "mock_user"]));
+        .outputs_ownership(hashmap!("output" => vec!["frontend_user", "mock_user"]));
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
@@ -212,7 +212,7 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" => vec!["frontend_user"]));
+        .outputs_ownership(hashmap!("output" => vec!["frontend_user"]));
 
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
@@ -247,7 +247,7 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" => vec!["frontend_user"]));
+        .outputs_ownership(hashmap!("output" => vec!["frontend_user"]));
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
@@ -281,7 +281,7 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "arg1_value"))
         .executor(Executor::MesaPy)
-        .output_owners_map(hashmap!("output" => vec!["frontend_user"]));
+        .outputs_ownership(hashmap!("output" => vec!["frontend_user"]));
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
diff --git a/tests/functional/enclave/src/management_service.rs b/tests/functional/enclave/src/management_service.rs
index acb0482..cc95f7f 100644
--- a/tests/functional/enclave/src/management_service.rs
+++ b/tests/functional/enclave/src/management_service.rs
@@ -175,7 +175,7 @@
     assert!(response.is_ok());
 }
 
-fn valid_create_task_request() -> CreateTaskRequest {
+fn create_valid_task_request() -> CreateTaskRequest {
     let function_id =
         ExternalID::try_from("function-00000000-0000-0000-0000-000000000001").unwrap();
     let input_owners = hashmap!(
@@ -191,8 +191,8 @@
         .function_id(function_id)
         .function_arguments(hashmap!("arg1" => "data1", "arg2" => "data2"))
         .executor(Executor::MesaPy)
-        .input_owners_map(input_owners)
-        .output_owners_map(output_owners)
+        .inputs_ownership(input_owners)
+        .outputs_ownership(output_owners)
 }
 
 #[test_case]
@@ -203,22 +203,26 @@
     let response = client.create_task(request);
     assert!(response.is_err());
 
-    let request = valid_create_task_request();
+    let request = create_valid_task_request();
     let response = client.create_task(request);
     assert!(response.is_ok());
 
-    let mut request = valid_create_task_request();
+    let mut request = create_valid_task_request();
     request.function_arguments.inner_mut().remove("arg1");
     let response = client.create_task(request);
     assert!(response.is_err());
 
-    let mut request = valid_create_task_request();
-    request.input_owners_map.remove("input");
+    let mut request = create_valid_task_request();
+    request = request.inputs_ownership(hashmap!(
+        "input2" => vec!["mock_user2", "mock_user3"]
+    ));
     let response = client.create_task(request);
     assert!(response.is_err());
 
-    let mut request = valid_create_task_request();
-    request.output_owners_map.remove("output");
+    let mut request = create_valid_task_request();
+    request = request.outputs_ownership(hashmap!(
+            "output2" => vec!["mock_user2", "mock_user3"]
+    ));
     let response = client.create_task(request);
     assert!(response.is_err());
 }
@@ -227,7 +231,7 @@
 fn test_get_task() {
     let mut client = authorized_client("mock_user");
 
-    let request = valid_create_task_request();
+    let request = create_valid_task_request();
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
@@ -247,7 +251,7 @@
     let mut client1 = authorized_client("mock_user1");
     let mut client2 = authorized_client("mock_user2");
     let mut client3 = authorized_client("mock_user3");
-    let request = valid_create_task_request();
+    let request = create_valid_task_request();
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
@@ -312,7 +316,7 @@
     let response = client1.assign_data(request);
     assert!(response.is_err());
 
-    // input_owners_map doesn't contain the name
+    // inputs_ownership doesn't contain the name
     let request = AssignDataRequest::new(
         task_id.clone(),
         hashmap!("none" => input_file_id_user2.clone()),
@@ -321,7 +325,7 @@
     let response = client2.assign_data(request);
     assert!(response.is_err());
 
-    // output_owners_map doesn't contain the name
+    // outputs_ownership doesn't contain the name
     let request = AssignDataRequest::new(
         task_id.clone(),
         hashmap!(),
@@ -422,7 +426,7 @@
     let mut client1 = authorized_client("mock_user1");
     let mut client2 = authorized_client("mock_user2");
     let mut client3 = authorized_client("mock_user3");
-    let request = valid_create_task_request();
+    let request = create_valid_task_request();
     let response = client.create_task(request).unwrap();
     let task_id = response.task_id;
 
@@ -506,7 +510,7 @@
     let mut client1 = authorized_client("mock_user1");
     let mut client2 = authorized_client("mock_user2");
     let mut client3 = authorized_client("mock_user3");
-    let request = valid_create_task_request();
+    let request = create_valid_task_request();
     let response = client.create_task(request);
     assert!(response.is_ok());
     let task_id = response.unwrap().task_id;
diff --git a/types/src/file.rs b/types/src/file.rs
index c2185a1..370b399 100644
--- a/types/src/file.rs
+++ b/types/src/file.rs
@@ -30,7 +30,7 @@
     Uuid::new_v4()
 }
 
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct TeaclaveInputFile {
     pub url: Url,
     pub cmac: FileAuthTag,
@@ -39,7 +39,7 @@
     pub uuid: Uuid,
 }
 
-#[derive(Debug, Deserialize, Serialize)]
+#[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct TeaclaveOutputFile {
     pub url: Url,
     pub cmac: Option<FileAuthTag>,
diff --git a/types/src/staged_task.rs b/types/src/staged_task.rs
index 71369c8..6cb930c 100644
--- a/types/src/staged_task.rs
+++ b/types/src/staged_task.rs
@@ -54,9 +54,20 @@
     }
 }
 
+impl<V> std::iter::FromIterator<(String, V)> for FunctionInputFiles
+where
+    V: Into<FunctionInputFile>,
+{
+    fn from_iter<T: IntoIterator<Item = (String, V)>>(iter: T) -> Self {
+        FunctionInputFiles {
+            inner: iter.into_iter().map(|(k, v)| (k, v.into())).collect(),
+        }
+    }
+}
+
 impl std::convert::From<HashMap<String, FunctionInputFile>> for FunctionInputFiles {
     fn from(entries: HashMap<String, FunctionInputFile>) -> FunctionInputFiles {
-        FunctionInputFiles { inner: entries }
+        entries.into_iter().collect()
     }
 }
 
@@ -74,6 +85,23 @@
     }
 }
 
+impl<V> std::iter::FromIterator<(String, V)> for FunctionOutputFiles
+where
+    V: Into<FunctionOutputFile>,
+{
+    fn from_iter<T: IntoIterator<Item = (String, V)>>(iter: T) -> Self {
+        FunctionOutputFiles {
+            inner: iter.into_iter().map(|(k, v)| (k, v.into())).collect(),
+        }
+    }
+}
+
+impl std::convert::From<HashMap<String, FunctionOutputFile>> for FunctionOutputFiles {
+    fn from(entries: HashMap<String, FunctionOutputFile>) -> FunctionOutputFiles {
+        entries.into_iter().collect()
+    }
+}
+
 impl FunctionOutputFiles {
     pub fn new(entries: HashMap<String, FunctionOutputFile>) -> Self {
         entries.into()
@@ -96,12 +124,6 @@
     }
 }
 
-impl std::convert::From<HashMap<String, FunctionOutputFile>> for FunctionOutputFiles {
-    fn from(entries: HashMap<String, FunctionOutputFile>) -> FunctionOutputFiles {
-        FunctionOutputFiles { inner: entries }
-    }
-}
-
 #[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct FunctionInputFile {
     pub url: Url,
@@ -117,11 +139,13 @@
             crypto_info: crypto.into(),
         }
     }
+}
 
-    pub fn from_teaclave_input_file(file: &TeaclaveInputFile) -> Self {
+impl From<TeaclaveInputFile> for FunctionInputFile {
+    fn from(file: TeaclaveInputFile) -> Self {
         Self {
-            url: file.url.to_owned(),
-            cmac: file.cmac.to_owned(),
+            url: file.url,
+            cmac: file.cmac,
             crypto_info: file.crypto_info,
         }
     }
@@ -140,10 +164,12 @@
             crypto_info: crypto.into(),
         }
     }
+}
 
-    pub fn from_teaclave_output_file(file: &TeaclaveOutputFile) -> Self {
+impl From<TeaclaveOutputFile> for FunctionOutputFile {
+    fn from(file: TeaclaveOutputFile) -> Self {
         Self {
-            url: file.url.to_owned(),
+            url: file.url,
             crypto_info: file.crypto_info,
         }
     }
diff --git a/types/src/task.rs b/types/src/task.rs
index 6061d38..eb24b5c 100644
--- a/types/src/task.rs
+++ b/types/src/task.rs
@@ -350,6 +350,153 @@
     }
 }
 
+#[derive(Debug, Default, Deserialize, Serialize)]
+pub struct TaskFileOwners {
+    inner: HashMap<String, OwnerList>,
+}
+
+impl TaskFileOwners {
+    pub fn all_owners(&self) -> OwnerList {
+        OwnerList::unions(self.inner.values().cloned())
+    }
+
+    pub fn keys(&self) -> std::collections::hash_map::Keys<String, OwnerList> {
+        self.inner.keys()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.inner.is_empty()
+    }
+
+    pub fn get(&self, key: &str) -> Option<&OwnerList> {
+        self.inner.get(key)
+    }
+
+    pub fn check(&self, fkey: &str, fowners: &OwnerList) -> Result<()> {
+        match self.inner.get(fkey) {
+            Some(owner_list) => {
+                ensure!(
+                    owner_list == fowners,
+                    "Assign: file ownership mismatch. {:?}",
+                    fkey
+                );
+            }
+            None => bail!("Assign: file name not exist in ownership spec. {:?}", fkey),
+        };
+        Ok(())
+    }
+}
+
+impl<V> std::iter::FromIterator<(String, V)> for TaskFileOwners
+where
+    V: Into<OwnerList>,
+{
+    fn from_iter<T: IntoIterator<Item = (String, V)>>(iter: T) -> Self {
+        TaskFileOwners {
+            inner: HashMap::from_iter(iter.into_iter().map(|(k, v)| (k, v.into()))),
+        }
+    }
+}
+
+impl IntoIterator for TaskFileOwners {
+    type Item = (String, OwnerList);
+    type IntoIter = std::collections::hash_map::IntoIter<String, OwnerList>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.inner.into_iter()
+    }
+}
+
+impl std::convert::From<HashMap<String, OwnerList>> for TaskFileOwners {
+    fn from(input: HashMap<String, OwnerList>) -> Self {
+        input.into_iter().collect()
+    }
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct TaskFiles<T: Clone> {
+    inner: HashMap<String, T>,
+}
+
+impl<T> Default for TaskFiles<T>
+where
+    T: Clone,
+{
+    fn default() -> TaskFiles<T> {
+        TaskFiles::<T> {
+            inner: HashMap::new(),
+        }
+    }
+}
+
+impl<T> TaskFiles<T>
+where
+    T: Clone + Storable,
+{
+    pub fn assign(&mut self, fname: &str, file: T) -> Result<()> {
+        ensure!(
+            self.inner.get(fname).is_none(),
+            "Assign: file already assigned. {:?}",
+            fname
+        );
+        self.inner.insert(fname.to_owned(), file);
+        Ok(())
+    }
+
+    pub fn keys(&self) -> std::collections::hash_map::Keys<String, T> {
+        self.inner.keys()
+    }
+
+    pub fn external_ids(&self) -> HashMap<String, ExternalID> {
+        self.inner
+            .iter()
+            .map(|(fname, file)| (fname.to_string(), file.external_id()))
+            .collect()
+    }
+}
+
+impl TaskFiles<TeaclaveOutputFile> {
+    pub fn update_cmac(
+        &mut self,
+        fname: &str,
+        auth_tag: &FileAuthTag,
+    ) -> Result<&TeaclaveOutputFile> {
+        let file = match self.inner.get_mut(fname) {
+            Some(file) => {
+                file.assign_cmac(auth_tag)?;
+                file
+            }
+            _ => bail!("Upadate_cmac: file not found. {:?}", fname),
+        };
+
+        Ok(file)
+    }
+}
+
+impl<T> IntoIterator for TaskFiles<T>
+where
+    T: Clone,
+{
+    type Item = (String, T);
+    type IntoIter = std::collections::hash_map::IntoIter<String, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.inner.into_iter()
+    }
+}
+
+impl std::convert::From<TaskFiles<TeaclaveInputFile>> for FunctionInputFiles {
+    fn from(files: TaskFiles<TeaclaveInputFile>) -> Self {
+        files.into_iter().collect()
+    }
+}
+
+impl std::convert::From<TaskFiles<TeaclaveOutputFile>> for FunctionOutputFiles {
+    fn from(files: TaskFiles<TeaclaveOutputFile>) -> Self {
+        files.into_iter().collect()
+    }
+}
+
 const TASK_PREFIX: &str = "task";
 
 #[derive(Debug, Default, Deserialize, Serialize)]
@@ -359,13 +506,13 @@
     pub function_id: ExternalID,
     pub function_arguments: FunctionArguments,
     pub executor: Executor,
-    pub input_owners_map: HashMap<String, OwnerList>,
-    pub output_owners_map: HashMap<String, OwnerList>,
+    pub inputs_ownership: TaskFileOwners,
+    pub outputs_ownership: TaskFileOwners,
     pub function_owner: UserID,
     pub participants: UserList,
     pub approved_users: UserList,
-    pub input_map: HashMap<String, ExternalID>,
-    pub output_map: HashMap<String, ExternalID>,
+    pub assigned_inputs: TaskFiles<TeaclaveInputFile>,
+    pub assigned_outputs: TaskFiles<TeaclaveOutputFile>,
     pub result: TaskResult,
     pub status: TaskStatus,
 }
@@ -385,13 +532,16 @@
         requester: UserID,
         req_executor: Executor,
         req_func_args: FunctionArguments,
-        req_input_owners: HashMap<String, OwnerList>,
-        req_output_owners: HashMap<String, OwnerList>,
+        req_input_owners: impl Into<TaskFileOwners>,
+        req_output_owners: impl Into<TaskFileOwners>,
         function: Function,
     ) -> Result<Self> {
+        let req_input_owners = req_input_owners.into();
+        let req_output_owners = req_output_owners.into();
+
         // gather all participants
-        let input_owners = UserList::unions(req_input_owners.values().cloned());
-        let output_owners = UserList::unions(req_output_owners.values().cloned());
+        let input_owners = req_input_owners.all_owners();
+        let output_owners = req_output_owners.all_owners();
         let mut participants = UserList::unions(vec![input_owners, output_owners]);
         participants.insert(requester.clone());
         if !function.public {
@@ -427,8 +577,8 @@
             function_id: function.external_id(),
             function_owner: function.owner.clone(),
             function_arguments: req_func_args,
-            input_owners_map: req_input_owners,
-            output_owners_map: req_output_owners,
+            inputs_ownership: req_input_owners,
+            outputs_ownership: req_output_owners,
             participants,
             status,
             ..Default::default()
@@ -483,8 +633,6 @@
         &mut self,
         requester: &UserID,
         function: Function,
-        input_map: HashMap<String, FunctionInputFile>,
-        output_map: HashMap<String, FunctionOutputFile>,
     ) -> Result<StagedTask> {
         ensure!(
             &self.creator == requester,
@@ -505,8 +653,8 @@
             function_name: function.name,
             function_payload: function.payload,
             function_arguments,
-            input_data: input_map.into(),
-            output_data: output_map.into(),
+            input_data: self.assigned_inputs.clone().into(),
+            output_data: self.assigned_outputs.clone().into(),
         };
 
         self.update_status(TaskStatus::Staged);
@@ -517,7 +665,7 @@
         &mut self,
         requester: &UserID,
         fname: &str,
-        file: &TeaclaveInputFile,
+        file: TeaclaveInputFile,
     ) -> Result<()> {
         ensure!(
             self.status == TaskStatus::Created,
@@ -531,27 +679,9 @@
             file.external_id()
         );
 
-        match self.input_owners_map.get(fname) {
-            Some(owner_list) => {
-                ensure!(
-                    owner_list == &file.owner,
-                    "Assign: file ownership mismatch. {:?}",
-                    file.external_id()
-                );
-            }
-            None => bail!(
-                "Assign: file name not exist in input_owners_map. {:?}",
-                fname
-            ),
-        };
+        self.inputs_ownership.check(fname, &file.owner)?;
 
-        ensure!(
-            self.input_map.get(fname).is_none(),
-            "Assign: file already assigned. {:?}",
-            fname
-        );
-
-        self.input_map.insert(fname.to_owned(), file.external_id());
+        self.assigned_inputs.assign(fname, file)?;
 
         if self.all_data_assigned() {
             self.update_status(TaskStatus::DataAssigned);
@@ -563,7 +693,7 @@
         &mut self,
         requester: &UserID,
         fname: &str,
-        file: &TeaclaveOutputFile,
+        file: TeaclaveOutputFile,
     ) -> Result<()> {
         ensure!(
             self.status == TaskStatus::Created,
@@ -577,27 +707,9 @@
             file.external_id()
         );
 
-        match self.output_owners_map.get(fname) {
-            Some(owner_list) => {
-                ensure!(
-                    owner_list == &file.owner,
-                    "Assign: file ownership mismatch. {:?}",
-                    file.external_id()
-                );
-            }
-            None => bail!(
-                "Assign: file name not exist in output_owners_map. {:?}",
-                fname
-            ),
-        };
+        self.outputs_ownership.check(fname, &file.owner)?;
 
-        ensure!(
-            self.output_map.get(fname).is_none(),
-            "Assign: file already assigned. {:?}",
-            fname
-        );
-
-        self.output_map.insert(fname.to_owned(), file.external_id());
+        self.assigned_outputs.assign(fname, file)?;
 
         if self.all_data_assigned() {
             self.update_status(TaskStatus::DataAssigned);
@@ -610,14 +722,14 @@
     }
 
     fn all_data_assigned(&self) -> bool {
-        let input_args: HashSet<&String> = self.input_owners_map.keys().collect();
-        let assiged_inputs: HashSet<&String> = self.input_map.keys().collect();
+        let input_args: HashSet<&String> = self.inputs_ownership.keys().collect();
+        let assiged_inputs: HashSet<&String> = self.assigned_inputs.keys().collect();
         if input_args != assiged_inputs {
             return false;
         }
 
-        let output_args: HashSet<&String> = self.output_owners_map.keys().collect();
-        let assiged_outputs: HashSet<&String> = self.output_map.keys().collect();
+        let output_args: HashSet<&String> = self.outputs_ownership.keys().collect();
+        let assiged_outputs: HashSet<&String> = self.assigned_outputs.keys().collect();
         if output_args != assiged_outputs {
             return false;
         }