From 0cba96b72677d3fe8e11416e3e4fb46fc157a070 Mon Sep 17 00:00:00 2001 From: toktar Date: Tue, 16 Feb 2021 01:57:34 +0300 Subject: [PATCH 1/7] UP-41: add set and get fees handlers Signed-off-by: toktar Signed-off-by: Ry Jones --- indy_common/constants.py | 4 ++ indy_common/transactions.py | 4 ++ indy_node/server/node_bootstrap.py | 8 +++ .../config_req_handlers/fees/__init__.py | 0 .../fees/fees_static_helper.py | 66 +++++++++++++++++++ .../fees/set_fees_handler.py | 44 +++++++++++++ .../fees/set_fees_handler_0_9_3.py | 16 +++++ .../read_req_handlers/get_fee_handler.py | 34 ++++++++++ .../read_req_handlers/get_fees_handler.py | 32 +++++++++ 9 files changed, 208 insertions(+) create mode 100644 indy_node/server/request_handlers/config_req_handlers/fees/__init__.py create mode 100644 indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py create mode 100644 indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py create mode 100644 indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py create mode 100644 indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py create mode 100644 indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py diff --git a/indy_common/constants.py b/indy_common/constants.py index 5ee16e38a..7db93ba19 100644 --- a/indy_common/constants.py +++ b/indy_common/constants.py @@ -172,6 +172,10 @@ AUTH_RULES = IndyTransactions.AUTH_RULES.value GET_AUTH_RULE = IndyTransactions.GET_AUTH_RULE.value +SET_FEES = IndyTransactions.SET_FEES.value +GET_FEES = IndyTransactions.GET_FEES.value +GET_FEE = IndyTransactions.GET_FEE.value + # client Rich Schema transaction types JSON_LD_CONTEXT = IndyTransactions.JSON_LD_CONTEXT.value RICH_SCHEMA = IndyTransactions.RICH_SCHEMA.value diff --git a/indy_common/transactions.py b/indy_common/transactions.py index b1d966d76..b166b5a8d 100644 --- a/indy_common/transactions.py +++ b/indy_common/transactions.py @@ -48,6 +48,10 @@ class IndyTransactions(Transactions): GET_RICH_SCHEMA_OBJECT_BY_ID = "300" GET_RICH_SCHEMA_OBJECT_BY_METADATA = "301" + SET_FEES = "20000" + GET_FEES = "20001" + GET_FEE = "20003" + @staticmethod def get_name_from_code(code: str): try: diff --git a/indy_node/server/node_bootstrap.py b/indy_node/server/node_bootstrap.py index 89d7bca75..44c8ed424 100644 --- a/indy_node/server/node_bootstrap.py +++ b/indy_node/server/node_bootstrap.py @@ -13,6 +13,7 @@ from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rule_handler_1_9_1 import AuthRuleHandler191 from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rules_handler import AuthRulesHandler from indy_node.server.request_handlers.config_req_handlers.ledgers_freeze_handler import LedgersFreezeHandler +from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler from indy_node.server.request_handlers.config_req_handlers.node_upgrade_handler import NodeUpgradeHandler from indy_node.server.request_handlers.config_req_handlers.pool_config_handler import PoolConfigHandler from indy_node.server.request_handlers.config_req_handlers.pool_upgrade_handler import PoolUpgradeHandler @@ -142,6 +143,9 @@ def _register_domain_req_handlers(self): get_rich_schema_obj_by_metadata_handler = GetRichSchemaObjectByMetadataHandler( database_manager=self.node.db_manager) + set_fees_handler = SetFeesHandler(database_manager=self.node.db_manager, + write_req_validator=self.node.write_req_validator) + # Register write handlers self.node.write_manager.register_req_handler(nym_handler) self.node.write_manager.register_req_handler(attrib_handler) @@ -155,6 +159,10 @@ def _register_domain_req_handlers(self): self.node.write_manager.register_req_handler(rich_schema_mapping_handler) self.node.write_manager.register_req_handler(rich_schema_cred_def_handler) self.node.write_manager.register_req_handler(rich_schema_pres_def_handler) + self.node.write_manager.register_req_handler(set_fees_handler) + self.node.write_manager.register_req_handler_with_version(SetFeesHandler093(node.db_manager, + node.write_req_validator), + "0.9.3") # Additional handler for idCache self.register_idr_cache_nym_handler() # Register read handlers diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/__init__.py b/indy_node/server/request_handlers/config_req_handlers/fees/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py b/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py new file mode 100644 index 000000000..2a8849e68 --- /dev/null +++ b/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py @@ -0,0 +1,66 @@ +from common.serializers.serialization import proof_nodes_serializer, state_roots_serializer, config_state_serializer +from plenum.common.constants import MULTI_SIGNATURE, ROOT_HASH, PROOF_NODES + + +class BatchFeesTracker: + def __init__(self): + self.fees_in_current_batch = 0 + self._deducted_fees = {} + + def add_deducted_fees(self, txn_type, seq_no, fees): + key = "{}#{}".format(txn_type, seq_no) + self._deducted_fees[key] = fees + + def has_deducted_fees(self, txn_type, seq_no): + return "{}#{}".format(txn_type, seq_no) in self._deducted_fees + + +class FeesStaticHelper: + + @staticmethod + def get_fee_from_state(state, fees_alias=None, is_committed=False, with_proof=False, bls_store=None): + fees = None + proof = None + try: + fees_key = FeesStaticHelper.build_path_for_set_fees(alias=fees_alias) + if with_proof: + root_hash = state.committedHeadHash if is_committed else state.headHash + proof, serz = state.generate_state_proof(fees_key, + root=state.get_head_by_hash(root_hash), + serialize=True, + get_value=True) + if serz: + serz = state.get_decoded(serz) + encoded_root_hash = state_roots_serializer.serialize(bytes(root_hash)) + multi_sig = bls_store.get(encoded_root_hash) + if multi_sig: + encoded_proof = proof_nodes_serializer.serialize(proof) + proof = { + MULTI_SIGNATURE: multi_sig.as_dict(), + ROOT_HASH: encoded_root_hash, + PROOF_NODES: encoded_proof + } + else: + proof = {} + else: + serz = state.get(fees_key, + isCommitted=is_committed) + if serz: + fees = config_state_serializer.deserialize(serz) + except KeyError: + pass + if with_proof: + return fees, proof + return fees + + FEES_STATE_PREFIX = '200' + FEES_KEY_DELIMITER = ':' + FEES_KEY_FOR_ALL = 'fees' + + @staticmethod + def build_path_for_set_fees(alias=None): + if alias: + return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, alias]) + return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, FeesStaticHelper.FEES_KEY_FOR_ALL]) + + diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py new file mode 100644 index 000000000..362110e11 --- /dev/null +++ b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py @@ -0,0 +1,44 @@ +from typing import Optional + +from common.serializers.serialization import config_state_serializer +from indy_common.constants import SET_FEES +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper +from plenum.common.constants import CONFIG_LEDGER_ID +from plenum.common.exceptions import InvalidClientRequest +from plenum.common.request import Request +from plenum.common.txn_util import get_payload_data +from plenum.common.types import f +from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.handler_interfaces.write_request_handler import WriteRequestHandler + + +class SetFeesHandler(WriteRequestHandler): + + def __init__(self, db_manager: DatabaseManager, write_req_validator): + super().__init__(db_manager, SET_FEES, CONFIG_LEDGER_ID) + self._write_req_validator = write_req_validator + + def static_validation(self, request: Request): + raise InvalidClientRequest(request.identifier, + request.reqId, + "SET_FEES transactions are forbidden now.") + + def dynamic_validation(self, request: Request, req_pp_time: Optional[int]): + raise InvalidClientRequest(request.identifier, + request.reqId, + "SET_FEES transactions are forbidden now.") + + def update_state(self, txn, prev_result, request, is_committed=False): + payload = get_payload_data(txn) + fees_from_req = payload.get(f.FEES.nm) + current_fees = FeesStaticHelper.get_fee_from_state(self.state) + current_fees = current_fees if current_fees else {} + current_fees.update(fees_from_req) + for fees_alias, fees_value in fees_from_req.items(): + self._set_to_state(FeesStaticHelper.build_path_for_set_fees(alias=fees_alias), fees_value) + self._set_to_state(FeesStaticHelper.build_path_for_set_fees(), current_fees) + + def _set_to_state(self, key, val): + val = config_state_serializer.serialize(val) + key = key.encode() + self.state.set(key, val) diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py new file mode 100644 index 000000000..cbdfa878a --- /dev/null +++ b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py @@ -0,0 +1,16 @@ +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper +from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler +from plenum.common.txn_util import get_payload_data +from plenum.common.types import f + + +class SetFeesHandler093(SetFeesHandler): + fees_state_key = 'fees' + + def update_state(self, txn, prev_result, request, is_committed=False): + payload = get_payload_data(txn) + fees_from_req = payload.get(f.FEES.nm) + current_fees = FeesStaticHelper.get_fee_from_state(self.state) + current_fees = current_fees if current_fees else {} + current_fees.update(fees_from_req) + self._set_to_state(self.fees_state_key, current_fees) diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py new file mode 100644 index 000000000..2c52029e8 --- /dev/null +++ b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py @@ -0,0 +1,34 @@ +from indy_common.constants import GET_FEE +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper +from plenum.common.constants import ALIAS, STATE_PROOF, CONFIG_LEDGER_ID, BLS_LABEL +from plenum.common.exceptions import InvalidClientRequest +from plenum.common.request import Request +from plenum.common.types import f +from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.handler_interfaces.read_request_handler import ReadRequestHandler + + +class GetFeeHandler(ReadRequestHandler): + + def __init__(self, database_manager: DatabaseManager): + super().__init__(database_manager, GET_FEE, CONFIG_LEDGER_ID) + + def get_result(self, request: Request): + alias = request.operation.get(ALIAS) + fee, proof = FeesStaticHelper.get_fee_from_state(self.state, fees_alias=alias, is_committed=True, + with_proof=True, + bls_store=self.database_manager.get_store(BLS_LABEL)) + result = {f.IDENTIFIER.nm: request.identifier, + f.REQ_ID.nm: request.reqId, f.FEE.nm: fee} + if proof: + result[STATE_PROOF] = proof + result.update(request.operation) + return result + + def static_validation(self, request: Request): + try: + self.get_fee_validator_cls(**request.operation) + except TypeError as exc: + raise InvalidClientRequest(request.identifier, + request.reqId, + exc) diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py new file mode 100644 index 000000000..168e8fa31 --- /dev/null +++ b/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py @@ -0,0 +1,32 @@ +from indy_common.constants import GET_FEES +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper +from plenum.common.constants import STATE_PROOF, CONFIG_LEDGER_ID, BLS_LABEL +from plenum.common.request import Request +from plenum.common.types import f +from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.handler_interfaces.read_request_handler import ReadRequestHandler + + +class GetFeesHandler(ReadRequestHandler): + def __init__(self, db_manager: DatabaseManager): + super().__init__(db_manager, GET_FEES, CONFIG_LEDGER_ID) + + def get_result(self, request: Request): + fees, proof = self.get_fees(is_committed=True, with_proof=True) + + result = {f.IDENTIFIER.nm: request.identifier, + f.REQ_ID.nm: request.reqId, + f.FEES.nm: fees} + if proof: + result[STATE_PROOF] = proof + result.update(request.operation) + return result + + def get_fees(self, is_committed=False, with_proof=False): + result = FeesStaticHelper.get_fee_from_state(self.state, is_committed=is_committed, with_proof=with_proof, + bls_store=self.database_manager.get_store(BLS_LABEL)) + if with_proof: + fees, proof = result + return (fees, proof) if fees is not None else ({}, proof) + else: + return result if result is not None else {} From db006144a3de8498e2dbda6122d1e5765e748075 Mon Sep 17 00:00:00 2001 From: toktar Date: Tue, 16 Feb 2021 04:07:36 +0300 Subject: [PATCH 2/7] UP-41: add set and get fees client operations Signed-off-by: toktar --- indy_common/constants.py | 7 ++++ indy_common/types.py | 40 +++++++++++++++++-- indy_node/server/node_bootstrap.py | 21 ++++++---- .../fees/set_fees_handler.py | 4 +- .../fees/set_fees_handler_0_9_3.py | 3 +- .../read_req_handlers/get_fees_handler.py | 4 +- 6 files changed, 64 insertions(+), 15 deletions(-) diff --git a/indy_common/constants.py b/indy_common/constants.py index 7db93ba19..4b2211edd 100644 --- a/indy_common/constants.py +++ b/indy_common/constants.py @@ -239,3 +239,10 @@ RS_MAPPING_SCHEMA = "schema" RS_MAPPING_ENC = "enc" RS_MAPPING_RANK = "rank" + +# FEES +FEES = "fees" +FEES_ALIAS = "alias" +FEES_VALUE = "value" +FEE_ALIAS_LENGTH = 128 +FEES_FIELD_NAME = "fees" diff --git a/indy_common/types.py b/indy_common/types.py index b896fae67..f641675d6 100644 --- a/indy_common/types.py +++ b/indy_common/types.py @@ -11,7 +11,7 @@ Sha256HexField, JsonField, MapField, BooleanField, VersionField, \ ChooseField, IntegerField, IterableField, \ AnyMapField, NonEmptyStringField, DatetimeStringField, RoleField, AnyField, FieldBase -from plenum.common.messages.message_base import MessageValidator +from plenum.common.messages.message_base import MessageValidator, MessageBase from plenum.common.messages.node_messages import NonNegativeNumberField from plenum.common.request import Request as PRequest from plenum.common.types import OPERATION @@ -44,7 +44,7 @@ RS_NAME, RS_ID, RS_CONTENT, RS_CONTEXT_TYPE_VALUE, RICH_SCHEMA, RS_SCHEMA_TYPE_VALUE, RS_ENCODING_TYPE_VALUE, \ RICH_SCHEMA_ENCODING, RS_MAPPING_TYPE_VALUE, RICH_SCHEMA_MAPPING, RS_CRED_DEF_TYPE_VALUE, \ RICH_SCHEMA_CRED_DEF, GET_RICH_SCHEMA_OBJECT_BY_ID, GET_RICH_SCHEMA_OBJECT_BY_METADATA, \ - RICH_SCHEMA_PRES_DEF, RS_PRES_DEF_TYPE_VALUE + RICH_SCHEMA_PRES_DEF, RS_PRES_DEF_TYPE_VALUE, GET_FEE, GET_FEES, SET_FEES, FEES_ALIAS, FEE_ALIAS_LENGTH, FEES from indy_common.version import SchemaVersion @@ -467,6 +467,37 @@ class ClientGetRichSchemaObjectByMetadataOperation(MessageValidator): ) +class ClientGetFeeMsgOperation(MessageBase): + schema = ( + (TXN_TYPE, ConstantField(GET_FEE)), + (FEES_ALIAS, LimitedLengthStringField(max_length=FEE_ALIAS_LENGTH)), + ) + + +class ClientGetFeesMsgOperation(MessageBase): + schema = ( + (TXN_TYPE, ConstantField(GET_FEES)), + ) + + +class SetFeesField(MapField): + def __init__(self, **kwargs): + super().__init__(NonEmptyStringField(), NonNegativeNumberField(), + **kwargs) + + def _specific_validation(self, val): + error = super()._specific_validation(val) + if error: + return "set_fees -- " + error + + +class ClientSetFeesMsgOperation(MessageBase): + schema = ( + (TXN_TYPE, ConstantField(SET_FEES)), + (FEES, SetFeesField()), + ) + + class ClientOperationField(PClientOperationField): _specific_operations = { SCHEMA: ClientSchemaOperation(), @@ -496,7 +527,10 @@ class ClientOperationField(PClientOperationField): RICH_SCHEMA_CRED_DEF: ClientRichSchemaCredDefOperation(), RICH_SCHEMA_PRES_DEF: ClientRichSchemaPresDefOperation(), GET_RICH_SCHEMA_OBJECT_BY_ID: ClientGetRichSchemaObjectByIdOperation(), - GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation() + GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation(), + SET_FEES: ClientSetFeesMsgOperation(), + GET_FEE: ClientGetFeeMsgOperation(), + GET_FEES: ClientGetFeesMsgOperation(), } # TODO: it is a workaround because INDY-338, `operations` must be a class diff --git a/indy_node/server/node_bootstrap.py b/indy_node/server/node_bootstrap.py index 44c8ed424..77b34b69d 100644 --- a/indy_node/server/node_bootstrap.py +++ b/indy_node/server/node_bootstrap.py @@ -12,6 +12,7 @@ from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rule_handler import AuthRuleHandler from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rule_handler_1_9_1 import AuthRuleHandler191 from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rules_handler import AuthRulesHandler +from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler_0_9_3 import SetFeesHandler093 from indy_node.server.request_handlers.config_req_handlers.ledgers_freeze_handler import LedgersFreezeHandler from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler from indy_node.server.request_handlers.config_req_handlers.node_upgrade_handler import NodeUpgradeHandler @@ -47,6 +48,8 @@ from indy_node.server.request_handlers.read_req_handlers.get_attribute_handler import GetAttributeHandler from indy_node.server.request_handlers.read_req_handlers.get_auth_rule_handler import GetAuthRuleHandler from indy_node.server.request_handlers.read_req_handlers.get_claim_def_handler import GetClaimDefHandler +from indy_node.server.request_handlers.read_req_handlers.get_fee_handler import GetFeeHandler +from indy_node.server.request_handlers.read_req_handlers.get_fees_handler import GetFeesHandler from plenum.server.request_handlers.ledgers_freeze.get_frozen_ledgers_handler import GetFrozenLedgersHandler from indy_node.server.request_handlers.read_req_handlers.get_nym_handler import GetNymHandler from indy_node.server.request_handlers.read_req_handlers.get_revoc_reg_def_handler import GetRevocRegDefHandler @@ -143,9 +146,6 @@ def _register_domain_req_handlers(self): get_rich_schema_obj_by_metadata_handler = GetRichSchemaObjectByMetadataHandler( database_manager=self.node.db_manager) - set_fees_handler = SetFeesHandler(database_manager=self.node.db_manager, - write_req_validator=self.node.write_req_validator) - # Register write handlers self.node.write_manager.register_req_handler(nym_handler) self.node.write_manager.register_req_handler(attrib_handler) @@ -159,10 +159,6 @@ def _register_domain_req_handlers(self): self.node.write_manager.register_req_handler(rich_schema_mapping_handler) self.node.write_manager.register_req_handler(rich_schema_cred_def_handler) self.node.write_manager.register_req_handler(rich_schema_pres_def_handler) - self.node.write_manager.register_req_handler(set_fees_handler) - self.node.write_manager.register_req_handler_with_version(SetFeesHandler093(node.db_manager, - node.write_req_validator), - "0.9.3") # Additional handler for idCache self.register_idr_cache_nym_handler() # Register read handlers @@ -210,6 +206,13 @@ def _register_config_req_handlers(self): ledgers_freeze_handler = LedgersFreezeHandler(database_manager=self.node.db_manager, write_req_validator=self.node.write_req_validator) get_frozen_ledgers_handler = GetFrozenLedgersHandler(database_manager=self.node.db_manager) + + set_fees_handler = SetFeesHandler(db_manager=self.node.db_manager, + write_req_validator=self.node.write_req_validator) + set_fees_handler_093 = SetFeesHandler093(db_manager=self.node.db_manager, + write_req_validator=self.node.write_req_validator) + get_fee_handler = GetFeeHandler(database_manager=self.node.db_manager) + get_fees_handler = GetFeesHandler(db_manager=self.node.db_manager) # Register write handlers self.node.write_manager.register_req_handler(auth_rule_handler) self.node.write_manager.register_req_handler(auth_rules_handler) @@ -220,6 +223,8 @@ def _register_config_req_handlers(self): self.node.write_manager.register_req_handler(taa_disable_handler) self.node.write_manager.register_req_handler(node_upgrade_handler) self.node.write_manager.register_req_handler(ledgers_freeze_handler) + self.node.write_manager.register_req_handler(set_fees_handler) + self.node.write_manager.register_req_handler_with_version(set_fees_handler_093, "0.9.3") # Register read handlers self.node.read_manager.register_req_handler(get_auth_rule_handler) self.node.read_manager.register_req_handler(get_taa_aml_handler) @@ -230,6 +235,8 @@ def _register_config_req_handlers(self): version="1.9.1") self.node.write_manager.register_req_handler_with_version(taa_handler_v1, version="1") + self.node.read_manager.register_req_handler(get_fee_handler) + self.node.read_manager.register_req_handler(get_fees_handler) def _register_action_req_handlers(self): # Action handlers diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py index 362110e11..5485f414c 100644 --- a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py +++ b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py @@ -1,7 +1,7 @@ from typing import Optional from common.serializers.serialization import config_state_serializer -from indy_common.constants import SET_FEES +from indy_common.constants import SET_FEES, FEES from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper from plenum.common.constants import CONFIG_LEDGER_ID from plenum.common.exceptions import InvalidClientRequest @@ -30,7 +30,7 @@ def dynamic_validation(self, request: Request, req_pp_time: Optional[int]): def update_state(self, txn, prev_result, request, is_committed=False): payload = get_payload_data(txn) - fees_from_req = payload.get(f.FEES.nm) + fees_from_req = payload.get(FEES) current_fees = FeesStaticHelper.get_fee_from_state(self.state) current_fees = current_fees if current_fees else {} current_fees.update(fees_from_req) diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py index cbdfa878a..1d39a7a4d 100644 --- a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py +++ b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler_0_9_3.py @@ -1,3 +1,4 @@ +from indy_common.constants import FEES from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler from plenum.common.txn_util import get_payload_data @@ -9,7 +10,7 @@ class SetFeesHandler093(SetFeesHandler): def update_state(self, txn, prev_result, request, is_committed=False): payload = get_payload_data(txn) - fees_from_req = payload.get(f.FEES.nm) + fees_from_req = payload.get(FEES) current_fees = FeesStaticHelper.get_fee_from_state(self.state) current_fees = current_fees if current_fees else {} current_fees.update(fees_from_req) diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py index 168e8fa31..7974549e5 100644 --- a/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py +++ b/indy_node/server/request_handlers/read_req_handlers/get_fees_handler.py @@ -1,4 +1,4 @@ -from indy_common.constants import GET_FEES +from indy_common.constants import GET_FEES, FEES from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper from plenum.common.constants import STATE_PROOF, CONFIG_LEDGER_ID, BLS_LABEL from plenum.common.request import Request @@ -16,7 +16,7 @@ def get_result(self, request: Request): result = {f.IDENTIFIER.nm: request.identifier, f.REQ_ID.nm: request.reqId, - f.FEES.nm: fees} + FEES: fees} if proof: result[STATE_PROOF] = proof result.update(request.operation) From fe8c75f2393f657cf89be8f069e236598f6075f7 Mon Sep 17 00:00:00 2001 From: toktar Date: Wed, 17 Feb 2021 16:46:43 +0300 Subject: [PATCH 3/7] UP-41: add tests for fees Signed-off-by: toktar --- indy_common/test/test_transactions.py | 6 +- indy_common/types.py | 8 +- .../fees/fees_static_helper.py | 2 - .../fees/set_fees_handler.py | 2 +- .../read_req_handlers/get_fee_handler.py | 10 +- ..._state_recovery_with_different_versions.py | 129 ++++++++++++++++++ indy_node/test/fees/__init__.py | 0 indy_node/test/fees/helper.py | 33 +++++ .../request_handlers/set_fees/conftest.py | 41 ++++++ .../set_fees/test_get_fee_req_handler.py | 18 +++ .../set_fees/test_get_fees_req_handler.py | 15 ++ .../set_fees/test_set_fees_req_handler.py | 30 ++++ 12 files changed, 277 insertions(+), 17 deletions(-) create mode 100644 indy_node/test/catchup/test_state_recovery_with_different_versions.py create mode 100644 indy_node/test/fees/__init__.py create mode 100644 indy_node/test/fees/helper.py create mode 100644 indy_node/test/request_handlers/set_fees/conftest.py create mode 100644 indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py create mode 100644 indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py create mode 100644 indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py diff --git a/indy_common/test/test_transactions.py b/indy_common/test/test_transactions.py index f74055ee4..365fa5468 100644 --- a/indy_common/test/test_transactions.py +++ b/indy_common/test/test_transactions.py @@ -4,7 +4,7 @@ GET_REVOC_REG_DEF, GET_REVOC_REG, GET_REVOC_REG_DELTA, POOL_RESTART, VALIDATOR_INFO, CHANGE_KEY, AUTH_RULE, \ GET_AUTH_RULE, AUTH_RULES, RICH_SCHEMA, RICH_SCHEMA_ENCODING, \ RICH_SCHEMA_MAPPING, RICH_SCHEMA_CRED_DEF, JSON_LD_CONTEXT, GET_RICH_SCHEMA_OBJECT_BY_METADATA, \ - GET_RICH_SCHEMA_OBJECT_BY_ID, RICH_SCHEMA_PRES_DEF + GET_RICH_SCHEMA_OBJECT_BY_ID, RICH_SCHEMA_PRES_DEF, SET_FEES, GET_FEES, GET_FEE from indy_common.transactions import IndyTransactions @@ -48,6 +48,10 @@ def test_transactions_are_encoded(): assert GET_RICH_SCHEMA_OBJECT_BY_ID == "300" assert GET_RICH_SCHEMA_OBJECT_BY_METADATA == "301" + assert SET_FEES == "20000" + assert GET_FEES == "20001" + assert GET_FEE == "20003" + def test_transaction_enum_decoded(): assert IndyTransactions.NODE.name == "NODE" diff --git a/indy_common/types.py b/indy_common/types.py index f641675d6..1b20b1549 100644 --- a/indy_common/types.py +++ b/indy_common/types.py @@ -467,14 +467,14 @@ class ClientGetRichSchemaObjectByMetadataOperation(MessageValidator): ) -class ClientGetFeeMsgOperation(MessageBase): +class ClientGetFeeMsgOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_FEE)), (FEES_ALIAS, LimitedLengthStringField(max_length=FEE_ALIAS_LENGTH)), ) -class ClientGetFeesMsgOperation(MessageBase): +class ClientGetFeesMsgOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_FEES)), ) @@ -491,7 +491,7 @@ def _specific_validation(self, val): return "set_fees -- " + error -class ClientSetFeesMsgOperation(MessageBase): +class ClientSetFeesMsgOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(SET_FEES)), (FEES, SetFeesField()), @@ -528,9 +528,9 @@ class ClientOperationField(PClientOperationField): RICH_SCHEMA_PRES_DEF: ClientRichSchemaPresDefOperation(), GET_RICH_SCHEMA_OBJECT_BY_ID: ClientGetRichSchemaObjectByIdOperation(), GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation(), - SET_FEES: ClientSetFeesMsgOperation(), GET_FEE: ClientGetFeeMsgOperation(), GET_FEES: ClientGetFeesMsgOperation(), + SET_FEES: ClientSetFeesMsgOperation(), } # TODO: it is a workaround because INDY-338, `operations` must be a class diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py b/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py index 2a8849e68..c361fd6a3 100644 --- a/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py +++ b/indy_node/server/request_handlers/config_req_handlers/fees/fees_static_helper.py @@ -62,5 +62,3 @@ def build_path_for_set_fees(alias=None): if alias: return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, alias]) return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, FeesStaticHelper.FEES_KEY_FOR_ALL]) - - diff --git a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py index 5485f414c..e56954d9b 100644 --- a/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py +++ b/indy_node/server/request_handlers/config_req_handlers/fees/set_fees_handler.py @@ -23,7 +23,7 @@ def static_validation(self, request: Request): request.reqId, "SET_FEES transactions are forbidden now.") - def dynamic_validation(self, request: Request, req_pp_time: Optional[int]): + def additional_dynamic_validation(self, request: Request, req_pp_time: Optional[int]): raise InvalidClientRequest(request.identifier, request.reqId, "SET_FEES transactions are forbidden now.") diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py index 2c52029e8..b32f3f0df 100644 --- a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py +++ b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py @@ -23,12 +23,4 @@ def get_result(self, request: Request): if proof: result[STATE_PROOF] = proof result.update(request.operation) - return result - - def static_validation(self, request: Request): - try: - self.get_fee_validator_cls(**request.operation) - except TypeError as exc: - raise InvalidClientRequest(request.identifier, - request.reqId, - exc) + return result \ No newline at end of file diff --git a/indy_node/test/catchup/test_state_recovery_with_different_versions.py b/indy_node/test/catchup/test_state_recovery_with_different_versions.py new file mode 100644 index 000000000..cfc4a4a2b --- /dev/null +++ b/indy_node/test/catchup/test_state_recovery_with_different_versions.py @@ -0,0 +1,129 @@ +import shutil +from datetime import datetime, timedelta + +import dateutil +import pytest + +from indy_node.test.fees.helper import sdk_set_fees +from stp_core.ratchet import Ratchet + +from indy_common.config_helper import NodeConfigHelper +from indy_node.test.upgrade.helper import sdk_ensure_upgrade_sent +from plenum.common.constants import TXN_TYPE, DATA, VERSION, CURRENT_PROTOCOL_VERSION +from indy_common.constants import NODE_UPGRADE, ACTION, COMPLETE, AUTH_RULE, START, SET_FEES +from indy_node.test.helper import sdk_send_and_check_auth_rule_request, TestNode +from plenum.common.request import Request +from plenum.common.types import f +from plenum.test.node_catchup.helper import waitNodeDataEquality + +from plenum.test.helper import assertEquality +from plenum.test.test_node import checkNodesConnected, ensure_node_disconnected +from stp_core.loop.eventually import eventually + + +@pytest.fixture(scope="module") +def tconf(tconf): + old_version_matching = tconf.INDY_VERSION_MATCHING + tconf.INDY_VERSION_MATCHING = {"1.1.24": "0.9.3"} + yield tconf + tconf.INDY_VERSION_MATCHING = old_version_matching + + +@pytest.fixture(scope='module') +def valid_upgrade(nodeSet, tconf): + schedule = {} + unow = datetime.utcnow().replace(tzinfo=dateutil.tz.tzutc()) + startAt = unow + timedelta(seconds=30000000) + acceptableDiff = tconf.MinSepBetweenNodeUpgrades + 1 + for n in nodeSet[0].poolManager.nodeIds: + schedule[n] = datetime.isoformat(startAt) + startAt = startAt + timedelta(seconds=acceptableDiff + 3) + + return dict(name='upgrade', version="10000.10.10", + action=START, schedule=schedule, timeout=1, + package=None, + sha256='db34a72a90d026dae49c3b3f0436c8d3963476c77468ad955845a1ccf7b03f55') + + +def send_node_upgrades(nodes, version, looper, count=None): + if count is None: + count = len(nodes) + last_ordered = nodes[0].master_last_ordered_3PC[1] + for node in nodes[:count]: + op = { + TXN_TYPE: NODE_UPGRADE, + DATA: { + ACTION: COMPLETE, + VERSION: version + } + } + op[f.SIG.nm] = node.wallet.signMsg(op[DATA]) + + request = node.wallet.signRequest( + Request(operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION)) + + node.startedProcessingReq(request.key, node.nodestack.name) + node.send(request) + looper.run(eventually(lambda: assertEquality(node.master_last_ordered_3PC[1], + last_ordered + 1))) + last_ordered += 1 + + +def test_state_recovery_with_fees(looper, tconf, tdir, + sdk_pool_handle, + sdk_wallet_trustee, + allPluginsPath, + do_post_node_creation, + nodeSet, + valid_upgrade, + monkeypatch): + version1 = "1.1.24" + version2 = "1.1.88" + node_set = nodeSet + # send POOL_UPGRADE to write in a ledger + last_ordered = node_set[0].master_last_ordered_3PC[1] + sdk_ensure_upgrade_sent(looper, sdk_pool_handle, sdk_wallet_trustee, + valid_upgrade) + looper.run(eventually(lambda: assertEquality(node_set[0].master_last_ordered_3PC[1], + last_ordered + 1))) + + send_node_upgrades(node_set, version1, looper) + for n in node_set: + handler = n.write_manager.request_handlers.get(SET_FEES)[0] + handler_for_0_9_3 = n.write_manager._request_handlers_with_version.get((SET_FEES, "0.9.3"))[0] + monkeypatch.setattr(handler, 'update_state', + handler_for_0_9_3.update_state) + monkeypatch.setattr(handler, 'static_validation', lambda _: _) + monkeypatch.setattr(handler, 'additional_dynamic_validation', lambda a, b: 0) + sdk_set_fees(looper, sdk_pool_handle, sdk_wallet_trustee, {"A": 2}) + send_node_upgrades(node_set, version2, looper) + for n in node_set: + handler = n.write_manager.request_handlers.get(SET_FEES)[0] + monkeypatch.delattr(handler, 'update_state') + sdk_set_fees(looper, sdk_pool_handle, sdk_wallet_trustee, {"B": 2}) + monkeypatch.undo() + node_to_stop = node_set[-1] + state_db_pathes = [state._kv.db_path + for state in node_to_stop.states.values()] + node_to_stop.cleanupOnStopping = False + node_to_stop.stop() + looper.removeProdable(node_to_stop) + ensure_node_disconnected(looper, node_to_stop, node_set[:-1]) + + for path in state_db_pathes: + shutil.rmtree(path) + config_helper = NodeConfigHelper(node_to_stop.name, tconf, chroot=tdir) + restarted_node = TestNode( + node_to_stop.name, + config_helper=config_helper, + config=tconf, + pluginPaths=allPluginsPath, + ha=node_to_stop.nodestack.ha, + cliha=node_to_stop.clientstack.ha) + do_post_node_creation(restarted_node) + + looper.add(restarted_node) + node_set[-1] = restarted_node + + looper.run(checkNodesConnected(node_set)) + waitNodeDataEquality(looper, restarted_node, *node_set[:-1], exclude_from_check=['check_last_ordered_3pc_backup']) diff --git a/indy_node/test/fees/__init__.py b/indy_node/test/fees/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/indy_node/test/fees/helper.py b/indy_node/test/fees/helper.py new file mode 100644 index 000000000..381c389d7 --- /dev/null +++ b/indy_node/test/fees/helper.py @@ -0,0 +1,33 @@ +import json + +from indy.payment import build_set_txn_fees_req + +from indy_common.constants import FEES, SET_FEES +from plenum.common.constants import TXN_TYPE, CURRENT_PROTOCOL_VERSION, LEDGERS_FREEZE, LEDGERS_IDS, GET_FROZEN_LEDGERS +from plenum.test.helper import sdk_get_and_check_replies, sdk_gen_request, \ + sdk_send_signed_requests, sdk_sign_and_submit_req_obj, sdk_multi_sign_request_objects + + +def build_set_fees_request(did, fees): + op = {TXN_TYPE: SET_FEES, + FEES: fees} + return sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, + identifier=did) + + +def build_get_frozen_ledgers_request(did): + op = {TXN_TYPE: GET_FROZEN_LEDGERS} + return sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, + identifier=did) + + +def sdk_set_fees(looper, sdk_pool_handle, sdk_wallet, fees): + req = build_set_fees_request(sdk_wallet[1], fees) + rep = sdk_sign_and_submit_req_obj(looper, sdk_pool_handle, sdk_wallet, req) + return sdk_get_and_check_replies(looper, [rep])[0] + + +def sdk_get_frozen_ledgers(looper, sdk_pool_handle, sdk_wallet): + req = build_get_frozen_ledgers_request(sdk_wallet[1]) + rep = sdk_sign_and_submit_req_obj(looper, sdk_pool_handle, sdk_wallet, req) + return sdk_get_and_check_replies(looper, [rep])[0] diff --git a/indy_node/test/request_handlers/set_fees/conftest.py b/indy_node/test/request_handlers/set_fees/conftest.py new file mode 100644 index 000000000..f915a9dd7 --- /dev/null +++ b/indy_node/test/request_handlers/set_fees/conftest.py @@ -0,0 +1,41 @@ +import pytest + +from indy_common.constants import FEES_ALIAS, GET_FEE, GET_FEES, SET_FEES, FEES +from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler +from plenum.common.constants import TXN_TYPE + +from plenum.common.request import Request + +txn_alias = "txn_alias1" +fees_value = 1 +VALID_FEES = { + txn_alias: fees_value, +} + + +@pytest.fixture(scope="function") +def get_fee_request(creator): + return Request(identifier=creator, + signature="signature", + operation={TXN_TYPE: GET_FEE, + FEES_ALIAS: txn_alias}) + + +@pytest.fixture(scope="function") +def get_fees_request(creator): + return Request(identifier=creator, + signature="signature", + operation={TXN_TYPE: GET_FEES}) + + +@pytest.fixture(scope="function") +def set_fees_request(creator): + return Request(identifier=creator, + signature="signature", + operation={TXN_TYPE: SET_FEES, + FEES: VALID_FEES}) + + +@pytest.fixture +def set_fees_handler(db_manager, write_auth_req_validator): + return SetFeesHandler(db_manager, write_auth_req_validator) diff --git a/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py b/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py new file mode 100644 index 000000000..57b41f62a --- /dev/null +++ b/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py @@ -0,0 +1,18 @@ +import pytest +from indy_common.constants import FEES_ALIAS +from indy_node.server.request_handlers.read_req_handlers.get_fee_handler import GetFeeHandler +from plenum.common.exceptions import InvalidClientRequest + + +@pytest.fixture +def get_fee_handler(db_manager): + return GetFeeHandler(db_manager) + + +def test_get_fee_valid_alias(get_fee_request, get_fee_handler): + """ + StaticValidation of a get fee request with all of the whitelisted txn + types. + """ + result = get_fee_handler.static_validation(get_fee_request) + assert result is None diff --git a/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py b/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py new file mode 100644 index 000000000..fd7c1e3bf --- /dev/null +++ b/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py @@ -0,0 +1,15 @@ +import pytest + +from indy_node.server.request_handlers.read_req_handlers.get_fees_handler import GetFeesHandler + + +@pytest.fixture +def get_fees_handler(db_manager): + return GetFeesHandler(db_manager) + + +def test_get_fees(get_fees_request, get_fees_handler): + """ + StaticValidation of a get fees request does nothing. + """ + get_fees_handler.static_validation(get_fees_request) diff --git a/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py new file mode 100644 index 000000000..b75c55fa4 --- /dev/null +++ b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py @@ -0,0 +1,30 @@ +import pytest + +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper +from indy_node.test.request_handlers.set_fees.conftest import txn_alias, fees_value +from plenum.common.exceptions import InvalidClientRequest +from plenum.common.txn_util import reqToTxn + + +def test_static_validation_missing_fees(set_fees_request, set_fees_handler): + """ + StaticValidation of a set fees request fails because it's forbidden. + """ + with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): + set_fees_handler.static_validation(set_fees_request) + + +def test_dynamic_validation_invalid_signee(set_fees_request, set_fees_handler): + """ + Validation of a set fees request fails because it's forbidden. + """ + with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): + set_fees_handler.dynamic_validation(set_fees_request, None) + + +def test_update_state(set_fees_request, set_fees_handler): + txn = reqToTxn(set_fees_request) + path = FeesStaticHelper.build_path_for_set_fees(txn_alias) + + set_fees_handler.update_state(txn, None, set_fees_request) + assert set_fees_handler.get_from_state(path) == fees_value From cf6c896d1c06248f6d16f8ab3bd4dadbe7c5a35e Mon Sep 17 00:00:00 2001 From: toktar Date: Wed, 17 Feb 2021 19:19:32 +0300 Subject: [PATCH 4/7] flake8 Signed-off-by: toktar --- .../request_handlers/read_req_handlers/get_fee_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py index b32f3f0df..3be5ea2e2 100644 --- a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py +++ b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py @@ -23,4 +23,4 @@ def get_result(self, request: Request): if proof: result[STATE_PROOF] = proof result.update(request.operation) - return result \ No newline at end of file + return result From e0ea3bda18c5c8db33000ed4dfaf9b2fd63c738f Mon Sep 17 00:00:00 2001 From: toktar Date: Thu, 18 Feb 2021 03:51:40 +0300 Subject: [PATCH 5/7] up-41: fix get_fee_handler.py import error Signed-off-by: toktar --- indy_common/constants.py | 1 + .../read_req_handlers/get_fee_handler.py | 4 +- .../request_handlers/set_fees/conftest.py | 40 +++++++++++++++---- .../set_fees/test_get_fee_req_handler.py | 11 ----- .../set_fees/test_get_fees_req_handler.py | 10 ----- .../set_fees/test_set_fees_req_handler.py | 14 ++++--- 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/indy_common/constants.py b/indy_common/constants.py index 4b2211edd..7db3eb43f 100644 --- a/indy_common/constants.py +++ b/indy_common/constants.py @@ -241,6 +241,7 @@ RS_MAPPING_RANK = "rank" # FEES +FEE = "fee" FEES = "fees" FEES_ALIAS = "alias" FEES_VALUE = "value" diff --git a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py index 3be5ea2e2..56fdc430a 100644 --- a/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py +++ b/indy_node/server/request_handlers/read_req_handlers/get_fee_handler.py @@ -1,4 +1,4 @@ -from indy_common.constants import GET_FEE +from indy_common.constants import GET_FEE, FEE from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper from plenum.common.constants import ALIAS, STATE_PROOF, CONFIG_LEDGER_ID, BLS_LABEL from plenum.common.exceptions import InvalidClientRequest @@ -19,7 +19,7 @@ def get_result(self, request: Request): with_proof=True, bls_store=self.database_manager.get_store(BLS_LABEL)) result = {f.IDENTIFIER.nm: request.identifier, - f.REQ_ID.nm: request.reqId, f.FEE.nm: fee} + f.REQ_ID.nm: request.reqId, FEE: fee} if proof: result[STATE_PROOF] = proof result.update(request.operation) diff --git a/indy_node/test/request_handlers/set_fees/conftest.py b/indy_node/test/request_handlers/set_fees/conftest.py index f915a9dd7..676a6db2c 100644 --- a/indy_node/test/request_handlers/set_fees/conftest.py +++ b/indy_node/test/request_handlers/set_fees/conftest.py @@ -2,19 +2,33 @@ from indy_common.constants import FEES_ALIAS, GET_FEE, GET_FEES, SET_FEES, FEES from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler +from indy_node.server.request_handlers.read_req_handlers.get_fee_handler import GetFeeHandler +from indy_node.server.request_handlers.read_req_handlers.get_fees_handler import GetFeesHandler from plenum.common.constants import TXN_TYPE from plenum.common.request import Request -txn_alias = "txn_alias1" -fees_value = 1 -VALID_FEES = { - txn_alias: fees_value, -} + +@pytest.fixture(scope="function") +def txn_alias(): + return "txn_alias1" + + +@pytest.fixture(scope="function") +def fee_value(): + return 1 + + +@pytest.fixture(scope="function") +def valid_fees(txn_alias, fee_value): + return { + txn_alias: fee_value, + "alias2": 2 + } @pytest.fixture(scope="function") -def get_fee_request(creator): +def get_fee_request(creator, txn_alias): return Request(identifier=creator, signature="signature", operation={TXN_TYPE: GET_FEE, @@ -29,13 +43,23 @@ def get_fees_request(creator): @pytest.fixture(scope="function") -def set_fees_request(creator): +def set_fees_request(creator, valid_fees): return Request(identifier=creator, signature="signature", operation={TXN_TYPE: SET_FEES, - FEES: VALID_FEES}) + FEES: valid_fees}) @pytest.fixture def set_fees_handler(db_manager, write_auth_req_validator): return SetFeesHandler(db_manager, write_auth_req_validator) + + +@pytest.fixture +def get_fee_handler(db_manager): + return GetFeeHandler(db_manager) + + +@pytest.fixture +def get_fees_handler(db_manager): + return GetFeesHandler(db_manager) diff --git a/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py b/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py index 57b41f62a..120b6f7d6 100644 --- a/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py +++ b/indy_node/test/request_handlers/set_fees/test_get_fee_req_handler.py @@ -1,14 +1,3 @@ -import pytest -from indy_common.constants import FEES_ALIAS -from indy_node.server.request_handlers.read_req_handlers.get_fee_handler import GetFeeHandler -from plenum.common.exceptions import InvalidClientRequest - - -@pytest.fixture -def get_fee_handler(db_manager): - return GetFeeHandler(db_manager) - - def test_get_fee_valid_alias(get_fee_request, get_fee_handler): """ StaticValidation of a get fee request with all of the whitelisted txn diff --git a/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py b/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py index fd7c1e3bf..f804a2eff 100644 --- a/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py +++ b/indy_node/test/request_handlers/set_fees/test_get_fees_req_handler.py @@ -1,13 +1,3 @@ -import pytest - -from indy_node.server.request_handlers.read_req_handlers.get_fees_handler import GetFeesHandler - - -@pytest.fixture -def get_fees_handler(db_manager): - return GetFeesHandler(db_manager) - - def test_get_fees(get_fees_request, get_fees_handler): """ StaticValidation of a get fees request does nothing. diff --git a/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py index b75c55fa4..c0c0d7f1c 100644 --- a/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py +++ b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py @@ -1,7 +1,6 @@ import pytest -from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper -from indy_node.test.request_handlers.set_fees.conftest import txn_alias, fees_value +from indy_common.constants import FEE from plenum.common.exceptions import InvalidClientRequest from plenum.common.txn_util import reqToTxn @@ -22,9 +21,12 @@ def test_dynamic_validation_invalid_signee(set_fees_request, set_fees_handler): set_fees_handler.dynamic_validation(set_fees_request, None) -def test_update_state(set_fees_request, set_fees_handler): +def test_update_state(set_fees_handler, get_fees_handler, get_fee_handler, + set_fees_request, get_fees_request, get_fee_request, + fee_value, valid_fees): txn = reqToTxn(set_fees_request) - path = FeesStaticHelper.build_path_for_set_fees(txn_alias) - set_fees_handler.update_state(txn, None, set_fees_request) - assert set_fees_handler.get_from_state(path) == fees_value + set_fees_handler.update_state(txn, None, set_fees_request, is_committed=True) + fees_map = get_fees_handler.get_fees(get_fees_request) + + assert fees_map == valid_fees From 759a6c1c8c64fa2da2fd2a6394499ff366ec8f3f Mon Sep 17 00:00:00 2001 From: toktar Date: Fri, 19 Feb 2021 18:54:52 +0300 Subject: [PATCH 6/7] up-41: fix tests Signed-off-by: toktar --- indy_node/test/fees/helper.py | 32 ++++++++++++------- indy_node/test/fees/test_set_fees.py | 20 ++++++++++++ .../set_fees/test_set_fees_req_handler.py | 30 ++++++++--------- 3 files changed, 55 insertions(+), 27 deletions(-) create mode 100644 indy_node/test/fees/test_set_fees.py diff --git a/indy_node/test/fees/helper.py b/indy_node/test/fees/helper.py index 381c389d7..4fcc19c03 100644 --- a/indy_node/test/fees/helper.py +++ b/indy_node/test/fees/helper.py @@ -1,11 +1,6 @@ -import json - -from indy.payment import build_set_txn_fees_req - -from indy_common.constants import FEES, SET_FEES -from plenum.common.constants import TXN_TYPE, CURRENT_PROTOCOL_VERSION, LEDGERS_FREEZE, LEDGERS_IDS, GET_FROZEN_LEDGERS -from plenum.test.helper import sdk_get_and_check_replies, sdk_gen_request, \ - sdk_send_signed_requests, sdk_sign_and_submit_req_obj, sdk_multi_sign_request_objects +from indy_common.constants import FEES, SET_FEES, GET_FEE, GET_FEES, FEES_ALIAS +from plenum.common.constants import TXN_TYPE, CURRENT_PROTOCOL_VERSION +from plenum.test.helper import sdk_get_and_check_replies, sdk_gen_request, sdk_sign_and_submit_req_obj def build_set_fees_request(did, fees): @@ -15,8 +10,15 @@ def build_set_fees_request(did, fees): identifier=did) -def build_get_frozen_ledgers_request(did): - op = {TXN_TYPE: GET_FROZEN_LEDGERS} +def build_get_fee(did, alias): + op = {TXN_TYPE: GET_FEE, + FEES_ALIAS: alias} + return sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, + identifier=did) + + +def build_get_fees(did): + op = {TXN_TYPE: GET_FEES} return sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, identifier=did) @@ -27,7 +29,13 @@ def sdk_set_fees(looper, sdk_pool_handle, sdk_wallet, fees): return sdk_get_and_check_replies(looper, [rep])[0] -def sdk_get_frozen_ledgers(looper, sdk_pool_handle, sdk_wallet): - req = build_get_frozen_ledgers_request(sdk_wallet[1]) +def sdk_get_fee(looper, sdk_pool_handle, sdk_wallet, alias): + req = build_get_fee(sdk_wallet[1], alias) + rep = sdk_sign_and_submit_req_obj(looper, sdk_pool_handle, sdk_wallet, req) + return sdk_get_and_check_replies(looper, [rep])[0] + + +def sdk_get_fees(looper, sdk_pool_handle, sdk_wallet): + req = build_get_fees(sdk_wallet[1]) rep = sdk_sign_and_submit_req_obj(looper, sdk_pool_handle, sdk_wallet, req) return sdk_get_and_check_replies(looper, [rep])[0] diff --git a/indy_node/test/fees/test_set_fees.py b/indy_node/test/fees/test_set_fees.py new file mode 100644 index 000000000..45c3f857d --- /dev/null +++ b/indy_node/test/fees/test_set_fees.py @@ -0,0 +1,20 @@ +from indy_common.constants import SET_FEES, FEE, FEES +from indy_node.test.fees.helper import sdk_set_fees, sdk_get_fees, sdk_get_fee + + +def test_set_fees(looper, sdk_pool_handle, nodeSet, + sdk_wallet_trustee, monkeypatch): + txn_alias = "txn_alias" + fee_value = 4 + + for n in nodeSet: + handler = n.write_manager.request_handlers.get(SET_FEES)[0] + monkeypatch.setattr(handler, 'static_validation', lambda _: _) + monkeypatch.setattr(handler, 'additional_dynamic_validation', lambda a, b: 0) + + sdk_set_fees(looper, sdk_pool_handle, sdk_wallet_trustee, {txn_alias: fee_value}) + get_fees_result = sdk_get_fees(looper, sdk_pool_handle, sdk_wallet_trustee) + get_fee_result = sdk_get_fee(looper, sdk_pool_handle, sdk_wallet_trustee, txn_alias) + + assert get_fees_result[1]["result"][FEES] == {txn_alias: fee_value} + assert get_fee_result[1]["result"][FEE] == fee_value diff --git a/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py index c0c0d7f1c..e6ba5bb48 100644 --- a/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py +++ b/indy_node/test/request_handlers/set_fees/test_set_fees_req_handler.py @@ -1,32 +1,32 @@ import pytest -from indy_common.constants import FEE +from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper from plenum.common.exceptions import InvalidClientRequest from plenum.common.txn_util import reqToTxn def test_static_validation_missing_fees(set_fees_request, set_fees_handler): - """ - StaticValidation of a set fees request fails because it's forbidden. - """ - with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): - set_fees_handler.static_validation(set_fees_request) + """ + StaticValidation of a set fees request fails because it's forbidden. + """ + with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): + set_fees_handler.static_validation(set_fees_request) def test_dynamic_validation_invalid_signee(set_fees_request, set_fees_handler): - """ - Validation of a set fees request fails because it's forbidden. - """ - with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): - set_fees_handler.dynamic_validation(set_fees_request, None) + """ + Validation of a set fees request fails because it's forbidden. + """ + with pytest.raises(InvalidClientRequest, match="SET_FEES transactions are forbidden now."): + set_fees_handler.dynamic_validation(set_fees_request, None) -def test_update_state(set_fees_handler, get_fees_handler, get_fee_handler, - set_fees_request, get_fees_request, get_fee_request, - fee_value, valid_fees): +def test_update_state(set_fees_handler, set_fees_request, config_state, txn_alias, fee_value, valid_fees): txn = reqToTxn(set_fees_request) set_fees_handler.update_state(txn, None, set_fees_request, is_committed=True) - fees_map = get_fees_handler.get_fees(get_fees_request) + fees_map = FeesStaticHelper.get_fee_from_state(config_state) + state_fee_value = FeesStaticHelper.get_fee_from_state(config_state, txn_alias) + assert state_fee_value == fee_value assert fees_map == valid_fees From 5452767ff902dbb846eae74c84cb19f36fb8d0fc Mon Sep 17 00:00:00 2001 From: toktar Date: Fri, 19 Feb 2021 19:59:08 +0300 Subject: [PATCH 7/7] up-41: add schema tests Signed-off-by: toktar --- indy_common/test/types/test_get_fee_schema.py | 20 +++++++++++++++++++ .../test/types/test_get_fees_schema.py | 19 ++++++++++++++++++ .../test/types/test_set_fees_schema.py | 20 +++++++++++++++++++ indy_common/types.py | 12 +++++------ 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 indy_common/test/types/test_get_fee_schema.py create mode 100644 indy_common/test/types/test_get_fees_schema.py create mode 100644 indy_common/test/types/test_set_fees_schema.py diff --git a/indy_common/test/types/test_get_fee_schema.py b/indy_common/test/types/test_get_fee_schema.py new file mode 100644 index 000000000..325730731 --- /dev/null +++ b/indy_common/test/types/test_get_fee_schema.py @@ -0,0 +1,20 @@ +from collections import OrderedDict + +from indy_common.types import ClientGetFeeOperation +from plenum.common.messages.fields import ConstantField, LimitedLengthStringField + +EXPECTED_ORDERED_FIELDS = OrderedDict([ + ("type", ConstantField), + ("alias", LimitedLengthStringField), +]) + + +def test_has_expected_fields(): + actual_field_names = OrderedDict(ClientGetFeeOperation.schema).keys() + assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys() + + +def test_has_expected_validators(): + schema = dict(ClientGetFeeOperation.schema) + for field, validator in EXPECTED_ORDERED_FIELDS.items(): + assert isinstance(schema[field], validator) diff --git a/indy_common/test/types/test_get_fees_schema.py b/indy_common/test/types/test_get_fees_schema.py new file mode 100644 index 000000000..9ec93feb7 --- /dev/null +++ b/indy_common/test/types/test_get_fees_schema.py @@ -0,0 +1,19 @@ +from collections import OrderedDict + +from indy_common.types import ClientGetFeesOperation +from plenum.common.messages.fields import ConstantField + +EXPECTED_ORDERED_FIELDS = OrderedDict([ + ("type", ConstantField), +]) + + +def test_has_expected_fields(): + actual_field_names = OrderedDict(ClientGetFeesOperation.schema).keys() + assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys() + + +def test_has_expected_validators(): + schema = dict(ClientGetFeesOperation.schema) + for field, validator in EXPECTED_ORDERED_FIELDS.items(): + assert isinstance(schema[field], validator) diff --git a/indy_common/test/types/test_set_fees_schema.py b/indy_common/test/types/test_set_fees_schema.py new file mode 100644 index 000000000..9dcf414c5 --- /dev/null +++ b/indy_common/test/types/test_set_fees_schema.py @@ -0,0 +1,20 @@ +from collections import OrderedDict + +from indy_common.types import ClientSetFeesOperation, SetFeesField +from plenum.common.messages.fields import ConstantField + +EXPECTED_ORDERED_FIELDS = OrderedDict([ + ("type", ConstantField), + ("fees", SetFeesField), +]) + + +def test_has_expected_fields(): + actual_field_names = OrderedDict(ClientSetFeesOperation.schema).keys() + assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys() + + +def test_has_expected_validators(): + schema = dict(ClientSetFeesOperation.schema) + for field, validator in EXPECTED_ORDERED_FIELDS.items(): + assert isinstance(schema[field], validator) diff --git a/indy_common/types.py b/indy_common/types.py index 1b20b1549..44ac54f1b 100644 --- a/indy_common/types.py +++ b/indy_common/types.py @@ -467,14 +467,14 @@ class ClientGetRichSchemaObjectByMetadataOperation(MessageValidator): ) -class ClientGetFeeMsgOperation(MessageValidator): +class ClientGetFeeOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_FEE)), (FEES_ALIAS, LimitedLengthStringField(max_length=FEE_ALIAS_LENGTH)), ) -class ClientGetFeesMsgOperation(MessageValidator): +class ClientGetFeesOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_FEES)), ) @@ -491,7 +491,7 @@ def _specific_validation(self, val): return "set_fees -- " + error -class ClientSetFeesMsgOperation(MessageValidator): +class ClientSetFeesOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(SET_FEES)), (FEES, SetFeesField()), @@ -528,9 +528,9 @@ class ClientOperationField(PClientOperationField): RICH_SCHEMA_PRES_DEF: ClientRichSchemaPresDefOperation(), GET_RICH_SCHEMA_OBJECT_BY_ID: ClientGetRichSchemaObjectByIdOperation(), GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation(), - GET_FEE: ClientGetFeeMsgOperation(), - GET_FEES: ClientGetFeesMsgOperation(), - SET_FEES: ClientSetFeesMsgOperation(), + GET_FEE: ClientGetFeeOperation(), + GET_FEES: ClientGetFeesOperation(), + SET_FEES: ClientSetFeesOperation(), } # TODO: it is a workaround because INDY-338, `operations` must be a class