def _validate_claim_def(self, req: Request): # we can not add a Claim Def with existent ISSUER_DID # sine a Claim Def needs to be identified by seqNo identifier = req.identifier operation = req.operation schema_ref = operation[REF] signature_type = operation[SIGNATURE_TYPE] claim_def, _, _, _ = self.getClaimDef(author=identifier, schemaSeqNo=schema_ref, signatureType=signature_type) if claim_def: raise InvalidClientRequest( identifier, req.reqId, '{} can have one and only one CLAIM_DEF for ' 'and schema ref {} and signature type {}'.format( identifier, schema_ref, signature_type))
def static_validation(self, request: Request): self._validate_request_type(request) self._validate_enabled(request) try: content_as_dict = JsonSerializer.loads( request.operation[RS_CONTENT]) except ValueError: raise InvalidClientRequest( request.identifier, request.reqId, "'{}' must be a JSON serialized string".format(RS_CONTENT)) if self.is_json_ld_content(): self.do_static_validation_json_ld(content_as_dict, request) self.do_static_validation_content(content_as_dict, request)
def dynamic_validation(self, request: Request, req_pp_time: Optional[int]): self._validate_request_type(request) self.authorize(request) operation, identifier, req_id = request.operation, request.identifier, request.reqId aml_latest, _, _ = self.get_from_state(StaticTAAHelper.state_path_taa_aml_latest()) if aml_latest is None: raise InvalidClientRequest(identifier, req_id, "TAA txn is forbidden until TAA AML is set. Send TAA AML first.") version = operation[TXN_AUTHOR_AGREEMENT_VERSION] digest = StaticTAAHelper.get_taa_digest(self.state, version, isCommitted=False) if digest is None: if req_pp_time is None: raise LogicError("Cannot validate TAA transaction outside of normal ordering") self._validate_add_taa(request, req_pp_time) else: self._validate_update_taa(request, digest)
def _validate_schema(self, req: Request): # we can not add a Schema with already existent NAME and VERSION # sine a Schema needs to be identified by seqNo identifier = req.identifier operation = req.operation schema_name = operation[DATA][NAME] schema_version = operation[DATA][VERSION] schema, _, _, _ = self.getSchema(author=identifier, schemaName=schema_name, schemaVersion=schema_version) if schema: raise InvalidClientRequest( identifier, req.reqId, '{} can have one and only one SCHEMA with ' 'name {} and version {}'.format(identifier, schema_name, schema_version))
def authenticate(self, req_data, identifier: str = None, signature: str = None, verifier=None): txn_type = req_data[OPERATION][TXN_TYPE] if txn_type == SET_FEES: verifier = verifier or DidVerifier return super().authenticate(req_data, identifier, signature, verifier=verifier) else: raise InvalidClientRequest( req_data[f.REQ_ID.nm], identifier, "txn type is {} not {}".format(txn_type, SET_FEES))
def _validateAttrib(self, req: Request): origin = req.identifier op = req.operation if not (not op.get(TARGET_NYM) or self.hasNym(op[TARGET_NYM], isCommitted=False)): raise InvalidClientRequest( origin, req.reqId, '{} should be added before adding ' 'attribute for it'.format(TARGET_NYM)) if op.get(TARGET_NYM) and op[TARGET_NYM] != req.identifier and \ not self.idrCache.getOwnerFor(op[TARGET_NYM], isCommitted=False) == origin: raise UnauthorizedClientRequest( req.identifier, req.reqId, "Only identity owner/guardian can add attribute " "for that identity")
def validate(self, req: Request, config=None): status = None operation = req.operation typ = operation.get(TXN_TYPE) if typ not in [POOL_UPGRADE, POOL_CONFIG]: return origin = req.identifier try: originRole = self.idrCache.getRole(origin, isCommitted=False) except BaseException: raise UnauthorizedClientRequest( req.identifier, req.reqId, "Nym {} not added to the ledger yet".format(origin)) if typ == POOL_UPGRADE: trname = SovrinTransactions.POOL_UPGRADE.name action = operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present txn = self.upgrader.get_upgrade_txn( lambda txn: txn.get( NAME, None) == req.operation.get( NAME, None) and txn.get(VERSION) == req.operation.get(VERSION), reverse=True) if txn: status = txn.get(ACTION, None) if status == START and action == START: raise InvalidClientRequest( req.identifier, req.reqId, "Upgrade '{}' is already scheduled".format( req.operation.get(NAME))) elif typ == POOL_CONFIG: trname = SovrinTransactions.POOL_CONFIG.name action = None status = None r, msg = Authoriser.authorised( typ, ACTION, originRole, oldVal=status, newVal=action) if not r: raise UnauthorizedClientRequest( req.identifier, req.reqId, "{} cannot do {}".format( Roles.nameFromValue(originRole), trname))
def dynamic_validation(self, request: Request): self._validate_request_type(request) identifier, req_id, operation = get_request_data(request) if not (not operation.get(TARGET_NYM) or self.__has_nym(operation[TARGET_NYM], is_committed=False)): raise InvalidClientRequest( identifier, req_id, '{} should be added before adding ' 'attribute for it'.format(TARGET_NYM)) if operation.get(TARGET_NYM) and operation[TARGET_NYM] != identifier and \ not self.database_manager.idr_cache.getOwnerFor(operation[TARGET_NYM], isCommitted=False) == identifier: raise UnauthorizedClientRequest( identifier, req_id, "Only identity owner/guardian can add attribute " "for that identity")
def additional_dynamic_validation(self, request: Request, req_pp_time: Optional[int]): self._validate_request_type(request) identifier, req_id, operation = get_request_data(request) if not (not operation.get(TARGET_NYM) or self.__has_nym(operation[TARGET_NYM], is_committed=False)): raise InvalidClientRequest( identifier, request.reqId, '{} should be added before adding ' 'attribute for it'.format(TARGET_NYM)) is_owner = self.database_manager.idr_cache.getOwnerFor( operation[TARGET_NYM], isCommitted=False) == identifier field = None value = None for key in (RAW, ENC, HASH): if key in operation: field = key value = operation[key] break if field == RAW: get_key = attrib_raw_data_serializer.deserialize(value) get_key = list(get_key.keys())[0] else: get_key = value old_value, seq_no, _ = self._get_attr(operation[TARGET_NYM], get_key, field) if seq_no is not None: self.write_req_validator.validate(request, [ AuthActionEdit(txn_type=ATTRIB, field=field, old_value=old_value, new_value=value, is_owner=is_owner) ]) else: self.write_req_validator.validate(request, [ AuthActionAdd(txn_type=ATTRIB, field=field, value=value, is_owner=is_owner) ])
def _validate_schema(self, req: Request): # we can not add a Schema with already existent NAME and VERSION # sine a Schema needs to be identified by seqNo identifier = req.identifier schema_name = get_write_schema_name(req) schema_version = get_write_schema_version(req) schema, _, _, _ = self.getSchema(author=identifier, schemaName=schema_name, schemaVersion=schema_version, with_proof=False) if schema: raise InvalidClientRequest( identifier, req.reqId, '{} can have one and only one SCHEMA with ' 'name {} and version {}'.format(identifier, schema_name, schema_version)) self.write_req_validator.validate( req, [AuthActionAdd(txn_type=SCHEMA, field='*', value='*')])
def processRequest(self, request: Request, frm: str): if request.operation[TXN_TYPE] == GET_NYM: self.send_ack_to_client(request.key, frm) result = self.reqHandler.handleGetNymReq(request, frm) self.transmitToClient(Reply(result), frm) self.total_read_request_number += 1 elif request.operation[TXN_TYPE] == GET_SCHEMA: self.send_ack_to_client(request.key, frm) # TODO: `handleGetSchemaReq` should be changed to # `get_reply_for_schema_req`, the rationale being that the method # is not completely handling the request but fetching a response. # Similar reasoning follows for other methods below result = self.reqHandler.handleGetSchemaReq(request, frm) self.transmitToClient(Reply(result), frm) self.total_read_request_number += 1 elif request.operation[TXN_TYPE] == GET_ATTR: self.send_ack_to_client(request.key, frm) result = self.reqHandler.handleGetAttrsReq(request, frm) self.transmitToClient(Reply(result), frm) self.total_read_request_number += 1 elif request.operation[TXN_TYPE] == GET_CLAIM_DEF: self.send_ack_to_client(request.key, frm) result = self.reqHandler.handleGetClaimDefReq(request, frm) self.transmitToClient(Reply(result), frm) self.total_read_request_number += 1 elif request.operation[TXN_TYPE] == GET_TXNS: super().processRequest(request, frm) else: # forced request should be processed before consensus if (request.operation[TXN_TYPE] in [ POOL_UPGRADE, POOL_CONFIG]) and request.isForced(): self.configReqHandler.validate(request) self.configReqHandler.applyForced(request) # here we should have write transactions that should be processed # only on writable pool if self.poolCfg.isWritable() or (request.operation[TXN_TYPE] in [ POOL_UPGRADE, POOL_CONFIG]): super().processRequest(request, frm) else: raise InvalidClientRequest( request.identifier, request.reqId, 'Pool is in readonly mode, try again in 60 seconds')
def processRequest(self, request: Request, frm: str): if self.is_query(request.operation[TXN_TYPE]): self.process_query(request, frm) self.total_read_request_number += 1 else: # forced request should be processed before consensus if (request.operation[TXN_TYPE] in [POOL_UPGRADE, POOL_CONFIG ]) and request.isForced(): self.configReqHandler.validate(request) self.configReqHandler.applyForced(request) # here we should have write transactions that should be processed # only on writable pool if self.poolCfg.isWritable() or (request.operation[TXN_TYPE] in [POOL_UPGRADE, POOL_CONFIG]): super().processRequest(request, frm) else: raise InvalidClientRequest( request.identifier, request.reqId, 'Pool is in readonly mode, try again in 60 seconds')
def dynamic_validation(self, request: Request): # we can not add a Schema with already existent NAME and VERSION # sine a Schema needs to be identified by seqNo self._validate_request_type(request) identifier, req_id, operation = get_request_data(request) schema_name = get_write_schema_name(request) schema_version = get_write_schema_version(request) schema, _, _, _ = self.get_schema_handler.get_schema( author=identifier, schema_name=schema_name, schema_version=schema_version, with_proof=False) if schema: raise InvalidClientRequest( identifier, req_id, '{} can have one and only one SCHEMA with ' 'name {} and version {}'.format(identifier, schema_name, schema_version)) self.write_request_validator.validate( request, [AuthActionAdd(txn_type=SCHEMA, field='*', value='*')])
def apply(self, req: Request, cons_time: int = None): logger.debug("Transaction {} with type {} started".format( req.reqId, req.txn_type)) try: if req.txn_type == POOL_RESTART: self.restarter.handleActionTxn(req) result = self._generate_action_result(req) elif req.txn_type == VALIDATOR_INFO: result = self._generate_action_result(req) result[DATA] = self.info_tool.info else: raise InvalidClientRequest( "{} is not type of action transaction".format( req.txn_type)) except Exception as ex: logger.warning("Operation is failed") raise ex logger.debug("Transaction {} with type {} finished".format( req.reqId, req.txn_type)) return result
def authenticate(self, req_data, identifier: str = None, signature: str = None, verifier=None): """ verifies the request operation is transaction type of fees if transaction type is not fees, an exception is raised. """ txn_type = req_data[OPERATION][TXN_TYPE] if txn_type == SET_FEES: verifier = verifier or DidVerifier return super().authenticate(req_data, identifier, signature, verifier=verifier) else: raise InvalidClientRequest( req_data[f.REQ_ID.nm], identifier, "txn type is {} not {}".format(txn_type, SET_FEES))
def can_pay_fees(self, request): required_fees = self.get_txn_fees(request) if self.has_fees(request) and not required_fees: raise InvalidClientMessageException(getattr(request, f.IDENTIFIER.nm, None), getattr(request, f.REQ_ID.nm, None), 'Fees are not allowed for this txn type') if request.operation[TXN_TYPE] == XFER_PUBLIC: # Fees in XFER_PUBLIC is part of operation[INPUTS] self._get_deducted_fees_xfer(request, required_fees) self.deducted_fees_xfer[request.key] = required_fees elif required_fees: # We don't want to allow transfers on txn fees. So only one OUTPUT address can be used. # We could consider lock this down even more by requiring OUTPUT address to be one of the # INPUT address outputs = request.fees[1] if len(outputs) > MAX_FEE_OUTPUTS: raise InvalidClientRequest(request.identifier, request.reqId, "Only {} OUTPUT is allow for Transaction fees".format(MAX_FEE_OUTPUTS)) self._get_deducted_fees_non_xfer(request, required_fees)
def _validate_existing_nym(self, request, operation, nym_data): origin = request.identifier owner = self.database_manager.idr_cache.getOwnerFor( operation[TARGET_NYM], isCommitted=False) is_owner = origin == owner updateKeys = [ROLE, VERKEY] updateKeysInOperationOrOwner = is_owner for key in updateKeys: if key in operation: updateKeysInOperationOrOwner = True newVal = operation[key] oldVal = nym_data.get(key) self.write_req_validator.validate(request, [ AuthActionEdit(txn_type=NYM, field=key, old_value=oldVal, new_value=newVal, is_owner=is_owner) ]) if not updateKeysInOperationOrOwner: raise InvalidClientRequest(request.identifier, request.reqId)
def additional_dynamic_validation(self, request: Request, req_pp_time: Optional[int]): self._validate_request_type(request) rs_id = request.operation[RS_ID] rs_object, _, _ = self.get_from_state(rs_id) # check that (rs_name, rs_type, rs_version) is unique within all rich schema objects secondary_key = self.make_secondary_key(request.operation[RS_TYPE], request.operation[RS_NAME], request.operation[RS_VERSION]) if not rs_object and self.state.get(secondary_key, isCommitted=False) is not None: raise InvalidClientRequest( request.identifier, request.reqId, 'An object with {rs_name}="{rs_name_value}", {rs_version}="{rs_version_value}" ' 'and {rs_type}="{rs_type_value}" already exists. ' 'Please choose different {rs_name}, {rs_version} or {rs_type}'. format(rs_name=RS_NAME, rs_version=RS_VERSION, rs_type=RS_TYPE, rs_name_value=request.operation[RS_NAME], rs_version_value=request.operation[RS_VERSION], rs_type_value=request.operation[RS_TYPE])) # do common auth-rule-based validation (which will check the default immutability of most of the objects) if rs_object: self.write_req_validator.validate(request, [ AuthActionEdit(txn_type=self.txn_type, field='*', old_value='*', new_value='*') ]) else: self.write_req_validator.validate( request, [AuthActionAdd(txn_type=self.txn_type, field='*', value='*')]) self.do_dynamic_validation_content(request)
def apply(self, req: Request, cons_time: int = None): logger.debug("Transaction {} with type {} started".format( req.reqId, req.txn_type)) try: if req.txn_type == POOL_RESTART: self.restarter.handleRestartRequest(req) result = self._generate_action_result(req) elif req.txn_type == VALIDATOR_INFO: result = self._generate_action_result(req) result[DATA] = self.info_tool.info result[DATA].update(self.info_tool.memory_profiler) result[DATA].update(self.info_tool._generate_software_info()) result[DATA].update(self.info_tool.extractions) result[DATA].update(self.info_tool.node_disk_size) else: raise InvalidClientRequest( req.reqId, "{} is not type of action transaction".format( req.txn_type)) except Exception as ex: logger.warning("Operation is failed") raise ex logger.debug("Transaction {} with type {} finished".format( req.reqId, req.txn_type)) return result
def static_validation(self, request: Request): raise InvalidClientRequest(request.identifier, request.reqId, "External NODE_UPGRADE requests are not allowed")
def static_validation(self, request: Request): try: self.set_fees_validator_cls(**request.operation) except TypeError as exc: raise InvalidClientRequest(request.identifier, request.reqId, str(exc))
def _doStaticValidationSchema(self, identifier, reqId, operation): if not operation.get(DATA).get(ATTR_NAMES): raise InvalidClientRequest( identifier, reqId, "attr_names in schema can not be empty")
def static_validation(self, request: Request): error = txn_xfer_public_validate(request) if error: raise InvalidClientRequest(request.identifier, request.reqId, error)
def validate(self, req: Request): status = '*' operation = req.operation typ = operation.get(TXN_TYPE) if typ not in [POOL_UPGRADE, POOL_CONFIG]: return if typ == POOL_UPGRADE: pkt_to_upgrade = req.operation.get(PACKAGE, getConfig().UPGRADE_ENTRY) if pkt_to_upgrade: currentVersion, cur_deps = self.curr_pkt_info(pkt_to_upgrade) if not currentVersion: raise InvalidClientRequest( req.identifier, req.reqId, "Packet {} is not installed and cannot be upgraded". format(pkt_to_upgrade)) if all([APP_NAME not in d for d in cur_deps]): raise InvalidClientRequest( req.identifier, req.reqId, "Packet {} doesn't belong to pool".format( pkt_to_upgrade)) else: raise InvalidClientRequest(req.identifier, req.reqId, "Upgrade packet name is empty") targetVersion = req.operation[VERSION] reinstall = req.operation.get(REINSTALL, False) if not Upgrader.is_version_upgradable(currentVersion, targetVersion, reinstall): # currentVersion > targetVersion raise InvalidClientRequest(req.identifier, req.reqId, "Version is not upgradable") action = operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present txn = self.upgrader.get_upgrade_txn( lambda txn: get_payload_data(txn).get(NAME, None) == req. operation.get(NAME, None) and get_payload_data(txn).get( VERSION) == req.operation.get(VERSION), reverse=True) if txn: status = get_payload_data(txn).get(ACTION, '*') if status == START and action == START: raise InvalidClientRequest( req.identifier, req.reqId, "Upgrade '{}' is already scheduled".format( req.operation.get(NAME))) if status == '*': auth_action = AuthActionAdd(txn_type=POOL_UPGRADE, field=ACTION, value=action) else: auth_action = AuthActionEdit(txn_type=POOL_UPGRADE, field=ACTION, old_value=status, new_value=action) self.write_req_validator.validate(req, [auth_action]) elif typ == POOL_CONFIG: action = '*' status = '*' self.write_req_validator.validate(req, [ AuthActionEdit(txn_type=typ, field=ACTION, old_value=status, new_value=action) ])
def static_validation(self, request: Request): operation, identifier, req_id = request.operation, request.identifier, request.reqId if len(operation[AML]) == 0: raise InvalidClientRequest( identifier, req_id, "TXN_AUTHOR_AGREEMENT_AML request " "must contain at least one acceptance mechanism")
def checkValidSovrinOperation(self, identifier, reqId, operation): unknownKeys = set(operation.keys()).difference(set(allOpKeys)) if unknownKeys: raise InvalidClientRequest(identifier, reqId, 'invalid keys "{}"'. format(",".join(unknownKeys))) missingKeys = set(reqOpKeys).difference(set(operation.keys())) if missingKeys: raise InvalidClientRequest(identifier, reqId, 'missing required keys "{}"'. format(",".join(missingKeys))) if operation[TXN_TYPE] not in validTxnTypes: raise InvalidClientRequest(identifier, reqId, 'invalid {}: {}'. format(TXN_TYPE, operation[TXN_TYPE])) if operation[TXN_TYPE] == ATTRIB: dataKeys = {RAW, ENC, HASH}.intersection(set(operation.keys())) if len(dataKeys) != 1: raise InvalidClientRequest(identifier, reqId, '{} should have one and only one of ' '{}, {}, {}' .format(ATTRIB, RAW, ENC, HASH)) if RAW in dataKeys: try: json.loads(operation[RAW]) except: raise InvalidClientRequest(identifier, reqId, 'raw attribute {} should be ' 'JSON'.format(operation[RAW])) if not (not operation.get(TARGET_NYM) or self.graphStore.hasNym(operation[TARGET_NYM])): raise InvalidClientRequest(identifier, reqId, '{} should be added before adding ' 'attribute for it'. format(TARGET_NYM)) if operation[TXN_TYPE] == NYM: role = operation.get(ROLE) nym = operation.get(TARGET_NYM) if not nym: raise InvalidClientRequest(identifier, reqId, "{} needs to be present". format(TARGET_NYM)) if not Authoriser.isValidRole(role): raise InvalidClientRequest(identifier, reqId, "{} not a valid role". format(role)) # Only if not self.canNymRequestBeProcessed(identifier, operation): raise InvalidClientRequest(identifier, reqId, "{} is already present". format(nym)) if operation[TXN_TYPE] == POOL_UPGRADE: action = operation.get(ACTION) if action not in (START, CANCEL): raise InvalidClientRequest(identifier, reqId, "{} not a valid action". format(action)) if action == START: schedule = operation.get(SCHEDULE, {}) isValid, msg = self.upgrader.isScheduleValid(schedule, self.poolManager.nodeIds) if not isValid: raise InvalidClientRequest(identifier, reqId, "{} not a valid schedule since {}". format(schedule, msg))
def validate(self, req: Request): super().validate(req) status = '*' operation = req.operation typ = operation.get(TXN_TYPE) if typ not in self.write_types: return if typ == POOL_UPGRADE: pkg_to_upgrade = req.operation.get(PACKAGE, getConfig().UPGRADE_ENTRY) targetVersion = req.operation[VERSION] reinstall = req.operation.get(REINSTALL, False) # check package name if not pkg_to_upgrade: raise InvalidClientRequest(req.identifier, req.reqId, "Upgrade package name is empty") try: res = self.upgrader.check_upgrade_possible( pkg_to_upgrade, targetVersion, reinstall) except Exception as exc: res = str(exc) if res: raise InvalidClientRequest(req.identifier, req.reqId, res) action = operation.get(ACTION) # TODO: Some validation needed for making sure name and version # present txn = self.upgrader.get_upgrade_txn( lambda txn: get_payload_data(txn).get(NAME, None) == req. operation.get(NAME, None) and get_payload_data(txn).get( VERSION) == req.operation.get(VERSION), reverse=True) if txn: status = get_payload_data(txn).get(ACTION, '*') if status == START and action == START: raise InvalidClientRequest( req.identifier, req.reqId, "Upgrade '{}' is already scheduled".format( req.operation.get(NAME))) if status == '*': auth_action = AuthActionAdd(txn_type=POOL_UPGRADE, field=ACTION, value=action) else: auth_action = AuthActionEdit(txn_type=POOL_UPGRADE, field=ACTION, old_value=status, new_value=action) self.write_req_validator.validate(req, [auth_action]) elif typ == POOL_CONFIG: action = '*' status = '*' self.write_req_validator.validate(req, [ AuthActionEdit(txn_type=typ, field=ACTION, old_value=status, new_value=action) ]) elif typ == AUTH_RULE: self.write_req_validator.validate(req, [ AuthActionEdit( txn_type=typ, field="*", old_value="*", new_value="*") ]) elif typ == AUTH_RULES: self.write_req_validator.validate(req, [ AuthActionEdit( txn_type=typ, field="*", old_value="*", new_value="*") ]) elif typ == TXN_AUTHOR_AGREEMENT: self.write_req_validator.validate( req, [AuthActionAdd(txn_type=typ, field="*", value="*")]) elif typ == TXN_AUTHOR_AGREEMENT_AML: self.write_req_validator.validate( req, [AuthActionAdd(txn_type=typ, field='*', value='*')])
def do_static_validation_content(self, content_as_dict, request: Request): if JSON_LD_CONTEXT_FIELD not in content_as_dict: raise InvalidClientRequest(request.identifier, request.reqId, "'{}' must contain a {} field".format(RS_CONTENT, JSON_LD_CONTEXT_FIELD)) self._validate_context(content_as_dict[JSON_LD_CONTEXT_FIELD], request.identifier, request.reqId)
def _doStaticValidationAttrib(self, identifier, reqId, operation): if not self._validate_attrib_keys(operation): raise InvalidClientRequest( identifier, reqId, '{} should have one and only one of ' '{}, {}, {}'.format(ATTRIB, RAW, ENC, HASH))
def _validateAttrib(self, req: Request): origin = req.identifier op = req.operation if not (not op.get(TARGET_NYM) or self.hasNym(op[TARGET_NYM], isCommitted=False)): raise InvalidClientRequest( origin, req.reqId, '{} should be added before adding ' 'attribute for it'.format(TARGET_NYM)) is_owner = self.idrCache.getOwnerFor(op[TARGET_NYM], isCommitted=False) == origin field = None value = None for key in (RAW, ENC, HASH): if key in op: field = key value = op[key] break if field is None or value is None: raise LogicError('Attribute data cannot be empty') get_key = None if field == RAW: try: get_key = attrib_raw_data_serializer.deserialize(value) if len(get_key) == 0: raise InvalidClientRequest( origin, req.reqId, '"row" attribute field must contain non-empty dict'. format(TARGET_NYM)) get_key = next(iter(get_key.keys())) except JSONDecodeError: raise InvalidClientRequest( origin, req.reqId, 'Attribute field must be dict while adding it as a row field' .format(TARGET_NYM)) else: get_key = value if get_key is None: raise LogicError('Attribute data must be parsed') old_value, seq_no, _, _ = self.getAttr(op[TARGET_NYM], get_key, field, isCommitted=False) if seq_no is not None: self.write_req_validator.validate(req, [ AuthActionEdit(txn_type=ATTRIB, field=field, old_value=old_value, new_value=value, is_owner=is_owner) ]) else: self.write_req_validator.validate(req, [ AuthActionAdd(txn_type=ATTRIB, field=field, value=value, is_owner=is_owner) ])