Skip to content
This repository was archived by the owner on Jan 27, 2022. It is now read-only.

Commit e6be4ea

Browse files
author
manju956
committed
Update Generic client to handle worker key refresh mechanism
When a worker key gets refreshed during the work order submission, a specific error code is returned to client to indicate worker key refresh happened at the enclave. On receiving this error code, client retrieves the updated worker details and does work order submission again. Signed-off-by: manju956 <[email protected]>
1 parent f6c27ba commit e6be4ea

File tree

5 files changed

+108
-70
lines changed

5 files changed

+108
-70
lines changed

common/crypto_utils/avalon_crypto_utils/crypto_utility.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import base64
16+
import hashlib
1617
import utility.hex_utils as hex_utils
1718
import avalon_crypto_utils.crypto.crypto as crypto
1819
import logging
@@ -197,3 +198,17 @@ def strip_begin_end_public_key(key):
197198
return key.replace("\n", "")\
198199
.replace("-----BEGIN PUBLIC KEY-----", "").replace(
199200
"-----END PUBLIC KEY-----", "")
201+
202+
203+
# -----------------------------------------------------------------------------
204+
def calculate_worker_id_from_public_key(key):
205+
"""
206+
Calculates worker id from workers public key by erasing
207+
BEGIN PUBLIC KEY and END PUBLIC KEY and taking hash on it.
208+
209+
@param key - public key of the worker
210+
"""
211+
stripped_key = strip_begin_end_public_key(key).encode("utf-8")
212+
# Calculate sha256 of worker id to get 32 bytes. The TC spec proxy
213+
# model contracts expect byte32. Then take a hexdigest for hex str.
214+
return hashlib.sha256(stripped_key).hexdigest()

common/python/error_code/enclave_error.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ class EnclaveError(IntEnum):
2828
ENCLAVE_ERR_VALUE = -8,
2929
ENCLAVE_ERR_SYSTEM = -9,
3030
ENCLAVE_ERR_CRYPTO = -11,
31+
ENCLAVE_ERR_ENCRYPT_KEY_REFRESH = -13,
3132
ENCLAVE_ERR_SYSTEM_BUSY = -10
3233
ENCLAVE_ERR_INVALID_WORKLOAD = -12

common/python/error_code/error_status.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class WorkOrderStatus(IntEnum):
3333
PROCESSING = 7
3434
BUSY = 8
3535
INVALID_WORKLOAD = 9
36-
UNKNOWN_ERROR = 10
36+
WORKER_ENCRYPT_KEY_REFRESHED = 10
37+
UNKNOWN_ERROR = 11
3738

3839

3940
@unique

examples/apps/generic_client/generic_client.py

Lines changed: 88 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import os
1818
import sys
19+
import time
1920
import json
2021
import argparse
2122
import logging
@@ -36,6 +37,7 @@
3637
from avalon_sdk.direct.jrpc.jrpc_work_order_receipt \
3738
import JRPCWorkOrderReceiptImpl
3839
from error_code.error_status import WorkOrderStatus, ReceiptCreateStatus
40+
from error_code.enclave_error import EnclaveError
3941
import avalon_crypto_utils.signature as signature
4042
from error_code.error_status import SignatureStatus
4143
from avalon_sdk.work_order_receipt.work_order_receipt \
@@ -291,38 +293,23 @@ def _verify_wo_res_signature(work_order_res,
291293
return True
292294

293295

294-
def Main(args=None):
295-
options = _parse_command_line(args)
296-
297-
config = _parse_config_file(options.config)
298-
if config is None:
299-
logger.error("\n Error in parsing config file: {}\n".format(
300-
options.config
301-
))
302-
sys.exit(-1)
303-
304-
# mode should be one of listing or registry (default)
305-
mode = options.mode
306-
307-
# Http JSON RPC listener uri
308-
uri = options.uri
309-
if uri:
310-
config["tcf"]["json_rpc_uri"] = uri
296+
def _start_client(config, options, jrpc_req_id, worker_id, worker_registry):
297+
"""
298+
Generates, submits work order requests. Retrieve response for the
299+
work order requests, verifies the response and generate receipt
311300
312-
# Address of smart contract
313-
address = options.address
314-
if address:
315-
if mode == "listing":
316-
config["ethereum"]["direct_registry_contract_address"] = \
317-
address
318-
elif mode == "registry":
319-
logger.error(
320-
"\n Only Worker registry listing address is supported." +
321-
"Worker registry address is unsupported \n")
322-
sys.exit(-1)
301+
@param config - instance of parsed config file
302+
@param options - command line options that are passed to the client
303+
@param jrpc_req_id - JSON RPC request id
304+
@param worker_id - worker id obtained from worker registry
305+
@param worker_registry - worker registry
306+
"""
323307

324-
# worker id
325-
worker_id = options.worker_id
308+
# Get first worker from worker registry
309+
worker_id = _lookup_first_worker(worker_registry, jrpc_req_id)
310+
if worker_id is None:
311+
logger.error("\n Unable to get worker \n")
312+
sys.exit(-1)
326313

327314
# work load id of worker
328315
workload_id = options.workload_id
@@ -342,42 +329,6 @@ def Main(args=None):
342329
# requester signature for work order requests
343330
requester_signature = options.requester_signature
344331

345-
# setup logging
346-
config["Logging"] = {
347-
"LogFile": "__screen__",
348-
"LogLevel": "INFO"
349-
}
350-
351-
plogger.setup_loggers(config.get("Logging", {}))
352-
sys.stdout = plogger.stream_to_logger(
353-
logging.getLogger("STDOUT"), logging.DEBUG)
354-
sys.stderr = plogger.stream_to_logger(
355-
logging.getLogger("STDERR"), logging.WARN)
356-
357-
logger.info("******* Hyperledger Avalon Generic client *******")
358-
359-
if mode == "registry" and address:
360-
logger.error("\n Worker registry contract address is unsupported \n")
361-
sys.exit(-1)
362-
363-
# Retrieve JSON RPC uri from registry list
364-
if not uri and mode == "listing":
365-
uri = _retrieve_uri_from_registry_list(config)
366-
if uri is None:
367-
logger.error("\n Unable to get http JSON RPC uri \n")
368-
sys.exit(-1)
369-
370-
# Prepare worker
371-
# JRPC request id. Choose any integer value
372-
jrpc_req_id = 31
373-
worker_registry = JRPCWorkerRegistryImpl(config)
374-
if not worker_id:
375-
# Get first worker from worker registry
376-
worker_id = _lookup_first_worker(worker_registry, jrpc_req_id)
377-
if worker_id is None:
378-
logger.error("\n Unable to get worker \n")
379-
sys.exit(-1)
380-
381332
# Retrieve worker details
382333
jrpc_req_id += 1
383334
worker_retrieve_result = worker_registry.worker_retrieve(
@@ -465,10 +416,14 @@ def Main(args=None):
465416
res['result'], session_key, session_iv)
466417
logger.info("\nDecrypted response:\n {}"
467418
.format(decrypted_res))
419+
# Handle worker key refresh scenario
420+
elif "error" in res and \
421+
res["error"]["code"] == \
422+
WorkOrderStatus.WORKER_ENCRYPT_KEY_REFRESHED:
423+
logger.error("Worker Key refreshed. Retrieving latest Worker details")
424+
_start_client(config, options, jrpc_req_id, worker_id, worker_registry)
468425
else:
469-
logger.error("\n Work order get result failed {}\n".format(
470-
res
471-
))
426+
logger.error("\n Work order get result failed {}\n".format(res))
472427
sys.exit(1)
473428

474429
if show_receipt:
@@ -483,5 +438,69 @@ def Main(args=None):
483438
sys.exit(1)
484439

485440

441+
def Main(args=None):
442+
options = _parse_command_line(args)
443+
444+
config = _parse_config_file(options.config)
445+
if config is None:
446+
logger.error("\n Error in parsing config file: {}\n".format(
447+
options.config
448+
))
449+
sys.exit(-1)
450+
451+
# mode should be one of listing or registry (default)
452+
mode = options.mode
453+
454+
# Http JSON RPC listener uri
455+
uri = options.uri
456+
if uri:
457+
config["tcf"]["json_rpc_uri"] = uri
458+
459+
# Address of smart contract
460+
address = options.address
461+
if address:
462+
if mode == "listing":
463+
config["ethereum"]["direct_registry_contract_address"] = \
464+
address
465+
elif mode == "registry":
466+
logger.error(
467+
"\n Only Worker registry listing address is supported." +
468+
"Worker registry address is unsupported \n")
469+
sys.exit(-1)
470+
471+
# worker id
472+
worker_id = options.worker_id
473+
474+
# setup logging
475+
config["Logging"] = {
476+
"LogFile": "__screen__",
477+
"LogLevel": "INFO"
478+
}
479+
480+
plogger.setup_loggers(config.get("Logging", {}))
481+
sys.stdout = plogger.stream_to_logger(
482+
logging.getLogger("STDOUT"), logging.DEBUG)
483+
sys.stderr = plogger.stream_to_logger(
484+
logging.getLogger("STDERR"), logging.WARN)
485+
486+
logger.info("******* Hyperledger Avalon Generic client *******")
487+
488+
if mode == "registry" and address:
489+
logger.error("\n Worker registry contract address is unsupported \n")
490+
sys.exit(-1)
491+
492+
# Retrieve JSON RPC uri from registry list
493+
if not uri and mode == "listing":
494+
uri = _retrieve_uri_from_registry_list(config)
495+
if uri is None:
496+
logger.error("\n Unable to get http JSON RPC uri \n")
497+
sys.exit(-1)
498+
499+
# JRPC request id. Choose any integer value
500+
jrpc_req_id = 31
501+
worker_registry = JRPCWorkerRegistryImpl(config)
502+
_start_client(config, options, jrpc_req_id, worker_id, worker_registry)
503+
504+
486505
# -----------------------------------------------------------------------------
487506
Main()

listener/avalon_listener/tcs_work_order_handler.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ def WorkOrderGetResult(self, **params):
144144
err_code = WorkOrderStatus.UNKNOWN_ERROR
145145
elif err_code == EnclaveError.ENCLAVE_ERR_INVALID_WORKLOAD:
146146
err_code = WorkOrderStatus.INVALID_WORKLOAD
147+
elif err_code == EnclaveError.ENCLAVE_ERR_ENCRYPT_KEY_REFRESH:
148+
err_code = WorkOrderStatus.WORKER_ENCRYPT_KEY_REFRESHED
147149
else:
148150
err_code = WorkOrderStatus.FAILED
149151
raise JSONRPCDispatchException(

0 commit comments

Comments
 (0)