Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-issuer support for wallets #46

Merged
merged 6 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docker/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -197,23 +197,23 @@ clean_repository :
# this would set in a make.loc
TEST_COMPOSE_ARGS += -f test.yaml

test : clean_config clean_repository clean_models build_contracts
test : clean_config clean_repository build_contracts
- PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
$(DOCKER_COMPOSE_COMMAND) $(TEST_COMPOSE_ARGS) up --abort-on-container-exit
PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
$(DOCKER_COMPOSE_COMMAND) $(TEST_COMPOSE_ARGS) down

JUPYTER_COMPOSE_ARGS += -f test_jupyter.yaml

test_jupyter : clean_config clean_repository clean_models build_contracts
test_jupyter : clean_config clean_repository build_contracts
- PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
$(DOCKER_COMPOSE_COMMAND) $(JUPYTER_COMPOSE_ARGS) up --abort-on-container-exit
PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
$(DOCKER_COMPOSE_COMMAND) $(JUPYTER_COMPOSE_ARGS) down

JUPYTER_MULTIUSER_COMPOSE_ARGS += -f test_multiuser_jupyter.yaml

test_multiuser_jupyter : clean_config clean_repository clean_models build_contracts
test_multiuser_jupyter : clean_config clean_repository build_contracts
- PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
docker-compose $(JUPYTER_MULTIUSER_COMPOSE_ARGS) up --abort-on-container-exit
PDO_VERSION=$(PDO_VERSION) CONTRACTS_VERSION=$(CONTRACTS_VERSION) \
Expand Down
22 changes: 11 additions & 11 deletions docs/notebooks/documents/getting_started.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
# Additional management of keys is provided by the [Key Manager Notebook](key_manager.ipynb).
#
# %%
from pdo.contracts.keys import PrivateKeyListWidget
from pdo.contracts.keys import PublicKeyListWidget
from pdo.contracts.keys import GenerateKeyWidget
from pdo.contracts.keys import UploadKeyWidget
from pdo.contracts.jupyter.keys import PrivateKeyListWidget
from pdo.contracts.jupyter.keys import PublicKeyListWidget
from pdo.contracts.jupyter.keys import GenerateKeyWidget
from pdo.contracts.jupyter.keys import UploadKeyWidget

private_key_list = PrivateKeyListWidget(state, bindings)
public_key_list = PublicKeyListWidget(state, bindings)
Expand All @@ -77,9 +77,9 @@
# [Service Manager Notebook](service_manager.ipynb)
#
# %%
from pdo.contracts.services import ServiceListWidget
from pdo.contracts.services import ServiceUploadWidget
from pdo.contracts.services import service_labels
from pdo.contracts.jupyter.services import ServiceListWidget
from pdo.contracts.jupyter.services import ServiceUploadWidget
from pdo.contracts.jupyter.services import service_labels

children = map(lambda stype : ServiceListWidget(state, bindings, stype), service_labels.keys())
titles = service_labels.values()
Expand All @@ -97,10 +97,10 @@
# Additional management of service group information is provided by the [Service Groups Manager
# Notebook](service_groups_manager.ipynb)
# %%
from pdo.contracts.groups import ServiceGroupListWidget
from pdo.contracts.groups import EnclaveServiceGroupCreateWidget
from pdo.contracts.groups import ProvisioningServiceGroupCreateWidget
from pdo.contracts.groups import StorageServiceGroupCreateWidget
from pdo.contracts.jupyter.groups import ServiceGroupListWidget
from pdo.contracts.jupyter.groups import EnclaveServiceGroupCreateWidget
from pdo.contracts.jupyter.groups import ProvisioningServiceGroupCreateWidget
from pdo.contracts.jupyter.groups import StorageServiceGroupCreateWidget
# %% [markdown]
# ### List Service Groups
#
Expand Down
10 changes: 5 additions & 5 deletions docs/notebooks/documents/service_groups_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
import IPython.display as ip_display
import ipywidgets

from pdo.contracts.services import service_labels
from pdo.contracts.groups import ServiceGroupListWidget
from pdo.contracts.groups import EnclaveServiceGroupCreateWidget
from pdo.contracts.groups import ProvisioningServiceGroupCreateWidget
from pdo.contracts.groups import StorageServiceGroupCreateWidget
from pdo.contracts.jupyter.services import service_labels
from pdo.contracts.jupyter.groups import ServiceGroupListWidget
from pdo.contracts.jupyter.groups import EnclaveServiceGroupCreateWidget
from pdo.contracts.jupyter.groups import ProvisioningServiceGroupCreateWidget
from pdo.contracts.jupyter.groups import StorageServiceGroupCreateWidget

pc_jupyter.load_ipython_extension(get_ipython())

Expand Down
4 changes: 2 additions & 2 deletions docs/notebooks/documents/service_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import IPython.display as ip_display
import ipywidgets

from pdo.contracts.services import ServiceUploadWidget, ServiceSelectionWidget, ServiceListWidget
from pdo.contracts.services import service_labels, get_by_url, update_service
from pdo.contracts.jupyter.services import ServiceUploadWidget, ServiceSelectionWidget, ServiceListWidget
from pdo.contracts.jupyter.services import service_labels, get_by_url, update_service

pc_jupyter.load_ipython_extension(get_ipython())

Expand Down
4 changes: 2 additions & 2 deletions docs/notebooks/documents/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import IPython.display as ip_display
import ipywidgets

from pdo.contracts.services import service_labels, ServiceSelectionWidget
from pdo.contracts.groups import ServiceGroupSelectionWidget
from pdo.contracts.jupyter.services import service_labels, ServiceSelectionWidget
from pdo.contracts.jupyter.groups import ServiceGroupSelectionWidget

pc_jupyter.load_ipython_extension(get_ipython())

Expand Down
14 changes: 9 additions & 5 deletions exchange-contract/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ etc/exchange.toml
pdo/__init__.py
pdo/contracts/__init__.py
pdo/contracts/common.py
pdo/contracts/groups.py
pdo/contracts/jupyter.py
pdo/contracts/keys.py
pdo/contracts/services.py
pdo/contracts/jupyter/__init__.py
pdo/contracts/jupyter/common_widgets.py
pdo/contracts/jupyter/groups.py
pdo/contracts/jupyter/keys.py
pdo/contracts/jupyter/services.py
pdo/contracts/jupyter/utility.py
pdo/exchange/__init__.py
pdo/exchange/jupyter.py
pdo/exchange/jupyter/__init__.py
pdo/exchange/jupyter/context.py
pdo/exchange/jupyter/wallet.py
pdo/exchange/plugins/__init__.py
pdo/exchange/plugins/asset_type.py
pdo/exchange/plugins/exchange.py
Expand Down
1 change: 1 addition & 0 deletions exchange-contract/contracts/token_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ contract_method_reference_t contract_method_dispatch_table[] = {
CONTRACT_METHOD(echo),

// object transfer, escrow & claim methods
CONTRACT_METHOD2(get_balance,ww::exchange::token_object::get_balance),
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),
Expand Down
30 changes: 4 additions & 26 deletions exchange-contract/docs/notebooks/factories/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# ---

# %% [markdown]
# *WORK IN PROGRESS*
# # Wallet Factory
#
# Use this notebook to create a wallet associated with a particular issuer.
Expand All @@ -39,28 +38,7 @@

# %%
wallet_owner = input('Identity of the wallet owner: ')
asset_name = input('Name of the asset: ')
import_file = input('Name of the asset import file: ')

# %% [markdown]
# ### Initialize the PDO Environment
#
# Initialize the PDO environment. This assumes that a functional PDO configuration is in place and
# that the PDO virtual environment has been activated. In particular, ensure that the groups file
# and eservice database have been configured correctly.
#
# For the most part, no modifications should be required below.
# %%
common_bindings = {
'wallet_owner' : wallet_owner,
'asset_name' : asset_name,
}

(state, bindings) = pc_jupyter.initialize_environment(wallet_owner, **common_bindings)

context_file = bindings.expand('${etc}/${asset_name}_context.toml')
import_file = bindings.expand(import_file)
_ = pc_jupyter.import_contract_collection(state, bindings, context_file, import_file)
wallet_name = input('Name of the wallet: ')

# %% [markdown]
# ## Create the Wallet Notebook
Expand All @@ -70,10 +48,10 @@
# %%
instance_parameters = {
'wallet_owner' : wallet_owner,
'asset_name' : asset_name,
'context_file' : context_file,
'wallet_name' : wallet_name,
'context_file' : '${etc}/${wallet_name}_context.toml',
}

instance_file = pc_jupyter.instantiate_notebook_from_template(asset_name, 'wallet', instance_parameters)
instance_file = pc_jupyter.instantiate_notebook_from_template(wallet_name, 'wallet', instance_parameters)
ip_display.display(ip_display.Markdown('[Wallet]({})'.format(instance_file)))
# %%
3 changes: 3 additions & 0 deletions exchange-contract/docs/notebooks/templates/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@
issuer_context.set('initialized', True)
pc_jupyter.pbuilder.Context.SaveContextFile(state, context_file, prefix=asset_path)

print('issuer authority approved')

# %% [markdown]
# <hr style="border:2px solid gray">
#
Expand All @@ -161,6 +163,7 @@ def issue_assets(owner, count) :
pc_jupyter.pcommand.invoke_contract_cmd(
pc_jupyter.ex_issuer.cmd_issue_assets, state, issuer_context,
owner=owner, count=count)
print(f'{count} assets issued to {owner}')
except ValueError as v :
print("assets have already been issued to {}".format(owner))

Expand Down
5 changes: 4 additions & 1 deletion exchange-contract/docs/notebooks/templates/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,11 @@ def token_transfer(new_owner) :
# free to change the file name as well. The default uses the asset name.

# %%
# this adds a reference key to "issuer" which makes the wallets work with tokens
context.set('issuer', '@{.token_object.' + token_name + '}')

contract_identifier = '{}_{}'.format(token_class, instance_identifier)
contexts = ['asset_type', 'vetting', 'guardian', 'token_issuer', 'token_object']
contexts = ['asset_type', 'issuer', 'vetting', 'guardian', 'token_issuer', 'token_object']
contract_files = {
'token' : token_context.get('save_file'),
}
Expand Down
93 changes: 37 additions & 56 deletions exchange-contract/docs/notebooks/templates/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,30 @@

# %% [markdown]
# # Wallet Notebook
# *WORK IN PROGRESS*
#
# This notebook is used to manage the assets issued to an indivdual by an issuer contract. The
# notebook assumes that the asset type, vetting, and issuer contract objects have been created.

# %% [markdown] editable=true slideshow={"slide_type": ""}
# <hr style="border:2px solid gray">
#
# ## Configure Asset Information
# ## Configure Wallet Information
#
# This section enables customization wallet. Edit the variables in the section below as necessary.
# * wallet_owner : the identity of the wallet owner
# * asset_name : the name of the asset type to be managed
# This section enables customization of the wallet. Edit the variables in the section below as
# necessary. These may be assigned through the factory interface.
# * wallet_owner : the identity of the wallet owner, default identity for assets
# * wallet_name : a name for customizing the wallet
# * context_file : the name of the context file where asset information is located
#

# %% tags=["parameters"]
wallet_owner = 'user1'
asset_name = 'asset'
context_file = '${etc}/${asset_name}_context.toml'
wallet_name = 'wallet'
context_file = '${etc}/${wallet_name}_context.toml'
instance_identifier = ''

# %% [markdown]
# <hr style="border:2px solid gray">
#
# ## Initialize

# %%
import os
import pdo.contracts.jupyter as pc_jupyter
Expand All @@ -62,82 +59,66 @@
except NameError:
common_bindings = {
'wallet_owner' : wallet_owner,
'asset_name' : asset_name,
'wallet_name' : wallet_name,
'instance' : instance_identifier,
}

(state, bindings) = pc_jupyter.initialize_environment(wallet_owner, **common_bindings)

print('environment initialized')

# %% [markdown]
# ### Initialize the Contract Context
# ### Initialize the Wallet Context
#
# The contract context defines the configuration for a collection of contract objects that interact
# with one another. By default, the context file used in this notebook is specific to the asset
# class. We need the class to ensure that all of the information necessary for the asset itself is
# available. If you prefer to use a common context file, edit the context_file variable below.
#
# For the most part, no other modifications should be required.

# The wallet context defines the configuration for a collection of contract objects that interact
# with one another.
# %%
wallet_path = 'wallet.{}'.format(wallet_name)
context_file = bindings.expand(context_file)
print('using context file {}'.format(context_file))

# Customize the context with the user's identity
context_bindings = {
'identity' : wallet_owner,
}

asset_path = 'asset.' + asset_name
context = pc_jupyter.ex_jupyter.initialize_asset_context(
state, bindings, context_file, asset_path, **context_bindings)
print('context initialized')

# %% [markdown]
# ### Configure the Contract Objects
#
# Set up the connections to each of the contract objects. Although most interactions
# are with the issuer contract object, it may be necessary to verify the authority
# of the other contracts as well.
context = pc_jupyter.common.initialize_context(state, bindings, context_file, wallet_path, [], **context_bindings)
pc_jupyter.pbuilder.Context.SaveContextFile(state, context_file, prefix=wallet_path)

# %%
issuer_context = pc_jupyter.pbuilder.Context(state, asset_path + '.issuer')
issuer_save_file = issuer_context.get('save_file')
print('issuer contract in {}'.format(issuer_save_file))
print('context initialized')

# %% [markdown]
# <hr style="border:2px solid gray">
#
# ## Operate on the Issuer Contract
#
# This section defines several functions that can be used to interact with the issuer contract:
# * get_balance -- get the current number of assets associated with the given identity
# This section defines several functions that can be used to interact with the wallet:
# * import issuers -- add asset handles to the wallet
# * account balance -- list the asset balances for each handle stored in the wallet
# * transfer -- transfer assets from one identity to another

# %% [markdown]
# ### Import Asset Issuers
#
# Import asset issuer contract collections and select an identity to use with the issuer. An asset
# handle is associated with the issuer/identity pair to simpflify other operations. The handle can
# be any name (alphanumeric string).
#
# Note that the veracity of the imported collections is assumed to be addressed out of
# band. Correctness checks are not a part of the import process.
# %%
def get_balance(owner) :
pc_jupyter.pcommand.invoke_contract_cmd(
pc_jupyter.ex_issuer.cmd_get_balance, state, issuer_context, identity=wallet_owner)

def transfer(count, new_owner, old_owner=identity) :
pc_jupyter.pcommand.invoke_contract_cmd(
pc_jupyter.ex_issuer.cmd_transfer_assets, state, issuer_context,
new_owner=new_owner, count=count, identity=old_owner)
pc_jupyter.pcommand.invoke_contract_cmd(
pc_jupyter.ex_issuer.cmd_get_balance, state, issuer_context, identity=old_owner)

import_widget = pc_jupyter.ex_jupyter.ImportIssuerWidget(state, bindings, context_file, wallet_path)
ip_display.display(import_widget)

# %% [markdown]
# ### Account Balance
# %%
# %%skip True
get_balance(wallet_owner)
balance_widget = pc_jupyter.ex_jupyter.AssetBalanceWidget(state, bindings, wallet_path)
ip_display.display(balance_widget)

# %% [markdown]
# ### Transfer Assets
#
# If necessary, use the [Key Manager Notebook](/documents/key_manager.ipynb) to import or create additional
# keys that can be used for the transfer.
# %%
# %%skip True
count = int(input('number of assets to transfer'))
recipient = input('identity of the recipient of the transfer')

transfer(count, recipient, wallet_owner)
transfer_widget = pc_jupyter.ex_jupyter.AssetTransferWidget(state, bindings, wallet_path)
ip_display.display(transfer_widget)
Loading