You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by hs...@apache.org on 2023/03/12 01:29:29 UTC

[incubator-teaclave] branch master updated: Improve function arguments by introducing FunctionArgument

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d02fb0ce Improve function arguments by introducing FunctionArgument
d02fb0ce is described below

commit d02fb0ce04de5970f9d26d54b5c6acfebb513cda
Author: sunhe05 <su...@baidu.com>
AuthorDate: Thu Mar 9 10:18:54 2023 +0000

    Improve function arguments by introducing FunctionArgument
---
 examples/c/builtin_echo.c                          |  2 +-
 examples/c/builtin_ordered_set_intersect.c         |  2 +-
 examples/python/builtin_echo.py                    |  3 +-
 examples/python/builtin_face_detection.py          | 10 ++-
 examples/python/builtin_gbdt_train.py              | 14 +++-
 examples/python/builtin_online_decrypt.py          |  8 +-
 examples/python/builtin_ordered_set_intersect.py   |  4 +-
 examples/python/builtin_password_check.py          |  2 +-
 .../python/builtin_private_join_and_compute.py     |  4 +-
 examples/python/builtin_rsa_sign.py                |  4 +-
 examples/python/mesapy_echo.py                     |  4 +-
 examples/python/mesapy_logistic_reg.py             |  4 +-
 examples/python/test_disable_function.py           | 15 ++--
 examples/python/wasm_c_simple_add.py               | 14 ++--
 examples/python/wasm_rust_psi.py                   |  7 +-
 examples/python/wasm_tvm_mnist.py                  |  4 +-
 examples/rust/builtin_echo/src/main.rs             |  4 +-
 .../rust/builtin_ordered_set_intersect/src/main.rs |  5 +-
 sdk/python/teaclave.py                             | 35 ++++++--
 sdk/rust/src/lib.rs                                |  6 +-
 services/management/enclave/src/service.rs         | 15 ++--
 .../src/proto/teaclave_frontend_service.proto      | 12 ++-
 services/proto/src/teaclave_frontend_service.rs    | 92 ++++++++++++++++------
 .../enclave/src/end_to_end/builtin_echo.rs         |  3 +-
 .../enclave/src/end_to_end/builtin_gbdt_train.rs   | 18 ++---
 .../enclave/src/end_to_end/mesapy_data_fusion.rs   |  3 +-
 .../enclave/src/end_to_end/mesapy_echo.rs          |  3 +-
 tests/functional/enclave/src/management_service.rs | 14 ++--
 types/src/function.rs                              | 25 +++++-
 types/src/staged_function.rs                       |  4 +
 types/src/task_state.rs                            | 19 ++++-
 31 files changed, 255 insertions(+), 104 deletions(-)

diff --git a/examples/c/builtin_echo.c b/examples/c/builtin_echo.c
index 3276be3a..9a838356 100644
--- a/examples/c/builtin_echo.c
+++ b/examples/c/builtin_echo.c
@@ -34,7 +34,7 @@ const char *register_function_request_serialized = QUOTE({
     "executor_type" : "builtin",
     "public" : true,
     "payload" : [],
-    "arguments" : ["message"],
+    "arguments" : [{"key": "message", "default_value": "", "allow_overwrite": true}],
     "inputs" : [],
     "outputs" : [],
     "user_allowlist": []
diff --git a/examples/c/builtin_ordered_set_intersect.c b/examples/c/builtin_ordered_set_intersect.c
index ade3596b..2b278202 100644
--- a/examples/c/builtin_ordered_set_intersect.c
+++ b/examples/c/builtin_ordered_set_intersect.c
@@ -60,7 +60,7 @@ const char *register_function_request_serialized = QUOTE(
     "executor_type": "builtin",
     "public": true,
     "payload": [],
-    "arguments": ["order"],
+    "arguments": [{"key": "order", "default_value": "", "allow_overwrite": true}],
     "inputs": [
         {"name": "input_data1", "description": "Client 0 data.", "optional": false},
         {"name": "input_data2", "description": "Client 1 data.", "optional": false}
diff --git a/examples/python/builtin_echo.py b/examples/python/builtin_echo.py
index 8c6f154e..fdfed5e8 100644
--- a/examples/python/builtin_echo.py
+++ b/examples/python/builtin_echo.py
@@ -20,6 +20,7 @@
 import sys
 
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service
+from teaclave import FunctionArgument
 
 
 class BuiltinEchoExample:
@@ -42,7 +43,7 @@ class BuiltinEchoExample:
                 name="builtin-echo",
                 description="Native Echo Function",
                 executor_type="builtin",
-                arguments=["message"])
+                arguments=[FunctionArgument("message")])
 
             print("[+] creating task")
             task_id = client.create_task(
diff --git a/examples/python/builtin_face_detection.py b/examples/python/builtin_face_detection.py
index 416e99c3..a0743735 100644
--- a/examples/python/builtin_face_detection.py
+++ b/examples/python/builtin_face_detection.py
@@ -25,6 +25,7 @@ from PIL import Image, ImageDraw
 import requests
 
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service
+from teaclave import FunctionArgument
 
 
 class BuiltinFaceDetectionExample:
@@ -49,9 +50,12 @@ class BuiltinFaceDetectionExample:
             executor_type="builtin",
             inputs=[],
             arguments=[
-                "image", "min_face_size", "score_thresh",
-                "pyramid_scale_factor", "slide_window_step_x",
-                "slide_window_step_y"
+                FunctionArgument("image"),
+                FunctionArgument("min_face_size"),
+                FunctionArgument("score_thresh"),
+                FunctionArgument("pyramid_scale_factor"),
+                FunctionArgument("slide_window_step_x"),
+                FunctionArgument("slide_window_step_y")
             ])
 
         print("[+] creating task")
diff --git a/examples/python/builtin_gbdt_train.py b/examples/python/builtin_gbdt_train.py
index e8ec045a..9b125104 100644
--- a/examples/python/builtin_gbdt_train.py
+++ b/examples/python/builtin_gbdt_train.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service
 
 
@@ -44,9 +44,15 @@ class BuiltinGbdtExample:
             description="Native Gbdt Training Function",
             executor_type="builtin",
             arguments=[
-                "feature_size", "max_depth", "iterations", "shrinkage",
-                "feature_sample_ratio", "data_sample_ratio", "min_leaf_size",
-                "loss", "training_optimization_level"
+                FunctionArgument("feature_size"),
+                FunctionArgument("max_depth"),
+                FunctionArgument("iterations"),
+                FunctionArgument("shrinkage"),
+                FunctionArgument("feature_sample_ratio"),
+                FunctionArgument("data_sample_ratio"),
+                FunctionArgument("min_leaf_size"),
+                FunctionArgument("loss"),
+                FunctionArgument("training_optimization_level")
             ],
             inputs=[
                 FunctionInput("training_data", "Input traning data file.")
diff --git a/examples/python/builtin_online_decrypt.py b/examples/python/builtin_online_decrypt.py
index aee9c80d..9a30b3b0 100644
--- a/examples/python/builtin_online_decrypt.py
+++ b/examples/python/builtin_online_decrypt.py
@@ -21,6 +21,7 @@ import sys
 import base64
 
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service
+from teaclave import FunctionArgument
 
 
 class BuiltinOnlineDecryptExample:
@@ -43,7 +44,12 @@ class BuiltinOnlineDecryptExample:
             name="builtin_online_decrypt",
             description="Native Online Decrypt",
             executor_type="builtin",
-            arguments=["key", "nonce", "encrypted_data", "algorithm"])
+            arguments=[
+                FunctionArgument("key"),
+                FunctionArgument("nonce"),
+                FunctionArgument("encrypted_data"),
+                FunctionArgument("algorithm")
+            ])
 
         print("[+] creating task")
         task_id = client.create_task(
diff --git a/examples/python/builtin_ordered_set_intersect.py b/examples/python/builtin_ordered_set_intersect.py
index 36061971..277cef70 100644
--- a/examples/python/builtin_ordered_set_intersect.py
+++ b/examples/python/builtin_ordered_set_intersect.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 # In the example, user 0 creates the task and user 0, 1, upload their private data.
@@ -91,7 +91,7 @@ class Client:
             name="builtin-ordered-set-intersect",
             description="Native Private Set Intersection",
             executor_type="builtin",
-            arguments=["order"],
+            arguments=[FunctionArgument("order")],
             inputs=[
                 FunctionInput("input_data1", "Client 0 data."),
                 FunctionInput("input_data2", "Client 1 data.")
diff --git a/examples/python/builtin_password_check.py b/examples/python/builtin_password_check.py
index aad72140..1715be0d 100644
--- a/examples/python/builtin_password_check.py
+++ b/examples/python/builtin_password_check.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 # In the example, user 0 creates the task and user 0, 1, upload their private data.
diff --git a/examples/python/builtin_private_join_and_compute.py b/examples/python/builtin_private_join_and_compute.py
index 37d198a1..0b7c89b6 100644
--- a/examples/python/builtin_private_join_and_compute.py
+++ b/examples/python/builtin_private_join_and_compute.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 # In the example, user 3 creates the task and user 0, 1, 2 upload their private data.
@@ -98,7 +98,7 @@ class ConfigClient:
             name="builtin-private-join-and-compute",
             description="Native Private Join And Compute",
             executor_type="builtin",
-            arguments=["num_user"],
+            arguments=[FunctionArgument("num_user")],
             inputs=[
                 FunctionInput("input_data0", "Bank A data file."),
                 FunctionInput("input_data1", "Bank B data file."),
diff --git a/examples/python/builtin_rsa_sign.py b/examples/python/builtin_rsa_sign.py
index 80d95886..3ba494a1 100644
--- a/examples/python/builtin_rsa_sign.py
+++ b/examples/python/builtin_rsa_sign.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 
@@ -61,7 +61,7 @@ def register_func(client):
         name="builtin-rsa-sign",
         description="Native Rsa Signing Function",
         executor_type="builtin",
-        arguments=["data"],
+        arguments=[FunctionArgument("data")],
         inputs=[FunctionInput("rsa_key", "Input key file.")])
 
     return function_id
diff --git a/examples/python/mesapy_echo.py b/examples/python/mesapy_echo.py
index d24c2aee..b60df003 100644
--- a/examples/python/mesapy_echo.py
+++ b/examples/python/mesapy_echo.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 
@@ -49,7 +49,7 @@ class MesaPyEchoExample:
             description="An echo function implemented in Python",
             executor_type="python",
             payload=list(payload),
-            arguments=["message"])
+            arguments=[FunctionArgument("message")])
 
         print("[+] creating task")
         task_id = client.create_task(function_id=function_id,
diff --git a/examples/python/mesapy_logistic_reg.py b/examples/python/mesapy_logistic_reg.py
index 758a1865..2b8c8b81 100644
--- a/examples/python/mesapy_logistic_reg.py
+++ b/examples/python/mesapy_logistic_reg.py
@@ -23,7 +23,7 @@ An example about Logistic Regression in MesaPy.
 import sys
 import binascii
 from typing import List
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 from enum import Enum
@@ -117,7 +117,7 @@ class ConfigClient:
             name=functionname,
             description="worker: %s" % functionname,
             executor_type=ex.name,
-            arguments=list(args.keys()),
+            arguments=[FunctionArgument(arg) for arg in args],
             payload=list(p_str),
             inputs=[
                 FunctionInput(label, "user input data fileļ¼š %s" % label)
diff --git a/examples/python/test_disable_function.py b/examples/python/test_disable_function.py
index 5c51e6d3..dbea609d 100644
--- a/examples/python/test_disable_function.py
+++ b/examples/python/test_disable_function.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 
@@ -50,12 +50,13 @@ class ConfigClient:
 
         print(f"[+] {self.user_id} registering function")
 
-        function_id = client.register_function(name=func_name,
-                                               description=func_name,
-                                               executor_type="builtin",
-                                               arguments=["num_user"],
-                                               inputs=[],
-                                               outputs=[])
+        function_id = client.register_function(
+            name=func_name,
+            description=func_name,
+            executor_type="builtin",
+            arguments=[FunctionArgument("num_user")],
+            inputs=[],
+            outputs=[])
 
         return function_id
 
diff --git a/examples/python/wasm_c_simple_add.py b/examples/python/wasm_c_simple_add.py
index c45175a5..867cba3a 100644
--- a/examples/python/wasm_c_simple_add.py
+++ b/examples/python/wasm_c_simple_add.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 
@@ -45,11 +45,13 @@ class WASMAddExample:
         with open(payload_file, "rb") as f:
             payload = f.read()
 
-        function_id = client.register_function(name="entrypoint",
-                                               description="test of wasm",
-                                               executor_type="wamr",
-                                               payload=list(payload),
-                                               arguments=["adder1", "adder2"])
+        function_id = client.register_function(
+            name="entrypoint",
+            description="test of wasm",
+            executor_type="wamr",
+            payload=list(payload),
+            arguments=[FunctionArgument("adder1"),
+                       FunctionArgument("adder2")])
 
         print("[+] creating task")
         task_id = client.create_task(function_id=function_id,
diff --git a/examples/python/wasm_rust_psi.py b/examples/python/wasm_rust_psi.py
index ead05eb5..61fc1c53 100644
--- a/examples/python/wasm_rust_psi.py
+++ b/examples/python/wasm_rust_psi.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 
@@ -102,7 +102,10 @@ class Client:
             payload=list(payload),
             executor_type="wamr",
             arguments=[
-                "input1_fid", "input2_fid", "output1_fid", "output2_fid"
+                FunctionArgument("input1_fid"),
+                FunctionArgument("input2_fid"),
+                FunctionArgument("output1_fid"),
+                FunctionArgument("output2_fid")
             ],
             inputs=[
                 FunctionInput(USER_DATA_0.input_fid, "Client 0 data."),
diff --git a/examples/python/wasm_tvm_mnist.py b/examples/python/wasm_tvm_mnist.py
index 3178874b..4f3b999c 100644
--- a/examples/python/wasm_tvm_mnist.py
+++ b/examples/python/wasm_tvm_mnist.py
@@ -19,7 +19,7 @@
 
 import sys
 
-from teaclave import FunctionInput, FunctionOutput, OwnerList, DataMap
+from teaclave import FunctionInput, FunctionOutput, FunctionArgument, OwnerList, DataMap
 from utils import USER_ID, USER_PASSWORD, connect_authentication_service, connect_frontend_service, PlatformAdmin
 
 # If you're using `docker-compose` to start the Teaclave server containers,
@@ -61,7 +61,7 @@ def main():
         description="WAMR TVM MNIST Prediction",
         payload=list(payload),
         executor_type="wamr",
-        arguments=["input_img"],
+        arguments=[FunctionArgument("input_img")],
         inputs=[
             FunctionInput("input_img",
                           "Input image for handwriting number perdiction")
diff --git a/examples/rust/builtin_echo/src/main.rs b/examples/rust/builtin_echo/src/main.rs
index 11e95a69..378b43ba 100644
--- a/examples/rust/builtin_echo/src/main.rs
+++ b/examples/rust/builtin_echo/src/main.rs
@@ -64,7 +64,9 @@ fn echo(message: &str) -> Result<Vec<u8>> {
         "An native echo function.",
         "builtin",
         None,
-        Some(&["message"]),
+        Some(vec![teaclave_client_sdk::FunctionArgument::new(
+            "message", "", true,
+        )]),
         None,
         None,
     )?;
diff --git a/examples/rust/builtin_ordered_set_intersect/src/main.rs b/examples/rust/builtin_ordered_set_intersect/src/main.rs
index 636dcd04..d39127d4 100644
--- a/examples/rust/builtin_ordered_set_intersect/src/main.rs
+++ b/examples/rust/builtin_ordered_set_intersect/src/main.rs
@@ -118,7 +118,10 @@ impl Client {
             "Native Private Set Intersection.",
             "builtin",
             None,
-            Some(&["order", "save_log"]),
+            Some(vec![
+                teaclave_client_sdk::FunctionArgument::new("order", "", true),
+                teaclave_client_sdk::FunctionArgument::new("save_log", "false", true),
+            ]),
             Some(vec![
                 teaclave_client_sdk::FunctionInput::new("input_data1", "Client 0 data.", false),
                 teaclave_client_sdk::FunctionInput::new("input_data2", "Client 1 data.", false),
diff --git a/sdk/python/teaclave.py b/sdk/python/teaclave.py
index 5a6907cb..c4a4873c 100644
--- a/sdk/python/teaclave.py
+++ b/sdk/python/teaclave.py
@@ -44,8 +44,8 @@ from OpenSSL.crypto import X509Store, X509StoreContext
 from OpenSSL import crypto
 
 __all__ = [
-    'FrontendService', 'AuthenticationService', 'FunctionInput',
-    'FunctionOutput', 'OwnerList', 'DataMap'
+    'FrontendService', 'AuthenticationService', 'FunctionArgument',
+    'FunctionInput', 'FunctionOutput', 'OwnerList', 'DataMap'
 ]
 
 Metadata = Dict[str, str]
@@ -250,6 +250,26 @@ class FunctionOutput:
         self.optional = optional
 
 
+class FunctionArgument:
+    """Function argument for registring.
+
+    Args:
+        key: Name of the argument.
+        default_value: A default value of the argument. The default value is "".
+        allow_overwrite: If allow_overwrite flag is set to be true. The service
+                         will allow the task creator to overwrite the arguement
+                         value when creating tasks.
+    """
+
+    def __init__(self,
+                 key: str,
+                 default_value: str = "",
+                 allow_overwrite=True):
+        self.key = key
+        self.default_value = default_value
+        self.allow_overwrite = allow_overwrite
+
+
 class OwnerList:
     """Defines data ownership.
 
@@ -546,8 +566,9 @@ class RegisterFunctionRequest(Request):
 
     def __init__(self, metadata: Metadata, name: str, description: str,
                  executor_type: str, public: bool, payload: List[int],
-                 arguments: List[str], inputs: List[FunctionInput],
-                 outputs: List[FunctionOutput], user_allowlist: List[str]):
+                 arguments: List[FunctionArgument],
+                 inputs: List[FunctionInput], outputs: List[FunctionOutput],
+                 user_allowlist: List[str]):
         self.request = "register_function"
         self.metadata = metadata
         self.name = name
@@ -565,7 +586,7 @@ class UpdateFunctionRequest(Request):
 
     def __init__(self, metadata: Metadata, function_id: str, name: str,
                  description: str, executor_type: str, public: bool,
-                 payload: List[int], arguments: List[str],
+                 payload: List[int], arguments: List[FunctionArgument],
                  inputs: List[FunctionInput], outputs: List[FunctionOutput],
                  user_allowlist: List[str]):
         self.request = "update_function"
@@ -738,7 +759,7 @@ class FrontendService(TeaclaveService):
         executor_type: str,
         public: bool = True,
         payload: List[int] = [],
-        arguments: List[str] = [],
+        arguments: List[FunctionArgument] = [],
         inputs: List[FunctionInput] = [],
         outputs: List[FunctionOutput] = [],
         user_allowlist: List[str] = [],
@@ -767,7 +788,7 @@ class FrontendService(TeaclaveService):
         executor_type: str,
         public: bool = True,
         payload: List[int] = [],
-        arguments: List[str] = [],
+        arguments: List[FunctionArgument] = [],
         inputs: List[FunctionInput] = [],
         outputs: List[FunctionOutput] = [],
         user_allowlist: List[str] = [],
diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs
index d4243a8c..65d80fed 100644
--- a/sdk/rust/src/lib.rs
+++ b/sdk/rust/src/lib.rs
@@ -41,7 +41,7 @@ pub use teaclave_proto::teaclave_frontend_service::{
     RegisterOutputFileRequest, RegisterOutputFileResponse,
 };
 pub use teaclave_types::{
-    EnclaveInfo, Executor, FileCrypto, FunctionInput, FunctionOutput, TaskResult,
+    EnclaveInfo, Executor, FileCrypto, FunctionArgument, FunctionInput, FunctionOutput, TaskResult,
 };
 
 pub mod bindings;
@@ -211,7 +211,7 @@ impl FrontendClient {
         description: &str,
         executor_type: &str,
         payload: Option<&[u8]>,
-        arguments: Option<&[&str]>,
+        arguments: Option<Vec<FunctionArgument>>,
         inputs: Option<Vec<FunctionInput>>,
         outputs: Option<Vec<FunctionOutput>>,
     ) -> Result<String> {
@@ -592,7 +592,7 @@ mod tests {
                 "An native echo function.",
                 "builtin",
                 None,
-                Some(&["message"]),
+                Some(vec![FunctionArgument::new("message", "", true)]),
                 None,
                 None,
             )
diff --git a/services/management/enclave/src/service.rs b/services/management/enclave/src/service.rs
index 73a7298e..1557de35 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -891,6 +891,8 @@ impl TeaclaveManagementService {
         let function_output = FunctionOutput::new("output", "output_desc", false);
         let function_input2 = FunctionInput::new("input2", "input_desc", false);
         let function_output2 = FunctionOutput::new("output2", "output_desc", false);
+        let function_arg1 = FunctionArgument::new("arg1", "", true);
+        let function_arg2 = FunctionArgument::new("arg2", "", true);
 
         let function = FunctionBuilder::new()
             .id(Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap())
@@ -898,7 +900,7 @@ impl TeaclaveManagementService {
             .description("mock-desc")
             .payload(b"mock-payload".to_vec())
             .public(true)
-            .arguments(vec!["arg1".to_string(), "arg2".to_string()])
+            .arguments(vec![function_arg1, function_arg2])
             .inputs(vec![function_input, function_input2])
             .outputs(vec![function_output, function_output2])
             .owner("teaclave".to_string())
@@ -907,13 +909,14 @@ impl TeaclaveManagementService {
         self.write_to_db(&function)?;
 
         let function_output = FunctionOutput::new("output", "output_desc", false);
+        let function_arg1 = FunctionArgument::new("arg1", "", true);
         let function = FunctionBuilder::new()
             .id(Uuid::parse_str("00000000-0000-0000-0000-000000000002").unwrap())
             .name("mock-func-2")
             .description("mock-desc")
             .payload(b"mock-payload".to_vec())
             .public(true)
-            .arguments(vec!["arg1".to_string()])
+            .arguments(vec![function_arg1.clone()])
             .outputs(vec![function_output])
             .owner("teaclave".to_string())
             .build();
@@ -926,7 +929,7 @@ impl TeaclaveManagementService {
             .description("Private mock function")
             .payload(b"mock-payload".to_vec())
             .public(false)
-            .arguments(vec!["arg1".to_string()])
+            .arguments(vec![function_arg1])
             .owner("mock_user".to_string())
             .user_allowlist(vec!["mock_user".to_string(), "mock_user1".to_string()])
             .build();
@@ -995,12 +998,13 @@ pub mod tests {
     pub fn handle_function() {
         let function_input = FunctionInput::new("input", "input_desc", false);
         let function_output = FunctionOutput::new("output", "output_desc", false);
+        let function_arg = FunctionArgument::new("arg", "", true);
         let function = FunctionBuilder::new()
             .id(Uuid::new_v4())
             .name("mock_function")
             .description("mock function")
             .payload(b"python script".to_vec())
-            .arguments(vec!["arg".to_string()])
+            .arguments(vec![function_arg])
             .inputs(vec![function_input])
             .outputs(vec![function_output])
             .public(true)
@@ -1013,12 +1017,13 @@ pub mod tests {
     }
 
     pub fn handle_task() {
+        let function_arg = FunctionArgument::new("arg", "", true);
         let function = FunctionBuilder::new()
             .id(Uuid::new_v4())
             .name("mock_function")
             .description("mock function")
             .payload(b"python script".to_vec())
-            .arguments(vec!["arg".to_string()])
+            .arguments(vec![function_arg])
             .public(true)
             .owner("mock_user")
             .build();
diff --git a/services/proto/src/proto/teaclave_frontend_service.proto b/services/proto/src/proto/teaclave_frontend_service.proto
index 31d8fd07..afd0dbb4 100644
--- a/services/proto/src/proto/teaclave_frontend_service.proto
+++ b/services/proto/src/proto/teaclave_frontend_service.proto
@@ -107,6 +107,12 @@ message FunctionOutput {
   bool optional = 3;
 }
 
+message FunctionArgument {
+  string key = 1;
+  string default_value = 2;
+  bool allow_overwrite = 3;
+}
+
 message OwnerList {
   string data_name = 1;
   repeated string uids = 2;
@@ -118,7 +124,7 @@ message RegisterFunctionRequest {
   string executor_type = 3;
   bool public = 4;
   bytes payload = 5;
-  repeated string arguments = 6;
+  repeated FunctionArgument arguments = 6;
   repeated FunctionInput inputs = 10;
   repeated FunctionOutput outputs = 11;
   repeated string user_allowlist = 12;
@@ -135,7 +141,7 @@ message UpdateFunctionRequest {
   string executor_type = 4;
   bool public = 5;
   bytes payload = 6;
-  repeated string arguments = 7;
+  repeated FunctionArgument arguments = 7;
   repeated FunctionInput inputs = 10;
   repeated FunctionOutput outputs = 11;
   repeated string user_allowlist = 12;
@@ -156,7 +162,7 @@ message GetFunctionResponse {
   string owner = 4;
   bytes payload = 5;
   bool public = 6;
-  repeated string arguments = 7;
+  repeated FunctionArgument arguments = 7;
   repeated FunctionInput inputs = 10;
   repeated FunctionOutput outputs = 11;
   repeated string user_allowlist = 12;
diff --git a/services/proto/src/teaclave_frontend_service.rs b/services/proto/src/teaclave_frontend_service.rs
index 6d5b6bf6..2e3c9150 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -25,9 +25,9 @@ use core::convert::TryInto;
 use std::collections::HashMap;
 use teaclave_rpc::into_request;
 use teaclave_types::{
-    Executor, ExecutorType, ExternalID, FileAuthTag, FileCrypto, FunctionArguments,
-    FunctionBuilder, FunctionInput, FunctionOutput, OwnerList, TaskFileOwners, TaskResult,
-    TaskStatus, UserID, UserList,
+    Executor, ExecutorType, ExternalID, FileAuthTag, FileCrypto, FunctionArgument,
+    FunctionArguments, FunctionBuilder, FunctionInput, FunctionOutput, OwnerList, TaskFileOwners,
+    TaskResult, TaskStatus, UserID, UserList,
 };
 use url::Url;
 
@@ -284,7 +284,7 @@ pub struct RegisterFunctionRequest {
     pub executor_type: ExecutorType,
     pub payload: Vec<u8>,
     pub public: bool,
-    pub arguments: Vec<String>,
+    pub arguments: Vec<FunctionArgument>,
     pub inputs: Vec<FunctionInput>,
     pub outputs: Vec<FunctionOutput>,
     pub user_allowlist: Vec<String>,
@@ -331,11 +331,8 @@ impl RegisterFunctionRequestBuilder {
         self
     }
 
-    pub fn arguments<T: IntoIterator>(mut self, args: T) -> Self
-    where
-        <T as IntoIterator>::Item: ToString,
-    {
-        self.request.arguments = args.into_iter().map(|x| x.to_string()).collect();
+    pub fn arguments(mut self, args: Vec<FunctionArgument>) -> Self {
+        self.request.arguments = args;
         self
     }
 
@@ -397,7 +394,7 @@ pub struct UpdateFunctionRequest {
     pub executor_type: ExecutorType,
     pub payload: Vec<u8>,
     pub public: bool,
-    pub arguments: Vec<String>,
+    pub arguments: Vec<FunctionArgument>,
     pub inputs: Vec<FunctionInput>,
     pub outputs: Vec<FunctionOutput>,
     pub user_allowlist: Vec<String>,
@@ -449,11 +446,8 @@ impl UpdateFunctionRequestBuilder {
         self
     }
 
-    pub fn arguments<T: IntoIterator>(mut self, args: T) -> Self
-    where
-        <T as IntoIterator>::Item: ToString,
-    {
-        self.request.arguments = args.into_iter().map(|x| x.to_string()).collect();
+    pub fn arguments(mut self, args: Vec<FunctionArgument>) -> Self {
+        self.request.arguments = args;
         self
     }
 
@@ -528,7 +522,7 @@ pub struct GetFunctionResponse {
     pub payload: Vec<u8>,
     pub public: bool,
     pub executor_type: ExecutorType,
-    pub arguments: Vec<String>,
+    pub arguments: Vec<FunctionArgument>,
     pub inputs: Vec<FunctionInput>,
     pub outputs: Vec<FunctionOutput>,
     pub user_allowlist: Vec<String>,
@@ -1123,6 +1117,11 @@ impl std::convert::TryFrom<proto::RegisterFunctionRequest> for RegisterFunctionR
             .map(FunctionOutput::try_from)
             .collect();
         let executor_type = proto.executor_type.try_into()?;
+        let arguments: Result<Vec<FunctionArgument>> = proto
+            .arguments
+            .into_iter()
+            .map(FunctionArgument::try_from)
+            .collect();
 
         let ret = Self {
             name: proto.name,
@@ -1130,7 +1129,7 @@ impl std::convert::TryFrom<proto::RegisterFunctionRequest> for RegisterFunctionR
             executor_type,
             payload: proto.payload,
             public: proto.public,
-            arguments: proto.arguments,
+            arguments: arguments?,
             inputs: inputs?,
             outputs: outputs?,
             user_allowlist: proto.user_allowlist,
@@ -1151,6 +1150,11 @@ impl From<RegisterFunctionRequest> for proto::RegisterFunctionRequest {
             .into_iter()
             .map(proto::FunctionOutput::from)
             .collect();
+        let arguments: Vec<proto::FunctionArgument> = request
+            .arguments
+            .into_iter()
+            .map(proto::FunctionArgument::from)
+            .collect();
 
         Self {
             name: request.name,
@@ -1158,7 +1162,7 @@ impl From<RegisterFunctionRequest> for proto::RegisterFunctionRequest {
             executor_type: request.executor_type.into(),
             payload: request.payload,
             public: request.public,
-            arguments: request.arguments,
+            arguments,
             inputs,
             outputs,
             user_allowlist: request.user_allowlist,
@@ -1201,6 +1205,11 @@ impl std::convert::TryFrom<proto::UpdateFunctionRequest> for UpdateFunctionReque
             .map(FunctionOutput::try_from)
             .collect();
         let executor_type = proto.executor_type.try_into()?;
+        let arguments: Result<Vec<FunctionArgument>> = proto
+            .arguments
+            .into_iter()
+            .map(FunctionArgument::try_from)
+            .collect();
 
         let ret = Self {
             function_id,
@@ -1209,7 +1218,7 @@ impl std::convert::TryFrom<proto::UpdateFunctionRequest> for UpdateFunctionReque
             executor_type,
             payload: proto.payload,
             public: proto.public,
-            arguments: proto.arguments,
+            arguments: arguments?,
             inputs: inputs?,
             outputs: outputs?,
             user_allowlist: proto.user_allowlist,
@@ -1230,6 +1239,11 @@ impl From<UpdateFunctionRequest> for proto::UpdateFunctionRequest {
             .into_iter()
             .map(proto::FunctionOutput::from)
             .collect();
+        let arguments: Vec<proto::FunctionArgument> = request
+            .arguments
+            .into_iter()
+            .map(proto::FunctionArgument::from)
+            .collect();
 
         Self {
             function_id: request.function_id.to_string(),
@@ -1238,7 +1252,7 @@ impl From<UpdateFunctionRequest> for proto::UpdateFunctionRequest {
             executor_type: request.executor_type.into(),
             payload: request.payload,
             public: request.public,
-            arguments: request.arguments,
+            arguments,
             inputs,
             outputs,
             user_allowlist: request.user_allowlist,
@@ -1406,6 +1420,11 @@ impl std::convert::TryFrom<proto::GetFunctionResponse> for GetFunctionResponse {
             .map(FunctionOutput::try_from)
             .collect();
         let executor_type = proto.executor_type.try_into()?;
+        let arguments: Result<Vec<FunctionArgument>> = proto
+            .arguments
+            .into_iter()
+            .map(FunctionArgument::try_from)
+            .collect();
 
         let ret = Self {
             name: proto.name,
@@ -1414,7 +1433,7 @@ impl std::convert::TryFrom<proto::GetFunctionResponse> for GetFunctionResponse {
             executor_type,
             payload: proto.payload,
             public: proto.public,
-            arguments: proto.arguments,
+            arguments: arguments?,
             inputs: inputs?,
             outputs: outputs?,
             user_allowlist: proto.user_allowlist,
@@ -1436,6 +1455,11 @@ impl From<GetFunctionResponse> for proto::GetFunctionResponse {
             .into_iter()
             .map(proto::FunctionOutput::from)
             .collect();
+        let arguments: Vec<proto::FunctionArgument> = response
+            .arguments
+            .into_iter()
+            .map(proto::FunctionArgument::from)
+            .collect();
 
         Self {
             name: response.name,
@@ -1444,7 +1468,7 @@ impl From<GetFunctionResponse> for proto::GetFunctionResponse {
             executor_type: response.executor_type.into(),
             payload: response.payload,
             public: response.public,
-            arguments: response.arguments,
+            arguments,
             inputs,
             outputs,
             user_allowlist: response.user_allowlist,
@@ -1452,6 +1476,30 @@ impl From<GetFunctionResponse> for proto::GetFunctionResponse {
     }
 }
 
+impl std::convert::TryFrom<proto::FunctionArgument> for FunctionArgument {
+    type Error = Error;
+
+    fn try_from(proto: proto::FunctionArgument) -> Result<Self> {
+        let ret = Self {
+            key: proto.key,
+            default_value: proto.default_value,
+            allow_overwrite: proto.allow_overwrite,
+        };
+
+        Ok(ret)
+    }
+}
+
+impl From<FunctionArgument> for proto::FunctionArgument {
+    fn from(arg: FunctionArgument) -> Self {
+        Self {
+            key: arg.key,
+            default_value: arg.default_value,
+            allow_overwrite: arg.allow_overwrite,
+        }
+    }
+}
+
 fn from_proto_ownership(proto: Vec<proto::OwnerList>) -> TaskFileOwners {
     proto
         .into_iter()
diff --git a/tests/functional/enclave/src/end_to_end/builtin_echo.rs b/tests/functional/enclave/src/end_to_end/builtin_echo.rs
index 15a1f68d..3b1da0c3 100644
--- a/tests/functional/enclave/src/end_to_end/builtin_echo.rs
+++ b/tests/functional/enclave/src/end_to_end/builtin_echo.rs
@@ -26,12 +26,13 @@ pub fn test_echo_task_success() {
     let cred = login(&mut api_client, USERNAME, TEST_PASSWORD).unwrap();
     let mut client =
         create_frontend_client(shared_enclave_info(), FRONTEND_SERVICE_ADDR, cred).unwrap();
+    let arg = FunctionArgument::new("message", "", true);
 
     // Register Function
     let request = RegisterFunctionRequestBuilder::new()
         .name("builtin-echo")
         .description("Native Echo Function")
-        .arguments(vec!["message"])
+        .arguments(vec![arg])
         .build();
 
     let response = client.register_function(request).unwrap();
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 273f41f8..2672a85c 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
@@ -49,15 +49,15 @@ fn register_gbdt_function(client: &mut TeaclaveFrontendClient) -> ExternalID {
     let fn_input = FunctionInput::new("training_data", "Input traning data file.", false);
     let fn_output = FunctionOutput::new("trained_model", "Output trained model.", false);
     let fn_args = vec![
-        "feature_size",
-        "max_depth",
-        "iterations",
-        "shrinkage",
-        "feature_sample_ratio",
-        "data_sample_ratio",
-        "min_leaf_size",
-        "loss",
-        "training_optimization_level",
+        FunctionArgument::new("feature_size", "", true),
+        FunctionArgument::new("max_depth", "", true),
+        FunctionArgument::new("iterations", "", true),
+        FunctionArgument::new("shrinkage", "", true),
+        FunctionArgument::new("feature_sample_ratio", "", true),
+        FunctionArgument::new("data_sample_ratio", "", true),
+        FunctionArgument::new("min_leaf_size", "", true),
+        FunctionArgument::new("loss", "", true),
+        FunctionArgument::new("training_optimization_level", "", true),
     ];
 
     // Register Function
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 266ce273..d2f992da 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
@@ -231,10 +231,11 @@ def entrypoint(argv):
 "#;
 
     let input_spec = FunctionInput::new("InputData", "Lines of Data", false);
+    let arg = FunctionArgument::new("query", "", true);
     let request = RegisterFunctionRequestBuilder::new()
         .name("wlc")
         .description("Mesapy Word Line Count Function")
-        .arguments(vec!["query"])
+        .arguments(vec![arg])
         .payload(script.into())
         .executor_type(ExecutorType::Python)
         .public(true)
diff --git a/tests/functional/enclave/src/end_to_end/mesapy_echo.rs b/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
index 42d1fb60..761f3bea 100644
--- a/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
+++ b/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
@@ -33,6 +33,7 @@ def entrypoint(argv):
     assert argv[1] is not None
     return argv[1]
 ";
+    let arg = FunctionArgument::new("message", "", true);
     // Register Function
     let request = RegisterFunctionRequestBuilder::new()
         .name("mesapy_echo_demo")
@@ -40,7 +41,7 @@ def entrypoint(argv):
         .payload(script.into())
         .executor_type(ExecutorType::Python)
         .public(true)
-        .arguments(vec!["message"])
+        .arguments(vec![arg])
         .build();
 
     let response = client.register_function(request).unwrap();
diff --git a/tests/functional/enclave/src/management_service.rs b/tests/functional/enclave/src/management_service.rs
index 9ee0ea49..95249edd 100644
--- a/tests/functional/enclave/src/management_service.rs
+++ b/tests/functional/enclave/src/management_service.rs
@@ -132,7 +132,7 @@ fn test_register_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(true)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .build();
@@ -152,7 +152,7 @@ fn test_register_private_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(false)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .user_allowlist(vec!["mock_user".to_string()])
@@ -173,7 +173,7 @@ fn test_delete_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(true)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .build();
@@ -196,7 +196,7 @@ fn test_disable_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(true)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .build();
@@ -219,7 +219,7 @@ fn test_update_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(true)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .build();
@@ -236,7 +236,7 @@ fn test_update_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(false)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .user_allowlist(vec!["mock_user".to_string()])
@@ -270,7 +270,7 @@ fn test_get_function() {
         .executor_type(ExecutorType::Python)
         .payload(b"def entrypoint:\n\treturn".to_vec())
         .public(false)
-        .arguments(vec!["arg"])
+        .arguments(vec![FunctionArgument::new("arg", "", true)])
         .inputs(vec![function_input])
         .outputs(vec![function_output])
         .build();
diff --git a/types/src/function.rs b/types/src/function.rs
index cf61ccf2..0180d8e8 100644
--- a/types/src/function.rs
+++ b/types/src/function.rs
@@ -82,7 +82,7 @@ pub struct Function {
     pub public: bool,
     pub executor_type: ExecutorType,
     pub payload: Vec<u8>,
-    pub arguments: Vec<String>,
+    pub arguments: Vec<FunctionArgument>,
     pub inputs: Vec<FunctionInput>,
     pub outputs: Vec<FunctionOutput>,
     pub owner: UserID,
@@ -131,7 +131,7 @@ impl FunctionBuilder {
         self
     }
 
-    pub fn arguments(mut self, arguments: Vec<String>) -> Self {
+    pub fn arguments(mut self, arguments: Vec<FunctionArgument>) -> Self {
         self.function.arguments = arguments;
         self
     }
@@ -170,3 +170,24 @@ impl Storable for Function {
         self.id
     }
 }
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+pub struct FunctionArgument {
+    pub key: String,
+    pub default_value: String,
+    pub allow_overwrite: bool,
+}
+
+impl FunctionArgument {
+    pub fn new(
+        key: impl Into<String>,
+        default_value: impl Into<String>,
+        allow_overwrite: bool,
+    ) -> Self {
+        Self {
+            key: key.into(),
+            default_value: default_value.into(),
+            allow_overwrite,
+        }
+    }
+}
diff --git a/types/src/staged_function.rs b/types/src/staged_function.rs
index 796acc8a..d0ee4923 100644
--- a/types/src/staged_function.rs
+++ b/types/src/staged_function.rs
@@ -100,6 +100,10 @@ impl FunctionArguments {
     pub fn into_string(self) -> String {
         ArgumentValue::Object(self.inner).to_string()
     }
+
+    pub fn insert(&mut self, k: String, v: ArgumentValue) -> Option<ArgumentValue> {
+        self.inner.insert(k, v)
+    }
 }
 
 #[derive(Debug, Default)]
diff --git a/types/src/task_state.rs b/types/src/task_state.rs
index 682afd23..aaece9f6 100644
--- a/types/src/task_state.rs
+++ b/types/src/task_state.rs
@@ -129,10 +129,25 @@ impl Task<Create> {
         }
 
         //check function compatibility
-        let fn_args_spec: HashSet<&String> = function.arguments.iter().collect();
+        let fn_args_spec: HashSet<&String> = function
+            .arguments
+            .iter()
+            .filter(|arg| arg.allow_overwrite)
+            .map(|arg| &arg.key)
+            .collect();
         let req_args: HashSet<&String> = req_func_args.inner().keys().collect();
         ensure!(fn_args_spec == req_args, "function_arguments mismatch");
 
+        let mut func_args = req_func_args;
+        for arg in &function.arguments {
+            if !arg.allow_overwrite || !func_args.inner().contains_key(&arg.key) {
+                func_args.insert(
+                    arg.key.clone(),
+                    serde_json::Value::String(arg.default_value.clone()),
+                );
+            }
+        }
+
         // check input fkeys
         let inputs_spec: HashSet<&String> = function.inputs.iter().map(|f| &f.name).collect();
         let mut req_input_fkeys: HashSet<&String> = req_input_owners.keys().collect();
@@ -166,7 +181,7 @@ impl Task<Create> {
             executor: req_executor,
             function_id: function.external_id(),
             function_owner: function.owner.clone(),
-            function_arguments: req_func_args,
+            function_arguments: func_args,
             inputs_ownership: req_input_owners,
             outputs_ownership: req_output_owners,
             participants,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org