diff --git a/.gitignore b/.gitignore
index 95c00b7..5953e05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,6 @@ dist
*.egg-info
*.ipynb_checkpoints
*.pyc
+quick_*.sh
+settings.sh
+hfmodels-contract/
\ No newline at end of file
diff --git a/medperf-contract/CMakeLists.txt b/medperf-contract/CMakeLists.txt
new file mode 100644
index 0000000..d4f1b51
--- /dev/null
+++ b/medperf-contract/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright 2024 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This is necessary to get at the definitions necessary
+# for the std::string class
+INCLUDE(exchange_common)
+LIST(APPEND WASM_LIBRARIES ${EXCHANGE_LIB})
+LIST(APPEND WASM_INCLUDES ${EXCHANGE_INCLUDES})
+
+
+INCLUDE(medperf_common.cmake)
+LIST(APPEND WASM_LIBRARIES ${MEDPERF_LIB})
+LIST(APPEND WASM_INCLUDES ${MEDPERF_INCLUDES})
+
+ADD_LIBRARY(${MEDPERF_LIB} STATIC ${MEDPERF_SOURCES})
+TARGET_INCLUDE_DIRECTORIES(${MEDPERF_LIB} PUBLIC ${MEDPERF_INCLUDES})
+
+SET_PROPERTY(TARGET ${MEDPERF_LIB} APPEND_STRING PROPERTY COMPILE_OPTIONS "${WASM_BUILD_OPTIONS}")
+SET_PROPERTY(TARGET ${MEDPERF_LIB} APPEND_STRING PROPERTY LINK_OPTIONS "${WASM_LINK_OPTIONS}")
+SET_TARGET_PROPERTIES(${MEDPERF_LIB} PROPERTIES EXCLUDE_FROM_ALL TRUE)
+
+BUILD_CONTRACT(medperf_token_object contracts/token_object.cpp)
+
+# -----------------------------------------------------------------
+INCLUDE(Python)
+BUILD_WHEEL(medperf medperf_token_object)
\ No newline at end of file
diff --git a/medperf-contract/MANIFEST b/medperf-contract/MANIFEST
new file mode 100644
index 0000000..7b26b13
--- /dev/null
+++ b/medperf-contract/MANIFEST
@@ -0,0 +1,32 @@
+MANIFEST.in
+./setup.py
+./pdo/medperf/wsgi/provision_token_issuer.py
+./pdo/medperf/wsgi/__init__.py
+./pdo/medperf/wsgi/add_endpoint.py
+./pdo/medperf/wsgi/provision_token_object.py
+./pdo/medperf/wsgi/info.py
+./pdo/medperf/wsgi/process_capability.py
+./pdo/medperf/operations/use_dataset.py
+./pdo/medperf/operations/__init__.py
+./pdo/medperf/plugins/medperf_token_object.py
+./pdo/medperf/plugins/__init__.py
+./pdo/medperf/plugins/medperf_guardian.py
+./pdo/medperf/__init__.py
+./pdo/medperf/resources/resources.py
+./pdo/medperf/resources/__init__.py
+./pdo/medperf/common/guardian_service.py
+./pdo/medperf/common/capability_keystore.py
+./pdo/medperf/common/secrets.py
+./pdo/medperf/common/__init__.py
+./pdo/medperf/common/endpoint_registry.py
+./pdo/medperf/common/utility.py
+./pdo/medperf/common/capability_keys.py
+./pdo/medperf/scripts/__init__.py
+./pdo/medperf/scripts/guardianCLI.py
+./pdo/medperf/scripts/scripts.py
+./scripts/gs_stop.sh
+./scripts/gs_start.sh
+./scripts/gs_status.sh
+./context/tokens.toml
+./etc/medperf.toml
+./etc/guardian_service.toml
\ No newline at end of file
diff --git a/medperf-contract/MANIFEST.in b/medperf-contract/MANIFEST.in
new file mode 100644
index 0000000..7eb8ee6
--- /dev/null
+++ b/medperf-contract/MANIFEST.in
@@ -0,0 +1,4 @@
+recursive-include ../build/medperf-contract *.b64
+recursive-include etc *.toml
+recursive-include context *.toml
+recursive-include scripts *.sh
diff --git a/medperf-contract/PROTOCOL.md b/medperf-contract/PROTOCOL.md
new file mode 100644
index 0000000..fba77fa
--- /dev/null
+++ b/medperf-contract/PROTOCOL.md
@@ -0,0 +1,124 @@
+## Workflow
+
+```mermaid
+sequenceDiagram
+ participant E as Experiment Committee
+ participant PDO as PDO Contract (SGX)
+ participant G as Digital Guardian Service
+ participant D as Data Owner
+ participant M as MedPerf Server
+ %% participant MO as Model Owner
+ note over G, M: experiment-data association (assume finished)
+ note over G, M: model-data association (assume finished)
+ note over M, PDO: assume the states data are synchronized
+ loop Attestation
+ PDO -> G:
+ end
+ D ->> PDO: create token_issuer and call cmd_mint_token
+ PDO ->> PDO: generate new identity token_issuer and new contract token.token_object
+ D ->> PDO: transfer token.token_object to new owner token_experitment1
+ PDO ->> PDO: generate new identity token_expertiment1 and new contract token.token_experiment1
+ note over E, PDO: owership transferred to Experiment committee
+ note over M: notification about token/dataset availiability
+ box Assume Trusted
+ participant M
+ end
+ box SGX Enclave
+ participant G
+ end
+ E ->> PDO: request the inference on specific model model_id, experiment_id (cmd_use_dataset)
+ activate PDO
+ PDO ->> PDO: policy evaluation
+ note right of PDO: policy:
experiment_id = experiment_id'
model_id in {model_id}
+ PDO ->> E: return capabilities, encoded with urls for dockerfile and weights of the granted model.identity of
+ deactivate PDO
+ E ->> G: request access to service with capability (storage )
+ E ->> D:
+ activate G
+ note over G: pull/download/deploy mlcube (the model)
+ G ->> G: run inference over the dataset
+ G ->> D: return result (basic verification with hash)
+ D ->> E: return results
+ deactivate G
+```
+
+
+## Protocols
+
+From the dataset owner side:
++ The dataset is identified by its hash.
++ Tokens are minted based on hash-based binding.
++ Guardian service of the token exposes an api to the callers
+
+
+## Core functions
+
++ Allow data owner to tokenize a dataset (into a PDO contract)
+ + with default policy checking the registration information from MedPerf
+ + ownership transfer to experiment committee
+ + generate capability to grant access to the guardian service
+
++ Allow experiment committee to initilize the use of data by interacting with PDO
+ + capabilities are published on MedPerf server (or PDO states/ledger?) for downloading
+
++ Allow data owner to host a guardian service, which exposes interface (local) to initilize the test
+ + data owner downloads the capability from the server (or ledger)
+ + data owner feeds the capability to guardian service to initialize the experiment
+ + guardian service publish experiment results to the server (or ledger)
+ + allows access control?
+
+
+
+### Guardian service
+
+Datasets are hosted behind the service.
+
+
+
+
+The guardian service is co-located with the dataset. guadian service provides a wsgi api to process the capability. Capability encodes `{model_id, dataset_id, url_to_docker, url_to_weights}`. After receiving capability, the guardian service:
+1. pull/build docker images from `url_to_docker`
+2. download weights from `url_to_weights`
+3. model up and run over `dataset_id`
+
+no execution integrity for now.
+
+
+
+
+### Contract methods
+
+new contract methods under the class `ww::medperf::token_object`
+
+`initialize`: public methode, mint token for the dataset, actual method behind `cmd_mint_token`
+ 1. kvs of the experiment/model/dataset info
+ 2. Store the registered metadata from medperf service (synthetic for PoC).
+ 3. set a `max_evaluation`
+
+| Keys | Values |
+| ---- | ---- |
+| experiment_id | identifier for the experimetn |
+| model_id | identifier for the model |
+| {urls} | url to model assets |
+| dataset_id | hash of the dataset |
+| max_evaluation | most models that allowed to evaluate |
+| cur_evaluation | 0 |
+| approved_capability| {} |
+| TBA |
+
+`get_datasetinfo`: public method, get the non-secret kvs info of dataset token
+return the information associated with the dataset.
+
+capability -links to- identity // invoked by the dataowner only
+
+
+
+`use_dataset(model_id, dataset_id, experiment_id)`: only invoked by TO
+ 1. check if model_id, dataset_id, experiment_id are in the kv storage
+ 2. cur_evaluation + 1, if cur_evaluation = max_evaluation, fail
+ 3. invoke `get_capability` and return secretly encoded {urls}.
+
+allows multiple models in one call
+
+`get_capability`: only invoked by TO, parse capability kv
\ No newline at end of file
diff --git a/medperf-contract/README.md b/medperf-contract/README.md
new file mode 100644
index 0000000..ae03f51
--- /dev/null
+++ b/medperf-contract/README.md
@@ -0,0 +1,40 @@
+
+
+# PDO-enhanced MedPerf Workflow
+This document includes an enhanced workflow for Federated Evaluation (FE) in machine learning, aiming in providing a policy-enforced digital asset usage framwork with tokenization. The framework is built upon the FE workflow from [MedPerf](https://github.com/mlcommons/medperf).
+
+## Note
+
+The initial version of this project only covers the protection of dataset. Other digital assets, including the model (weights)and experiment results are not included for now.
+
+
+## Test with the MedPerf tutorial
+The existing test simulates the pdo-enhanced workflow by running both components simultaneously. The pdo command hacks into the medperf database directly to simulate the information updates.
+
+Set up PDO test environment and have the [MedPerf](https://github.com/mlcommons/medperf) installed and built. Then set up environment variables `MEDPERF_SQLITE_PATH`, `MEDPERF_VENV_PATH` and `MEDPERF_HOME`.
+
+Simply run [easy_test.sh](./easy_test.sh) to start the test.
+
+
+
+
+
+
+
+## Testing workflow
++ create token issuer and mint the token for the dataset.
++ token issuer transfers token to model_owner1
++ model_owner1 invoke `cmd_use_dataset` with specific `model_id` and `dataset_id`
+ + get capability for one model, increase the count
+ + call service to run inference
++ model_owner1 invoke `cmd_use_dataset` with specific `model_id` and `dataset_id`
+ + max_evaluation exceeds, fail
+
+For detailed description of the whole protocol, check [here](./PROTOCOL.md).
\ No newline at end of file
diff --git a/medperf-contract/context/tokens.toml b/medperf-contract/context/tokens.toml
new file mode 100644
index 0000000..72e9379
--- /dev/null
+++ b/medperf-contract/context/tokens.toml
@@ -0,0 +1,54 @@
+# Copyright 2024 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------
+# token ${token}
+# -----------------------------------------------------------------
+[token.${token}.asset_type]
+module = "pdo.exchange.plugins.asset_type"
+identity = "token_type"
+source = "${ContractFamily.Exchange.asset_type.source}"
+name = "${token}"
+description = "asset type for ${token} token objects"
+link = "http://"
+
+[token.${token}.vetting]
+module = "pdo.exchange.plugins.vetting"
+identity = "token_vetting"
+source = "${ContractFamily.Exchange.vetting.source}"
+asset_type_context = "@{..asset_type}"
+
+[token.${token}.guardian]
+module = "pdo.medperf.plugins.medperf_guardian"
+url = "${url}"
+identity = "${..token_issuer.identity}"
+token_issuer_context = "@{..token_issuer}"
+service_only = true
+
+[token.${token}.token_issuer]
+module = "pdo.exchange.plugins.token_issuer"
+identity = "token_issuer"
+source = "${ContractFamily.Exchange.token_issuer.source}"
+token_object_context = "@{..token_object}"
+vetting_context = "@{..vetting}"
+guardian_context = "@{..guardian}"
+description = "issuer for token ${token}"
+count = 1
+
+[token.${token}.token_object]
+module = "pdo.medperf.plugins.medperf_token_object"
+identity = "${..token_issuer.identity}"
+source = "${ContractFamily.medperf.token_object.source}"
+token_issuer_context = "@{..token_issuer}"
+data_guardian_context = "@{..guardian}"
diff --git a/medperf-contract/contracts/token_object.cpp b/medperf-contract/contracts/token_object.cpp
new file mode 100644
index 0000000..0ffa95f
--- /dev/null
+++ b/medperf-contract/contracts/token_object.cpp
@@ -0,0 +1,80 @@
+/* Copyright 2023 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+
+#include "Dispatch.h"
+
+#include "Cryptography.h"
+#include "KeyValue.h"
+#include "Environment.h"
+#include "Message.h"
+#include "Response.h"
+#include "Types.h"
+#include "Util.h"
+#include "Value.h"
+#include "WasmExtensions.h"
+
+#include "contract/base.h"
+#include "contract/attestation.h"
+#include "exchange/issuer_authority_base.h"
+#include "exchange/token_object.h"
+#include "medperf/token_object.h"
+
+// -----------------------------------------------------------------
+// METHOD: initialize_contract
+// -----------------------------------------------------------------
+bool initialize_contract(const Environment& env, Response& rsp)
+{
+ ASSERT_SUCCESS(rsp, ww::exchange::token_object::initialize_contract(env),
+ "failed to initialize the base contract");
+
+ return rsp.success(true);
+}
+
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+contract_method_reference_t contract_method_dispatch_table[] = {
+
+ CONTRACT_METHOD2(get_verifying_key, ww::contract::base::get_verifying_key),
+ CONTRACT_METHOD2(initialize, ww::medperf::token_object::initialize),
+
+ // issuer methods
+ CONTRACT_METHOD2(get_asset_type_identifier, ww::exchange::issuer_authority_base::get_asset_type_identifier),
+ CONTRACT_METHOD2(get_issuer_authority, ww::exchange::issuer_authority_base::get_issuer_authority),
+ CONTRACT_METHOD2(get_authority, ww::exchange::issuer_authority_base::get_authority),
+
+ // from the attestation contract
+ CONTRACT_METHOD2(get_contract_metadata, ww::contract::attestation::get_contract_metadata),
+ CONTRACT_METHOD2(get_contract_code_metadata, ww::contract::attestation::get_contract_code_metadata),
+
+ // use the asset
+ CONTRACT_METHOD2(get_dataset_info, ww::medperf::token_object::get_dataset_info),
+ CONTRACT_METHOD2(use_dataset, ww::medperf::token_object::use_dataset),
+ CONTRACT_METHOD2(get_capability, ww::medperf::token_object::get_capability),
+ CONTRACT_METHOD2(owner_test, ww::medperf::token_object::owner_test),
+ CONTRACT_METHOD2(update_policy, ww::medperf::token_object::update_policy),
+
+ // object transfer, escrow & claim methods
+ CONTRACT_METHOD2(transfer,ww::exchange::token_object::transfer),
+ CONTRACT_METHOD2(escrow,ww::exchange::token_object::escrow),
+ CONTRACT_METHOD2(escrow_attestation,ww::exchange::token_object::escrow_attestation),
+ CONTRACT_METHOD2(release,ww::exchange::token_object::release),
+ CONTRACT_METHOD2(claim,ww::exchange::token_object::claim),
+
+ { NULL, NULL }
+};
diff --git a/medperf-contract/easy_test.sh b/medperf-contract/easy_test.sh
new file mode 100755
index 0000000..af361cb
--- /dev/null
+++ b/medperf-contract/easy_test.sh
@@ -0,0 +1,6 @@
+source ${PDO_SOURCE_ROOT}/build/common-config.sh
+source ${PDO_INSTALL_ROOT}'/bin/activate'
+make -C ${PDO_CONTRACTS_ROOT}
+make -C ${PDO_CONTRACTS_ROOT} install
+$PDO_CONTRACTS_ROOT/medperf-contract/test/mp_test.sh --host $PDO_HOSTNAME --ledger $PDO_LEDGER_URL
+deactivate
diff --git a/medperf-contract/etc/guardian_service.toml b/medperf-contract/etc/guardian_service.toml
new file mode 100644
index 0000000..c3d115a
--- /dev/null
+++ b/medperf-contract/etc/guardian_service.toml
@@ -0,0 +1,69 @@
+# Copyright 2024 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# --------------------------------------------------
+# GuardianService -- general information about the guardian service
+# --------------------------------------------------
+[GuardianService]
+# Identity is a string used to identify the service in log files
+Identity = "${identity}"
+HttpPort = 7900
+Host = "${host}"
+
+# --------------------------------------------------
+# StorageService -- information about passing kv stores
+# --------------------------------------------------
+[StorageService]
+URL = "http://${host}:7901"
+KeyValueStore = "${data}/guardian_service.mdb"
+BlockStore = "${data}/guardian_service.mdb"
+Identity = "${identity}"
+HttpPort = 7901
+Host = "${host}"
+GarbageCollectionInterval = 0
+MaxDuration = 0
+
+# --------------------------------------------------
+# Keys -- configuration for retrieving service keys
+# --------------------------------------------------
+[Key]
+SearchPath = [ ".", "./keys", "${keys}" ]
+FileName = "${identity}_private.pem"
+
+# --------------------------------------------------
+# Logging -- configuration of service logging
+# --------------------------------------------------
+[Logging]
+LogLevel = "INFO"
+LogFile = "${logs}/${identity}.log"
+
+# --------------------------------------------------
+# Data -- names for the various databases
+# --------------------------------------------------
+[Data]
+EndpointRegistry = "${data}/endpoints.db"
+CapabilityKeyStore = "${data}/keystore.db"
+
+# --------------------------------------------------
+# TokenIssuer -- configuration for TI verification
+# --------------------------------------------------
+[TokenIssuer]
+LedgerKey = ""
+CodeHash = ""
+ContractIDs = []
+
+# --------------------------------------------------
+# TokenObject -- configuration for TO verification
+# --------------------------------------------------
+[TokenObject]
diff --git a/medperf-contract/etc/medperf.toml b/medperf-contract/etc/medperf.toml
new file mode 100644
index 0000000..9dafa21
--- /dev/null
+++ b/medperf-contract/etc/medperf.toml
@@ -0,0 +1,19 @@
+# Copyright 2024 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# -----------------------------------------------------------------
+# medperf family contract source
+# -----------------------------------------------------------------
+[ContractFamily.medperf]
+token_object = { source = "${home}/contracts/medperf/_medperf_token_object.b64" }
diff --git a/medperf-contract/medperf/contracts/token_object.cpp b/medperf-contract/medperf/contracts/token_object.cpp
new file mode 100644
index 0000000..8c921a4
--- /dev/null
+++ b/medperf-contract/medperf/contracts/token_object.cpp
@@ -0,0 +1,567 @@
+/* Copyright 2024 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+// #include
+#include
+#include
+#include
+#include "Dispatch.h"
+
+#include "Cryptography.h"
+#include "KeyValue.h"
+#include "Environment.h"
+#include "Message.h"
+#include "Response.h"
+#include "Types.h"
+#include "Util.h"
+#include "Value.h"
+#include "WasmExtensions.h"
+
+#include "contract/attestation.h"
+#include "contract/base.h"
+#include "exchange/token_object.h"
+#include "medperf/token_object.h"
+
+
+static KeyValueStore dataset_TO_store("dataset_TO_store");
+static const std::string dataset_id_KEY("dataset_id");
+static const std::string experiment_id_KEY("experiment_id");
+static const std::string associated_model_ids_KEY("associated_model_ids");
+static const std::string associated_model_tags_KEY("associated_model_tags");
+static const std::string dataset_max_use_count_KEY("dataset_max_use_count");
+static const std::string dataset_current_use_count_KEY("dataset_current_use_count");
+static const std::string pdo_challenge_KEY("pdo_challenge");
+
+static const std::string dataset_use_capability_kv_store_encryption_key_KEY("dataset_use_capability_kv_store_encryption_key");
+static const std::string dataset_use_capability_kv_store_root_block_hash_KEY("dataset_use_capability_kv_store_root_block_hash");
+static const std::string dataset_use_capability_kv_store_input_key_KEY("dataset_use_capability_kv_store_input_key");
+
+//
+
+// -----------------------------------------------------------------
+// METHOD: initialize
+//
+// 1. Store the dataset_id (hash of the dataset) that is tokenized. This information should be generated by the dataset owner. The dataset_id is not cross-checked with the dataset itself for now.
+// 2. For testing purposes, the experiment_id is associated with the dataset_token at this step, which implies that the dataset is by default consent to be inferenced by all the models under the associated experiment.
+// We will Initilize the token object with no experiment/model association. The association will be done via an additional association method.
+// 3. The model_id are also stored in the token object. The model_id is the path to the modelcubes. (So far we assume all model matierials are stored locally)
+//
+// Note that the token object is intentionally kept generic and not hard-coded to any specific model.
+// -------------------------------------------------------------------------------------------------------------
+bool ww::medperf::token_object::initialize(const Message &msg, const Environment &env, Response &rsp)
+{
+ ASSERT_SENDER_IS_CREATOR(env, rsp);
+ ASSERT_UNINITIALIZED(rsp);
+
+ // print the message to the log
+
+
+ ASSERT_SUCCESS(rsp, msg.validate_schema(DATASET_TO_INIT_PARAM_SCHEMA),
+ "invalid request, missing required parameters for medperf dataset token object initialization");
+
+ // Get the params to be stored in dataset_TO_store
+ const std::string dataset_id_value(msg.get_string("dataset_id"));
+
+ // Store params from msg in dataset_TO_store
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_id_KEY, dataset_id_value), "failed to store dataset_id");
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(experiment_id_KEY, "none"), "failed to store experiment_id");
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_ids_KEY, "none"), "failed to store associated_model_ids");
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_max_use_count_KEY, 0), "failed to store dataset_max_use_count");
+
+ // Set current use count to 0
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_current_use_count_KEY, (uint32_t)0), "failed to store dataset_current_use_count");
+
+ // Do the rest of the initialization of the token object via the initialize method in the exchange contract
+ ww::value::Structure to_message(TO_INITIALIZE_PARAM_SCHEMA);
+
+ const std::string ledger_verifying_key(msg.get_string("ledger_verifying_key"));
+ ww::value::Object initialization_package;
+ msg.get_value("initialization_package", initialization_package);
+ ww::value::Object asset_authority_chain;
+ msg.get_value("asset_authority_chain", asset_authority_chain);
+
+ ASSERT_SUCCESS(rsp, to_message.set_string("ledger_verifying_key", ledger_verifying_key.c_str()), "unexpected error: failed to set the parameter");
+ ASSERT_SUCCESS(rsp, to_message.set_value("initialization_package", initialization_package), "unexpected error: failed to set the parameter");
+ ASSERT_SUCCESS(rsp, to_message.set_value("asset_authority_chain", asset_authority_chain), "unexpected error: failed to set the parameter");
+
+ return ww::exchange::token_object::initialize(to_message, env, rsp);
+}
+
+
+// update_policy attaches the policy
+// bool ww::medperf::token_object::update_policy(const Message &msg, const Environment &env, Response &rsp)
+// {
+// // only the owner can
+// ASSERT_SENDER_IS_CREATOR(env, rsp);
+// ASSERT_UNINITIALIZED(rsp);
+// }
+
+// -----------------------------------------------------------------
+// METHOD: get_dataset_info
+//
+// Return fixed model parameters, schema for user-specified model parameters, and
+// model metadata useful for the TO to understand how to use the model required to invoke Inference API.
+// Method is public, and can be invoked by PDO user.
+// note that we are not returning the "remaining use count" as part of the model info.
+// ideally a prospective token buyer would like access to "remaining use count" before purchasing the token.
+// In such a case, ideally such information shall be provided only after escrow of payment for the token is done.
+// Left for future enhancement.
+// -----------------------------------------------------------------
+
+bool ww::medperf::token_object::get_dataset_info(
+ const Message &msg,
+ const Environment &env,
+ Response &rsp)
+{
+ ASSERT_INITIALIZED(rsp);
+ // ww::value::Structure v(DATASET_INFO_SCHEMA);
+ ww::value::Object v;
+
+ // Get the dataset_id
+ std::string dataset_id_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_id_KEY, dataset_id_string), "failed to retrieve dataset_id");
+ ASSERT_SUCCESS(rsp, v.set_string("dataset_id", dataset_id_string.c_str()), "failed to set return value for dataset_id");
+
+
+ std::string associated_model_ids_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_ids_KEY, associated_model_ids_string), "failed to retrieve associated_model_ids");
+ ASSERT_SUCCESS(rsp, v.set_string("associated_model_ids", associated_model_ids_string.c_str()), "failed to set return value for associated_model_ids");
+
+
+ std::string experiment_id_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(experiment_id_KEY, experiment_id_string), "failed to retrieve experiment_id_string");
+ ASSERT_SUCCESS(rsp, v.set_string("experiment_id", experiment_id_string.c_str()), "failed to set return value for experiment_id_string");
+
+ std::string associated_model_tags_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_tags_KEY, associated_model_tags_string), "failed to retrieve associated_model_tags");
+ ASSERT_SUCCESS(rsp, v.set_string("associated_model_tags", associated_model_tags_string.c_str()), "failed to set return value for associated_model_tags");
+
+ // Get the max use count
+ uint32_t dataset_max_use_count_value;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_max_use_count_KEY, dataset_max_use_count_value), "failed to retrieve dataset_max_use_count");
+ ASSERT_SUCCESS(rsp, v.set_number("max_use_count", dataset_max_use_count_value), "failed to set return value for max_use_count");
+
+ return rsp.value(v, false);
+}
+
+// -----------------------------------------------------------------
+// METHOD: use_dataset
+//
+// 1. Save the parameters required to generate a use_dataset capability to kvs, increments the current use count, and returns the call
+// Capability is calculated and returned once proof of commit of state is presented (via the get_capability method).
+// 2. Inputs:
+// kvstore_encryption_key
+// kvstore_root_block_hash
+// kvstore_input_key
+// model_ids_to_evaluate
+// The first 3 parameters provide flexibility to use large inputs for the model via the kv_store attached to the guardian.
+// Only TO may invoke method
+// -----------------------------------------------------------------
+bool ww::medperf::token_object::use_dataset(
+ const Message &msg,
+ const Environment &env,
+ Response &rsp)
+{
+ ASSERT_SENDER_IS_OWNER(env, rsp);
+ ASSERT_INITIALIZED(rsp);
+
+ ASSERT_SUCCESS(rsp, msg.validate_schema(USE_DATASET_SCHEMA), "invalid request, missing required parameters");
+
+ const std::string dataset_id(msg.get_string("dataset_id"));
+ std::string dataset_id_store;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_id_KEY, dataset_id_store), "fail to retrieve dataset_id");
+ ASSERT_SUCCESS(rsp, dataset_id == dataset_id_store, "dataset does not exist");
+
+ const std::string kvstore_encryption_key(msg.get_string("kvstore_encryption_key"));
+ const std::string kvstore_root_block_hash(msg.get_string("kvstore_root_block_hash"));
+ const std::string kvstore_input_key(msg.get_string("kvstore_input_key"));
+
+
+ std::string associated_model_ids_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_ids_KEY, associated_model_ids_string), "failed to retrieve associated_model_ids");
+ uint32_t associated_model_ids = std::stoi(associated_model_ids_string);
+
+ std::string model_ids_to_evaluate_string(msg.get_string("model_ids_to_evaluate"));
+ const uint32_t model_ids_to_evaluate = std::stoi(model_ids_to_evaluate_string) - 1;
+ ASSERT_SUCCESS(rsp, model_ids_to_evaluate < associated_model_ids, "model is not associated with the dataset");
+
+ std::string associated_model_tags_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_tags_KEY, associated_model_tags_string), "failed to retrieve associated_model_tags");
+ ww::types::StringArray associated_model_tags_vec(associated_model_tags_string);
+ ASSERT_SUCCESS(rsp, associated_model_tags_vec[model_ids_to_evaluate] == '0', "model has already been scheduled or used");
+
+ uint32_t dataset_current_use_count_value;
+ uint32_t dataset_max_use_count_value;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_current_use_count_KEY, dataset_current_use_count_value), "failed to retrieve dataset_current_use_count");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_max_use_count_KEY, dataset_max_use_count_value), "failed to retrieve dataset_max_use_count");
+ ASSERT_SUCCESS(rsp, dataset_current_use_count_value + 1 <= dataset_max_use_count_value, "max use count is reached, cannot use dataset");
+
+ // '1' represents that the model is scheduled for evaluation
+ associated_model_tags_vec[model_ids_to_evaluate] = '1';
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_tags_KEY, associated_model_tags_vec.str().c_str()), "failed to update associated_model_tags");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_current_use_count_KEY, dataset_current_use_count_value + 1), "failed to update dataset_current_use_count");
+
+ // ww::types::StringArray model_ids_to_evaluate_vec(model_ids_to_evaluate);
+ // uint32_t num_models_to_evaluate = std::count(model_ids_to_evaluate_vec.begin(), model_ids_to_evaluate_vec.end(), ',') + 1;
+
+ // ASSERT_SUCCESS(rsp, num_models_to_evaluate > 0, "invalid request, no models to evaluate");
+
+ // std::string associated_model_ids_string;
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_ids_KEY, associated_model_ids_string), "failed to retrieve associated_model_ids");
+ // ww::types::StringArray associated_model_ids_vec(associated_model_ids_string);
+ // uint32_t num_associated_models = std::count(associated_model_ids_vec.begin(), associated_model_ids_vec.end(), ',') + 1;
+
+ // std::vector associated_models = stringToVector(associated_model_ids_string);
+ // std::vector to_evaluate_models = stringToVector(model_ids_to_evaluate);
+ // std::vector model_index;
+ // std::string error_message;
+ // for (std::string to_eva_model_id : to_evaluate_models)
+ // {
+ // error_message = to_eva_model_id + " not associated with the dataset";
+ // ASSERT_SUCCESS(rsp, std::find(associated_models.begin(), associated_models.end(), to_eva_model_id) != associated_models.end(), error_message.c_str());
+ // model_index.push_back(std::find(associated_models.begin(), associated_models.end(), to_eva_model_id) - associated_models.begin());
+ // }
+
+
+ // uint32_t dataset_current_use_count_value;
+ // uint32_t dataset_max_use_count_value;
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_current_use_count_KEY, dataset_current_use_count_value), "failed to retrieve dataset_current_use_count");
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_max_use_count_KEY, dataset_max_use_count_value), "failed to retrieve dataset_max_use_count");
+ // ASSERT_SUCCESS(rsp, dataset_current_use_count_value + num_models_to_evaluate <= dataset_max_use_count_value, "max use count is reached, cannot use dataset");
+
+ // // Add the counter if the use_dataset is successful
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_current_use_count_KEY, dataset_current_use_count_value + num_models_to_evaluate), "failed to update dataset_current_use_count");
+
+ // // change the status of the model_ids to "scheduled"
+ // // const std::string associated_model_ids_to_be_stored = associated_model_ids_json.dump();
+ // const std::string associated_model_ids_to_be_stored = mapToString(associated_model_ids_map);
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_ids_KEY, associated_model_ids_to_be_stored), "failed to store associated_model_ids");
+
+ // store the parameters required to generate a use_dataset capability
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_use_capability_kv_store_encryption_key_KEY, kvstore_encryption_key), "failed to store dataset_use_capability_kv_store_enc_key");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_use_capability_kv_store_root_block_hash_KEY, kvstore_root_block_hash), "failed to store dataset_use_capability_kv_store_hash");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_use_capability_kv_store_input_key_KEY, kvstore_input_key), "failed to store dataset_use_capability_kv_store_input_key");
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_use_capability_user_inputs_KEY, user_inputs), "failed to store dataset_use_capability_user_inputs");
+
+ return rsp.success(true);
+}
+
+
+
+
+// -----------------------------------------------------------------
+// METHOD: get_capability
+//
+// Check proof of commit, calculate/return capability.
+// Only TO may invoke method. It is currently possible for the TO to ask for a past capability
+// even after token transfer. This is a feature, not a bug. The justification is that
+// any new owner is only getting access to "unused uses" of the model.
+// -----------------------------------------------------------------
+
+bool ww::medperf::token_object::get_capability(
+ const Message &msg,
+ const Environment &env,
+ Response &rsp)
+{
+ ASSERT_SENDER_IS_OWNER(env, rsp);
+ ASSERT_INITIALIZED(rsp);
+ ASSERT_SUCCESS(rsp, msg.validate_schema(GET_CAPABILITY_SCHEMA), "invalid request, missing required parameters");
+
+ // Ensure that the current use count is greater than 0, so that an attempt to use the model was made.
+ // Otherwise, the capability cannot be generated.ls
+ // uint32_t dataset_current_use_count_value;
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_current_use_count_KEY, dataset_current_use_count_value), "failed to retrieve dataset_current_use_count");
+ // ASSERT_SUCCESS(rsp, dataset_current_use_count_value > 0, "invalid request, capability can be obtained only after use_dataset is called");
+
+ // check for proof of commit of current state of the token object before returning capability
+ std::string ledger_key;
+ if (!ww::contract::attestation::get_ledger_key(ledger_key) && ledger_key.length() > 0)
+ return rsp.error("contract has not been initialized");
+
+ const std::string ledger_signature(msg.get_string("ledger_signature"));
+
+ ww::types::ByteArray buffer;
+ std::copy(env.contract_id_.begin(), env.contract_id_.end(), std::back_inserter(buffer));
+ std::copy(env.state_hash_.begin(), env.state_hash_.end(), std::back_inserter(buffer));
+
+ ww::types::ByteArray signature;
+ if (!ww::crypto::b64_decode(ledger_signature, signature))
+ return rsp.error("failed to decode ledger signature");
+ if (!ww::crypto::ecdsa::verify_signature(buffer, ledger_key, signature))
+ return rsp.error("failed to verify ledger signature");
+
+ // the current state has been committed so now compute and return the capability
+ ww::value::Structure params(GENERATE_CAPABILITY_SCHEMA);
+
+ // Get kvstore_encryption_key from dataset_TO_store
+ std::string kvstore_encryption_key;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_use_capability_kv_store_encryption_key_KEY, kvstore_encryption_key), "failed to retrieve dataset_use_capability_kv_store_enc_key");
+ ASSERT_SUCCESS(rsp, params.set_string("kvstore_encryption_key", kvstore_encryption_key.c_str()), "failed to set return value for kvstore_encryption_key");
+
+ // Get kvstore_root_block_hash from dataset_TO_store
+ std::string kvstore_root_block_hash;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_use_capability_kv_store_root_block_hash_KEY, kvstore_root_block_hash), "failed to retrieve dataset_use_capability_kv_store_hash");
+ ASSERT_SUCCESS(rsp, params.set_string("kvstore_root_block_hash", kvstore_root_block_hash.c_str()), "failed to set return value for kvstore_root_block_hash");
+
+ // Get kvstore_input_key from dataset_TO_store
+ std::string kvstore_input_key;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_use_capability_kv_store_input_key_KEY, kvstore_input_key), "failed to retrieve dataset_use_capability_kv_store_input_key");
+ ASSERT_SUCCESS(rsp, params.set_string("kvstore_input_key", kvstore_input_key.c_str()), "failed to set return value for kvstore_input_key");
+
+ // Get dataset_id from dataset_TO_store
+ std::string dataset_id_store;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_id_KEY, dataset_id_store), "failed to retrieve dataset_id");
+ std::string dataset_id_order(msg.get_string("dataset_id"));
+ ASSERT_SUCCESS(rsp, dataset_id_store == dataset_id_order, "dataset does not exist");
+ ASSERT_SUCCESS(rsp, params.set_string("dataset_id", dataset_id_store.c_str()), "failed to set return value for dataset_id");
+
+ // Get associated_model_ids from dataset_TO_store
+ std::string associated_model_tags_string;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(associated_model_tags_KEY, associated_model_tags_string), "failed to retrieve associated_model_tags");
+ ww::types::StringArray associated_model_tags_vec(associated_model_tags_string);
+ std::string model_id_to_evaluate_string = "";
+
+ for (size_t i = 0; i < associated_model_tags_vec.size(); i++)
+ {
+ if (associated_model_tags_vec[i] == '1')
+ {
+ model_id_to_evaluate_string += std::to_string(i+1) + ",";
+ associated_model_tags_vec[i] = '2';
+
+ }
+ }
+ model_id_to_evaluate_string.pop_back();
+
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_tags_KEY, associated_model_tags_vec.str().c_str()), "failed to store associated_model_ids");
+ ASSERT_SUCCESS(rsp, params.set_string("model_ids_to_evaluate", model_id_to_evaluate_string.c_str()), "failed to set return value for model_ids_to_evaluate");
+
+
+ // Calculate capability
+ ww::value::Object result;
+ ASSERT_SUCCESS(rsp, ww::exchange::token_object::create_operation_package("use_dataset", params, result),
+ "unexpected error: failed to generate capability");
+
+ // this assumes that generating the capability changes state
+ return rsp.value(result, true);
+}
+
+// -----------------------------------------------------------------
+// Method: return a hello world message
+// -----------------------------------------------------------------
+
+bool ww::medperf::token_object::owner_test(
+ const Message &msg,
+ const Environment &env,
+ Response &rsp)
+{
+ // check if this is called by the owner
+ ASSERT_SENDER_IS_OWNER(env, rsp);
+ ww::value::String result("owner!");
+ return rsp.value(result, false);
+}
+
+// -----------------------------------------------------------------
+// Method: check if the sender is the creator
+// -----------------------------------------------------------------
+
+bool ww::medperf::token_object::update_policy(
+ const Message &msg,
+ const Environment &env,
+ Response &rsp)
+{
+ // check if this is called by the creator
+ ASSERT_SENDER_IS_CREATOR(env, rsp);
+
+ // schema validation
+ ASSERT_SUCCESS(rsp, msg.validate_schema(UPDATE_POLICY_SCHEMA), "invalid request, missing required parameters");
+
+ ww::value::Structure result(DATASET_INFO_SCHEMA);
+
+
+ const std::string dataset_id_value(msg.get_string("dataset_id"));
+ std::string dataset_id_value_from_store;
+ ASSERT_SUCCESS(rsp, dataset_TO_store.get(dataset_id_KEY, dataset_id_value_from_store), "failed to retrieve dataset_id");
+ ASSERT_SUCCESS(rsp, dataset_id_value_from_store == dataset_id_value, "dataset does not exist");
+ ASSERT_SUCCESS(rsp, result.set_string("dataset_id", dataset_id_value.c_str()), "failed to set return value for dataset_id");
+
+ std::string experiment_id_value(msg.get_string("experiment_id"));
+ // ASSERT_SUCCESS(rsp, msg.get_string("experiment_id", experiment_id_value), "failed to retrieve experiment_id");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(experiment_id_KEY, experiment_id_value), "failed to store experiment_id");
+ ASSERT_SUCCESS(rsp, result.set_string("experiment_id", experiment_id_value.c_str()), "failed to set return value for experiment_id");
+
+ const std::string associated_model_ids_value(msg.get_string("associated_model_ids"));
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_ids_KEY, associated_model_ids_value), "failed to store associated_model_ids");
+ ASSERT_SUCCESS(rsp, result.set_string("associated_model_ids", associated_model_ids_value.c_str()), "failed to set return value for associated_model_ids");
+
+ // size_t model_count;
+ // ww::types::StringArray associated_model_ids_for_tag_string(associated_model_ids_value);
+ // model_count = std::count(associated_model_ids_for_tag_string.begin(), associated_model_ids_for_tag_string.end(), ',') + 1;
+
+ size_t model_count = std::stoi(associated_model_ids_value);
+ const std::string associated_model_tags_value(model_count, '0');
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_tags_KEY, associated_model_tags_value.c_str()), "failed to store associated_model_tags");
+ ASSERT_SUCCESS(rsp, result.set_string("associated_model_tags", associated_model_tags_value.c_str()), "failed to set return value for associated_model_tags");
+ // ww::value::Array associated_model_ids_array = splitString(associated_model_ids_value.c_str(), ',');
+
+
+ // std::vector associated_model_vec = stringToVector(associated_model_ids_value);
+ // set the associated_model_tag for each model_id in associated_model_ids to '0'
+ // std::vector associated_model_tags_vec(associated_model_vec.size(), '0');
+ // const std::string associated_model_tags_value = vectorToString(associated_model_tags_vec);
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_tags_KEY, associated_model_tags_value), "failed to store associated_model_tags");
+
+ // removed for testing
+ // =============================================
+ // std::vector associated_model_ids = stringToVector(associated_model_ids_value);
+ // std::map associated_model_ids_map;
+ // for (auto model_id : associated_model_ids)
+ // {
+ // associated_model_ids_map[model_id] = "not used";
+ // }
+ // const std::string associated_model_to_be_stored = mapToString(associated_model_ids_map);
+ // ASSERT_SUCCESS(rsp, dataset_TO_store.set(associated_model_ids_KEY, associated_model_to_be_stored), "failed to store associated_model_ids");
+
+ const uint32_t dataset_max_use_count_value = (uint32_t)msg.get_number("max_use_count");
+ ASSERT_SUCCESS(rsp, dataset_TO_store.set(dataset_max_use_count_KEY, dataset_max_use_count_value), "failed to store dataset_max_use_count");
+ ASSERT_SUCCESS(rsp, result.set_number("max_use_count", dataset_max_use_count_value), "failed to set return value for max_use_count");
+ // ww::value::String result("Policy updated!");
+
+ return rsp.value(result, true);
+ // return rsp.success(true);
+}
+
+
+
+std::string mapToString(const std::map& myMap) {
+ std::ostringstream oss; // Create a string stream
+ oss << "{";
+ for (auto it = myMap.begin(); it != myMap.end(); ++it) {
+ oss << "\"" << it->first << "\": \"" << it->second << "\"";
+ if (std::next(it) != myMap.end()) {
+ oss << ", "; // Add a comma, except for the last item
+ }
+ }
+ oss << "}";
+ return oss.str(); // Return the formatted string
+}
+
+std::map stringToMap(const std::string& str) {
+ std::map myMap;
+ size_t start = 0;
+ size_t end = 0;
+
+ // Check if the string starts with '{' and ends with '}'
+ if (str.front() == '{' && str.back() == '}') {
+ start = 1; // Skip '{'
+ end = str.size() - 1; // Calculate end position
+ } else {
+ return myMap; // Return an empty map if format is incorrect
+ }
+
+ while (start < end) {
+ size_t colonPos = str.find(':', start); // Find the position of ':'
+ size_t keyStart = str.find('"', start) + 1; // Find the key start position
+ size_t keyEnd = str.find('"', keyStart); // Find the key end position
+
+ if (keyEnd == std::string::npos || colonPos == std::string::npos || keyEnd > colonPos) {
+ break; // Exit if format is incorrect
+ }
+
+ std::string key = str.substr(keyStart, keyEnd - keyStart); // Get the key
+ size_t valueStart = colonPos + 1; // Start position of value
+ size_t valueEnd = str.find(',', valueStart); // Find the next ',' position
+
+ if (valueEnd == std::string::npos) {
+ valueEnd = end; // If no ',' found, set to the end
+ }
+
+ // Remove whitespace after ':' and before the starting quote of the value
+ size_t valueQuoteStart = str.find('"', valueStart);
+ size_t valueQuoteEnd = str.find('"', valueQuoteStart + 1); // Find the value end
+
+ std::string value = str.substr(valueQuoteStart + 1, valueQuoteEnd - valueQuoteStart - 1); // Get value
+
+ myMap[key] = value; // Add to the map
+ start = valueEnd + 1; // Update the start position
+ }
+
+ return myMap; // Return the constructed map
+}
+
+std::vector stringToVector(const std::string& str) {
+ std::vector result;
+ std::string::size_type start = 0;
+ std::string::size_type end = str.find(',');
+
+ while (end != std::string::npos) {
+ result.push_back(str.substr(start, end - start));
+ start = end + 1;
+ end = str.find(',', start);
+ }
+ result.push_back(str.substr(start));
+
+ return result;
+}
+
+std::string vectorToString(const std::vector& vec) {
+ std::string result = "{";
+ for (size_t i = 0; i < vec.size(); ++i) {
+ result += "\"" + vec[i] + "\"";
+ if (i < vec.size() - 1) {
+ result += ", ";
+ }
+ }
+ result += "}";
+ return result;
+}
+
+// // splitString takes a string and a delimiter character and returns a ww::value::Array
+// ww::value::Array splitString(const std::string& str, char delimiter) {
+// ww::value::Array result;
+// ww::value::Object model_map;
+// std::stringstream ss(str);
+// std::string item;
+
+// while (std::getline(ss, item, delimiter)) {
+// model_map.set_value(item.c_str(), ww::value::String("not used"));
+// result.append_value(model_map);
+// }
+
+// return result;
+// }
+
+
+std::vector splitForTags(const std::string& str) {
+ std::vector result;
+ std::stringstream ss(str);
+ std::string item;
+
+ while (std::getline(ss, item, ',')) {
+ result.push_back('0');
+ }
+
+ return result;
+}
+
+std::string joinString(const std::vector& vec, char delimiter) {
+ std::string result;
+ for (const auto& item : vec) {
+ result += item + delimiter;
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/medperf-contract/medperf/token_object.h b/medperf-contract/medperf/token_object.h
new file mode 100644
index 0000000..b794b9d
--- /dev/null
+++ b/medperf-contract/medperf/token_object.h
@@ -0,0 +1,113 @@
+/* Copyright 2023 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include
+#include
+#include