Workshop Prerequisites

Please complete the instructions found here in order to be prepared for the hands on portion of the workshop. If you have questions about these prerequisites, we'll do our best to provide assistance on RocketChat in the #indy channel.

Useful Links and Additional Reading

Hands-On Guide

We will be extending the nym transaction in indy plenum to include an image field. We are working from the 'ubuntu-20.04-upgrade' branch.

  1. To get started we will create a test that writes a nym with an image, then retrieves it from the ledger, and finally checks the returned image is correct.
    In indy_node/test/nym_txn/test_nym_additional.py around line 90 add this test.
    1. test_nym_img
      def test_nym_img(looper, sdk_pool_handle, sdk_wallet_steward, endorser_did_verkey):
          # prepare txn
          did, verkey = endorser_did_verkey
          nym_request, _ = looper.loop.run_until_complete(
              prepare_nym_request(sdk_wallet_steward, None,
                                  None, ENDORSER_STRING, did, verkey, False if verkey else True))
          # modify transaction to include image
          hyperledger_logo = 'https://raw.githubusercontent.com/hyperledger/indy-node/master/collateral/logos/indy-logo.png'
          txn = json.loads(nym_request)
          txn['operation']['img'] = hyperledger_logo # don't do this, avoid private data on ledgers
          request_couple = sdk_sign_and_send_prepared_request(looper, sdk_wallet_steward,
                                                              sdk_pool_handle, json.dumps(txn))
          sdk_get_and_check_replies(looper, [request_couple])
          # check image is in the nym
          rep = get_nym(looper, sdk_pool_handle, sdk_wallet_steward, did)
          assert rep[0][1]['result']['data']
          assert json.loads(rep[0][1]['result']['data'])['img'] == hyperledger_logo
    2. Inside indy_node/test/nym_txn directory, pytest -k test_nym_img should result in a failing test.
  2.  Now that we have a failing test we can start updating nym write transaction types. In indy_common/types.py there is a class called ClientOperationField around line 470. This class extends operations. Looks like Indy Node does not change the basic nym operations, we will borrow some code from Indy Plenum that defines a new operation. We will define in the next steps a new ClientNYMOperation. Since we are here let's add the instantiation inside _specific_operations.
    1. nym operation
      ...
      class ClientOperationField(PClientOperationField):
          _specific_operations = {
              NYM: ClientNYMOperation(), # <----- new operation
              SCHEMA: ClientSchemaOperation(),
              ATTRIB: ClientAttribOperation(),
      ...
    2. Around line 72 we will copy in the ClientNYMOperation class from Indy Plenum with our extra img field.

      nym operation
      class ClientNYMOperation(MessageValidator):
          schema = (
              (TXN_TYPE, ConstantField(NYM)),
              (ALIAS, LimitedLengthStringField(max_length=ALIAS_FIELD_LIMIT, optional=True)),
              (VERKEY, VerkeyField(optional=True, nullable=True)),
              (TARGET_NYM, DestNymField()),
              (ROLE, RoleField(optional=True)),
              (IMG, LimitedLengthStringField(max_length=RAW_FIELD_LIMIT, optional=True)) # <----- new image field
          )
    3. We also need to update some imports. Some of which we will define in the next steps.

      nym operation
      ...
      # include  ALIAS, VERKEY from plenum.common.constants
      from plenum.common.constants import TARGET_NYM, NONCE, RAW, ENC, HASH, NAME, \
          VERSION, FORCE, ORIGIN, OPERATION_SCHEMA_IS_STRICT, OP_VER, ALIAS, VERKEY
      ...
      # include VerkeyField, DestNymField from plenum.common.messages.fields
      from plenum.common.messages.fields import ConstantField, IdentifierField, \
      	...
          AnyMapField, NonEmptyStringField, DatetimeStringField, RoleField, AnyField, FieldBase, VerkeyField, DestNymField
      ...
      from plenum.config import JSON_FIELD_LIMIT, NAME_FIELD_LIMIT, DATA_FIELD_LIMIT, \
          NONCE_FIELD_LIMIT, \
          ENC_FIELD_LIMIT, RAW_FIELD_LIMIT, SIGNATURE_TYPE_FIELD_LIMIT, ALIAS_FIELD_LIMIT
      ...
      # include NYM, IMG from indy_common.constants
      from indy_common.constants import TXN_TYPE, ATTRIB, GET_ATTR, \
      	...
          RICH_SCHEMA_PRES_DEF, RS_PRES_DEF_TYPE_VALUE, NYM, IMG
  3. Now that we have a test, updated operator field we need to define the 'NYM' string constant. Inside indy_common/constants.py define a new NYM constant around line 14.
    1. nym constant
      # NYM
      IMG = "img"
  4. With the client operation for nym updated we will have transactions with our new "img" field.  We now can update the nym handler.
    1. inside indy_node/server/request_handlers/domain_req_handlers/nym_handler.py we will add a check for the img field, if present, store it. On line 78, add the check inside of update_state with supporting NYM import.

      nym handler
      ...
      from indy_common.constants import IMG, NYM <--- include NYM
      ...
           def update_state(self, txn, prev_result, request, is_committed=False):
      		...
              if IMG in txn_data: # check for IMG field
                  new_data[IMG] = txn_data[IMG] # store IMG
              ...
  5. Inside indy_node/test/nym_txn directory, pytest -k test_nym_img should result in a passing test.
  6. Celebrate!
  7. You can find this coding example here, with a diff highlighting changes


  • No labels