diff --git a/plenum/common/constants.py b/plenum/common/constants.py index b8c67cc88f..32e1c8ba1d 100644 --- a/plenum/common/constants.py +++ b/plenum/common/constants.py @@ -1,4 +1,5 @@ # inter-node communication +from collections import defaultdict from enum import IntEnum, unique from plenum.common.plenum_protocol_version import PlenumProtocolVersion @@ -154,9 +155,13 @@ GET_TXN = PlenumTransactions.GET_TXN.value TXN_AUTHOR_AGREEMENT = PlenumTransactions.TXN_AUTHOR_AGREEMENT.value TXN_AUTHOR_AGREEMENT_AML = PlenumTransactions.TXN_AUTHOR_AGREEMENT_AML.value +TXN_AUTHOR_AGREEMENT_DISABLE = PlenumTransactions.TXN_AUTHOR_AGREEMENT_DISABLE.value GET_TXN_AUTHOR_AGREEMENT = PlenumTransactions.GET_TXN_AUTHOR_AGREEMENT.value GET_TXN_AUTHOR_AGREEMENT_AML = PlenumTransactions.GET_TXN_AUTHOR_AGREEMENT_AML.value +CURRENT_TXN_VERSIONS = defaultdict(lambda: "1") +CURRENT_TXN_VERSIONS[TXN_AUTHOR_AGREEMENT] = "2" + # TXN # TODO: manye of these constants will be replaced # by constants from Request after Request refactoring @@ -264,7 +269,6 @@ class LedgerState(IntEnum): VALID_LEDGER_IDS = (POOL_LEDGER_ID, DOMAIN_LEDGER_ID, CONFIG_LEDGER_ID, AUDIT_LEDGER_ID) CURRENT_PROTOCOL_VERSION = PlenumProtocolVersion.TXN_FORMAT_1_0_SUPPORT.value -CURRENT_TXN_VERSION = "2" OPERATION_SCHEMA_IS_STRICT = False SCHEMA_IS_STRICT = False diff --git a/plenum/common/messages/client_request.py b/plenum/common/messages/client_request.py index 720c498bf8..db86ad345d 100644 --- a/plenum/common/messages/client_request.py +++ b/plenum/common/messages/client_request.py @@ -6,7 +6,8 @@ TXN_AUTHOR_AGREEMENT_AML, AML, AML_CONTEXT, AML_VERSION, \ TXN_AUTHOR_AGREEMENT_VERSION, GET_TXN_AUTHOR_AGREEMENT, GET_TXN_AUTHOR_AGREEMENT_VERSION, \ GET_TXN_AUTHOR_AGREEMENT_DIGEST, GET_TXN_AUTHOR_AGREEMENT_TIMESTAMP, GET_TXN_AUTHOR_AGREEMENT_AML_VERSION, \ - GET_TXN_AUTHOR_AGREEMENT_AML_TIMESTAMP, GET_TXN_AUTHOR_AGREEMENT_AML, TXN_AUTHOR_AGREEMENT_RETIRED + GET_TXN_AUTHOR_AGREEMENT_AML_TIMESTAMP, GET_TXN_AUTHOR_AGREEMENT_AML, TXN_AUTHOR_AGREEMENT_RETIRED, \ + TXN_AUTHOR_AGREEMENT_DISABLE from plenum.common.messages.fields import NetworkIpAddressField, \ NetworkPortField, IterableField, \ ChooseField, ConstantField, DestNodeField, VerkeyField, DestNymField, \ @@ -81,6 +82,12 @@ class ClientTxnAuthorAgreementOperation(MessageValidator): ) +class ClientTxnAuthorAgreementDisableOperation(MessageValidator): + schema = ( + (TXN_TYPE, ConstantField(TXN_AUTHOR_AGREEMENT_DISABLE)), + ) + + class ClientTxnAuthorAgreementOperationAML(MessageValidator): schema = ( (TXN_TYPE, ConstantField(TXN_AUTHOR_AGREEMENT_AML)), @@ -117,6 +124,7 @@ def __init__(self, *args, **kwargs): NYM: ClientNYMOperation(schema_is_strict=strict), GET_TXN: ClientGetTxnOperation(schema_is_strict=strict), TXN_AUTHOR_AGREEMENT: ClientTxnAuthorAgreementOperation(schema_is_strict=strict), + TXN_AUTHOR_AGREEMENT_DISABLE: ClientTxnAuthorAgreementDisableOperation(schema_is_strict=strict), TXN_AUTHOR_AGREEMENT_AML: ClientTxnAuthorAgreementOperationAML(schema_is_strict=strict), GET_TXN_AUTHOR_AGREEMENT: ClientGetTxnAuthorAgreementOperation(schema_is_strict=strict), GET_TXN_AUTHOR_AGREEMENT_AML: ClientGetTxnAuthorAgreementAMLOperation(schema_is_strict=strict) diff --git a/plenum/common/transactions.py b/plenum/common/transactions.py index dd966018ee..acad03e879 100644 --- a/plenum/common/transactions.py +++ b/plenum/common/transactions.py @@ -20,3 +20,4 @@ class PlenumTransactions(Transactions): TXN_AUTHOR_AGREEMENT_AML = "5" GET_TXN_AUTHOR_AGREEMENT = "6" GET_TXN_AUTHOR_AGREEMENT_AML = "7" + TXN_AUTHOR_AGREEMENT_DISABLE = "8" diff --git a/plenum/common/txn_util.py b/plenum/common/txn_util.py index 01c736c8bd..425946a25c 100644 --- a/plenum/common/txn_util.py +++ b/plenum/common/txn_util.py @@ -9,7 +9,7 @@ TXN_PAYLOAD_METADATA_FROM, TXN_PAYLOAD_PROTOCOL_VERSION, TXN_PAYLOAD_TYPE, TXN_METADATA_SEQ_NO, TXN_METADATA_TIME, \ TXN_METADATA_ID, TXN_VERSION, TXN_PAYLOAD_METADATA_DIGEST, TXN_ID, CURRENT_PROTOCOL_VERSION, \ TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST, TXN_PAYLOAD_METADATA_TAA_ACCEPTANCE, TXN_PAYLOAD_METADATA_ENDORSER, \ - CURRENT_TXN_VERSION + CURRENT_TXN_VERSIONS from plenum.common.request import Request from plenum.common.types import f, OPERATION from stp_core.common.log import getlogger @@ -177,7 +177,7 @@ def init_empty_txn(txn_type, protocol_version=CURRENT_PROTOCOL_VERSION): result[TXN_PAYLOAD] = {} result[TXN_METADATA] = {} result[TXN_SIGNATURE] = {} - result[TXN_VERSION] = CURRENT_TXN_VERSION + result[TXN_VERSION] = CURRENT_TXN_VERSIONS[txn_type] set_type(result, txn_type) result[TXN_PAYLOAD][TXN_PAYLOAD_DATA] = {} diff --git a/plenum/server/batch_handlers/audit_batch_handler.py b/plenum/server/batch_handlers/audit_batch_handler.py index 5821e10cb4..bce2634ee4 100644 --- a/plenum/server/batch_handlers/audit_batch_handler.py +++ b/plenum/server/batch_handlers/audit_batch_handler.py @@ -4,7 +4,7 @@ from ledger.ledger import Ledger from plenum.common.constants import AUDIT_LEDGER_ID, TXN_VERSION, AUDIT_TXN_VIEW_NO, AUDIT_TXN_PP_SEQ_NO, \ AUDIT_TXN_LEDGERS_SIZE, AUDIT_TXN_LEDGER_ROOT, AUDIT_TXN_STATE_ROOT, AUDIT_TXN_PRIMARIES, AUDIT_TXN_DIGEST, \ - AUDIT_TXN_NODE_REG, CURRENT_TXN_VERSION + AUDIT_TXN_NODE_REG, CURRENT_TXN_VERSIONS from plenum.common.ledger_uncommitted_tracker import LedgerUncommittedTracker from plenum.common.transactions import PlenumTransactions from plenum.common.txn_util import init_empty_txn, set_payload_data, get_payload_data, get_seq_no @@ -83,7 +83,7 @@ def _create_audit_txn_data(self, three_pc_batch, last_audit_txn): # 1. general format and (view_no, pp_seq_no) view_no = three_pc_batch.original_view_no if three_pc_batch.original_view_no is not None else three_pc_batch.view_no txn = { - TXN_VERSION: CURRENT_TXN_VERSION, + TXN_VERSION: CURRENT_TXN_VERSIONS["AUDIT_LEDGER"], AUDIT_TXN_VIEW_NO: view_no, AUDIT_TXN_PP_SEQ_NO: three_pc_batch.pp_seq_no, AUDIT_TXN_LEDGERS_SIZE: {}, diff --git a/plenum/server/ledgers_bootstrap.py b/plenum/server/ledgers_bootstrap.py index ff7f7fc771..b7f7eda31d 100644 --- a/plenum/server/ledgers_bootstrap.py +++ b/plenum/server/ledgers_bootstrap.py @@ -22,6 +22,7 @@ from plenum.server.request_handlers.node_handler import NodeHandler from plenum.server.request_handlers.nym_handler import NymHandler from plenum.server.request_handlers.txn_author_agreement_aml_handler import TxnAuthorAgreementAmlHandler +from plenum.server.request_handlers.txn_author_agreement_disable_handler import TxnAuthorAgreementDisableHandler from plenum.server.request_handlers.txn_author_agreement_handler import TxnAuthorAgreementHandler from plenum.server.request_managers.action_request_manager import ActionRequestManager from plenum.server.request_managers.read_request_manager import ReadRequestManager @@ -141,11 +142,13 @@ def _register_domain_req_handlers(self): def _register_config_req_handlers(self): taa_aml_handler = TxnAuthorAgreementAmlHandler(database_manager=self.db_manager) taa_handler = TxnAuthorAgreementHandler(database_manager=self.db_manager) + taa_disable_handler = TxnAuthorAgreementDisableHandler(database_manager=self.db_manager) get_taa_aml_handler = GetTxnAuthorAgreementAmlHandler(database_manager=self.db_manager) get_taa_handler = GetTxnAuthorAgreementHandler(database_manager=self.db_manager) self.write_manager.register_req_handler(taa_aml_handler) self.write_manager.register_req_handler(taa_handler) + self.write_manager.register_req_handler(taa_disable_handler) self.read_manager.register_req_handler(get_taa_aml_handler) self.read_manager.register_req_handler(get_taa_handler) diff --git a/plenum/server/request_handlers/base_taa_handler.py b/plenum/server/request_handlers/base_taa_handler.py new file mode 100644 index 0000000000..f9734708e4 --- /dev/null +++ b/plenum/server/request_handlers/base_taa_handler.py @@ -0,0 +1,49 @@ +from abc import ABCMeta + +from common.serializers.serialization import config_state_serializer +from plenum.common.constants import TXN_AUTHOR_AGREEMENT, CONFIG_LEDGER_ID, TXN_AUTHOR_AGREEMENT_VERSION, \ + TXN_AUTHOR_AGREEMENT_TEXT, TXN_AUTHOR_AGREEMENT_DIGEST, TXN_AUTHOR_AGREEMENT_RETIRED, \ + TXN_AUTHOR_AGREEMENT_TIMESTAMP +from plenum.common.exceptions import InvalidClientRequest +from plenum.common.request import Request +from plenum.common.txn_util import get_payload_data, get_seq_no, get_txn_time +from plenum.common.util import SortedDict +from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.handler_interfaces.write_request_handler import WriteRequestHandler +from plenum.server.request_handlers.static_taa_helper import StaticTAAHelper +from plenum.server.request_handlers.utils import encode_state_value, decode_state_value + + +class BaseTAAHandler(WriteRequestHandler, metaclass=ABCMeta): + + def _update_txn_author_agreement(self, digest, seq_no, txn_time, text=None, version=None, retired=None): + taa_time = None + ledger_taa = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest))[0] + if ledger_taa: + taa_time = ledger_taa.get(TXN_AUTHOR_AGREEMENT_TIMESTAMP) + text = ledger_taa.get(TXN_AUTHOR_AGREEMENT_TEXT) + version = ledger_taa.get(TXN_AUTHOR_AGREEMENT_VERSION) + + state_value = { + TXN_AUTHOR_AGREEMENT_TEXT: text, + TXN_AUTHOR_AGREEMENT_VERSION: version, + TXN_AUTHOR_AGREEMENT_DIGEST: digest + } + if retired: + state_value[TXN_AUTHOR_AGREEMENT_RETIRED] = retired + state_value[TXN_AUTHOR_AGREEMENT_TIMESTAMP] = txn_time if taa_time is None else taa_time + + data = encode_state_value(state_value, seq_no, txn_time, + serializer=config_state_serializer) + + self.state.set(StaticTAAHelper.state_path_taa_digest(digest), data) + self.state.set(StaticTAAHelper.state_path_taa_version(version), digest) + if not retired: + self.state.set(StaticTAAHelper.state_path_taa_latest(), digest) + + # self.state.set(StaticTAAHelper.state_path_taa_digest(digest), data) + # self.state.set(StaticTAAHelper.state_path_taa_latest(), digest) + # self.state.set(StaticTAAHelper.state_path_taa_version(version), digest) + + def authorize(self, request): + StaticTAAHelper.authorize(self.database_manager, request) diff --git a/plenum/server/request_handlers/static_taa_helper.py b/plenum/server/request_handlers/static_taa_helper.py index 08df17b9a8..07d9922625 100644 --- a/plenum/server/request_handlers/static_taa_helper.py +++ b/plenum/server/request_handlers/static_taa_helper.py @@ -11,6 +11,11 @@ class StaticTAAHelper: + @staticmethod + def state_path_taa_active_list() -> bytes: + return "{marker}:active_list". \ + format(marker=MARKER_TAA).encode() + @staticmethod def state_path_taa_latest() -> bytes: return "{marker}:latest". \ diff --git a/plenum/server/request_handlers/txn_author_agreement_disable_handler.py b/plenum/server/request_handlers/txn_author_agreement_disable_handler.py new file mode 100644 index 0000000000..37d1b0f7d5 --- /dev/null +++ b/plenum/server/request_handlers/txn_author_agreement_disable_handler.py @@ -0,0 +1,47 @@ +from common.serializers.serialization import config_state_serializer +from plenum.common.constants import TXN_AUTHOR_AGREEMENT, CONFIG_LEDGER_ID, TXN_AUTHOR_AGREEMENT_VERSION, \ + TXN_AUTHOR_AGREEMENT_TEXT, TXN_AUTHOR_AGREEMENT_DIGEST, TXN_AUTHOR_AGREEMENT_RETIRED, \ + TXN_AUTHOR_AGREEMENT_TIMESTAMP, TXN_AUTHOR_AGREEMENT_DISABLE +from plenum.common.exceptions import InvalidClientRequest +from plenum.common.request import Request +from plenum.common.txn_util import get_payload_data, get_seq_no, get_txn_time +from plenum.common.util import SortedDict +from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.base_taa_handler import BaseTAAHandler +from plenum.server.request_handlers.handler_interfaces.write_request_handler import WriteRequestHandler +from plenum.server.request_handlers.static_taa_helper import StaticTAAHelper +from plenum.server.request_handlers.utils import encode_state_value, decode_state_value +import time + +from state.trie.pruning_trie import rlp_decode + + +class TxnAuthorAgreementDisableHandler(BaseTAAHandler): + + def __init__(self, database_manager: DatabaseManager): + super().__init__(database_manager, TXN_AUTHOR_AGREEMENT_DISABLE, CONFIG_LEDGER_ID) + self.retired_time = int(time.time() // (2600 * 24)) + + def static_validation(self, request: Request): + pass + + def dynamic_validation(self, request: Request): + self._validate_request_type(request) + self.authorize(request) + operation, identifier, req_id = request.operation, request.identifier, request.reqId + if not self.state.get(StaticTAAHelper.state_path_taa_latest(), isCommitted=False): + raise InvalidClientRequest(identifier, req_id, + "Transaction author agreement is already disabled.") + + def update_state(self, txn, prev_result, request, is_committed=False): + self._validate_txn_type(txn) + seq_no = get_seq_no(txn) + txn_time = get_txn_time(txn) + _, taa_list = self.state.generate_state_proof_for_keys_with_prefix(StaticTAAHelper.state_path_taa_digest(""), + serialize=False, get_value=True) + for encode_key, encode_data in taa_list.items(): + # taa = rlp_decode(encode_data) + # taa = self._decode_state_value(taa[0])[0] + digest = encode_key.decode().split(":")[-1] + self._update_txn_author_agreement(digest, seq_no, txn_time, retired=self.retired_time) + self.state.remove(StaticTAAHelper.state_path_taa_latest()) diff --git a/plenum/server/request_handlers/txn_author_agreement_handler.py b/plenum/server/request_handlers/txn_author_agreement_handler.py index 8a3a143992..abed682e53 100644 --- a/plenum/server/request_handlers/txn_author_agreement_handler.py +++ b/plenum/server/request_handlers/txn_author_agreement_handler.py @@ -5,13 +5,15 @@ from plenum.common.exceptions import InvalidClientRequest from plenum.common.request import Request from plenum.common.txn_util import get_payload_data, get_seq_no, get_txn_time +from plenum.common.util import SortedDict from plenum.server.database_manager import DatabaseManager +from plenum.server.request_handlers.base_taa_handler import BaseTAAHandler from plenum.server.request_handlers.handler_interfaces.write_request_handler import WriteRequestHandler from plenum.server.request_handlers.static_taa_helper import StaticTAAHelper from plenum.server.request_handlers.utils import encode_state_value, decode_state_value -class TxnAuthorAgreementHandler(WriteRequestHandler): +class TxnAuthorAgreementHandler(BaseTAAHandler): def __init__(self, database_manager: DatabaseManager): super().__init__(database_manager, TXN_AUTHOR_AGREEMENT, CONFIG_LEDGER_ID) @@ -28,47 +30,22 @@ def dynamic_validation(self, request: Request): raise InvalidClientRequest(identifier, req_id, "TAA txn is forbidden until TAA AML is set. Send TAA AML first.") version = operation[TXN_AUTHOR_AGREEMENT_VERSION] - text = operation.get(TXN_AUTHOR_AGREEMENT_TEXT) digest = StaticTAAHelper.get_taa_digest(self.state, version, isCommitted=False) - if digest is not None: - ledger_taa = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest))[0] - if ledger_taa.get(TXN_AUTHOR_AGREEMENT_TEXT, text) != text: - raise InvalidClientRequest(identifier, req_id, - "Changing a text of existing transaction author agreement is forbidden") + if digest is None: + self._validate_add_taa(request) + else: + self._validate_update_taa(request, digest) def update_state(self, txn, prev_result, request, is_committed=False): self._validate_txn_type(txn) payload = get_payload_data(txn) - text = payload[TXN_AUTHOR_AGREEMENT_TEXT] + text = payload.get(TXN_AUTHOR_AGREEMENT_TEXT) version = payload[TXN_AUTHOR_AGREEMENT_VERSION] retired = payload.get(TXN_AUTHOR_AGREEMENT_RETIRED, False) seq_no = get_seq_no(txn) txn_time = get_txn_time(txn) - self._update_txn_author_agreement(text, version, seq_no, txn_time, retired) - - def _update_txn_author_agreement(self, text, version, seq_no, txn_time, retired=False): digest = StaticTAAHelper.taa_digest(text, version) - state_value = { - TXN_AUTHOR_AGREEMENT_TEXT: text, - TXN_AUTHOR_AGREEMENT_VERSION: version, - TXN_AUTHOR_AGREEMENT_DIGEST: digest - } - taa_time = None - ledger_taa = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest))[0] - if ledger_taa: - taa_time = ledger_taa.get(TXN_AUTHOR_AGREEMENT_TIMESTAMP) - - if retired: - state_value[TXN_AUTHOR_AGREEMENT_RETIRED] = retired - else: - taa_time = txn_time if taa_time is None else taa_time - state_value[TXN_AUTHOR_AGREEMENT_TIMESTAMP] = taa_time - - data = encode_state_value(state_value, seq_no, txn_time, - serializer=config_state_serializer) - self.state.set(StaticTAAHelper.state_path_taa_digest(digest), data) - self.state.set(StaticTAAHelper.state_path_taa_latest(), digest) - self.state.set(StaticTAAHelper.state_path_taa_version(version), digest) + self._update_txn_author_agreement(digest, seq_no, txn_time, text, version, retired) def authorize(self, request): StaticTAAHelper.authorize(self.database_manager, request) @@ -79,3 +56,22 @@ def _decode_state_value(self, encoded): serializer=config_state_serializer) return value, last_seq_no, last_update_time return None, None, None + + def _validate_add_taa(self, request): + if request.operation.get(TXN_AUTHOR_AGREEMENT_RETIRED, False): + raise InvalidClientRequest(request.identifier, request.reqId, + "Cannot create a transaction author agreement with a 'retired' field.") + + def _validate_update_taa(self, request, digest): + # check TAA text + text = request.operation.get(TXN_AUTHOR_AGREEMENT_TEXT) + ledger_taa = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest))[0] + if ledger_taa.get(TXN_AUTHOR_AGREEMENT_TEXT, text) != text: + raise InvalidClientRequest(request.identifier, request.reqId, + "Changing a text of existing transaction author agreement is forbidden") + # check the latest TAA + if request.operation.get(TXN_AUTHOR_AGREEMENT_RETIRED, False): + last_taa_digest = self.get_from_state(StaticTAAHelper.state_path_taa_latest()) + if last_taa_digest == digest: + raise InvalidClientRequest(request.identifier, request.reqId, + "The latest transaction author agreement cannot be retired.") diff --git a/plenum/test/audit_ledger/helper.py b/plenum/test/audit_ledger/helper.py index a964f775a0..ee7403bd3a 100644 --- a/plenum/test/audit_ledger/helper.py +++ b/plenum/test/audit_ledger/helper.py @@ -1,7 +1,7 @@ from common.serializers.json_serializer import JsonSerializer from common.serializers.serialization import domain_state_serializer from ledger.ledger import Ledger -from plenum.common.constants import CURRENT_PROTOCOL_VERSION, CURRENT_TXN_VERSION +from plenum.common.constants import CURRENT_PROTOCOL_VERSION, CURRENT_TXN_VERSIONS from plenum.common.txn_util import do_req_to_txn from plenum.server.batch_handlers.three_pc_batch import ThreePcBatch @@ -46,7 +46,7 @@ def check_audit_txn(txn, "txn": { "data": { "ledgerRoot": expectedLedgerRoots, - "ver": CURRENT_TXN_VERSION, + "ver": CURRENT_TXN_VERSIONS["2"], "viewNo": view_no, "ppSeqNo": pp_seq_no, "ledgerSize": ledger_size, @@ -64,7 +64,7 @@ def check_audit_txn(txn, "txnTime": txn_time }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS["2"] } if node_reg is not None: expected["txn"]["data"]["nodeReg"] = node_reg diff --git a/plenum/test/input_validation/test_client_taa_disable_op.py b/plenum/test/input_validation/test_client_taa_disable_op.py new file mode 100644 index 0000000000..75371e943d --- /dev/null +++ b/plenum/test/input_validation/test_client_taa_disable_op.py @@ -0,0 +1,21 @@ +from collections import OrderedDict + +from plenum.common.constants import TXN_AUTHOR_AGREEMENT_DISABLE +from plenum.common.messages.client_request import ClientTxnAuthorAgreementDisableOperation +from plenum.common.messages.fields import ConstantField + +TAA_DELAY_EXPECTED_ORDERED_FIELDS = OrderedDict([ + ("type", ConstantField), +]) + + +def check_schema(actual, expected): + assert list(actual.keys()) == list(expected.keys()) + for field, validator in expected.items(): + assert isinstance(actual[field], validator) + + +def test_taa_has_expected_schema(): + schema = OrderedDict(ClientTxnAuthorAgreementDisableOperation.schema) + check_schema(schema, TAA_DELAY_EXPECTED_ORDERED_FIELDS) + assert schema["type"].value == TXN_AUTHOR_AGREEMENT_DISABLE diff --git a/plenum/test/node/test_api.py b/plenum/test/node/test_api.py index 71f8804d92..c3cb888bc5 100644 --- a/plenum/test/node/test_api.py +++ b/plenum/test/node/test_api.py @@ -3,7 +3,7 @@ from common.exceptions import LogicError from plenum.common.constants import TXN_TYPE, TXN_PAYLOAD, TXN_PAYLOAD_METADATA, TXN_PAYLOAD_METADATA_DIGEST, \ TXN_PAYLOAD_TYPE, TXN_PAYLOAD_DATA, TXN_PAYLOAD_METADATA_REQ_ID, TXN_METADATA, TXN_METADATA_SEQ_NO, \ - TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST, CURRENT_TXN_VERSION, TXN_VERSION + TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST, CURRENT_TXN_VERSIONS, TXN_VERSION from plenum.common.request import Request from plenum.test.testing_utils import FakeSomething @@ -29,7 +29,7 @@ def test_seq_no_db_updates(test_node): TXN_METADATA: { TXN_METADATA_SEQ_NO: "1" }, - TXN_VERSION: CURRENT_TXN_VERSION + TXN_VERSION: CURRENT_TXN_VERSIONS["2"] } test_node.postTxnFromCatchupAddedToLedger(2, test_txn, False) @@ -51,7 +51,7 @@ def test_seq_no_db_updates_by_default(test_node): TXN_METADATA: { TXN_METADATA_SEQ_NO: "1" }, - TXN_VERSION: CURRENT_TXN_VERSION + TXN_VERSION: CURRENT_TXN_VERSIONS["2"] } test_node.postTxnFromCatchupAddedToLedger(2, test_txn) diff --git a/plenum/test/req_handler/test_request_manager.py b/plenum/test/req_handler/test_request_manager.py index 4405f3de81..6dc558d99e 100644 --- a/plenum/test/req_handler/test_request_manager.py +++ b/plenum/test/req_handler/test_request_manager.py @@ -12,7 +12,7 @@ from plenum.common.request import Request from plenum.common.util import randomString from plenum.common.constants import TARGET_NYM, NODE, DOMAIN_LEDGER_ID, TXN_PAYLOAD, TXN_PAYLOAD_TYPE, \ - TXN_METADATA_TIME, TXN_METADATA, TXN_TYPE, CURRENT_TXN_VERSION, TXN_VERSION + TXN_METADATA_TIME, TXN_METADATA, TXN_TYPE, CURRENT_TXN_VERSIONS, TXN_VERSION from plenum.server.batch_handlers.domain_batch_handler import DomainBatchHandler from plenum.server.request_handlers.node_handler import NodeHandler @@ -227,7 +227,7 @@ def update_state(self, txn, prev_result, request, is_committed=False): version = "version1" txn = {TXN_PAYLOAD: {TXN_PAYLOAD_TYPE: txn_type}, TXN_METADATA: {TXN_METADATA_TIME: 0}, - TXN_VERSION: CURRENT_TXN_VERSION} + TXN_VERSION: CURRENT_TXN_VERSIONS["txn_type"]} write_req_manager.register_req_handler(handler_current) write_req_manager.register_req_handler_with_version(handler_prev_version, version) diff --git a/plenum/test/script/test_bootstrap_test_node.py b/plenum/test/script/test_bootstrap_test_node.py index 4413a235bb..941a0d0390 100644 --- a/plenum/test/script/test_bootstrap_test_node.py +++ b/plenum/test/script/test_bootstrap_test_node.py @@ -8,7 +8,7 @@ from plenum.bls.bls_key_manager_file import BlsKeyManagerFile from plenum.common.constants import NYM, VERKEY, ROLE, TARGET_NYM, ALIAS, NODE, \ DATA, CLIENT_IP, CLIENT_PORT, NODE_IP, \ - NODE_PORT, SERVICES, BLS_KEY, VALIDATOR, TRUSTEE, STEWARD, BLS_KEY_PROOF, CURRENT_TXN_VERSION + NODE_PORT, SERVICES, BLS_KEY, VALIDATOR, TRUSTEE, STEWARD, BLS_KEY_PROOF, CURRENT_TXN_VERSIONS from plenum.common.test_network_setup import TestNetworkSetup from plenum.common.txn_util import getTxnOrderedFields, get_seq_no, get_txn_id, get_payload_data, get_type, get_version, \ get_protocol_version @@ -107,7 +107,7 @@ def test_domain_genesis_txns(bootstrap, domain_genesis_file): assert get_seq_no(txn) assert get_payload_data(txn) assert get_type(txn) == NYM - assert get_version(txn) == CURRENT_TXN_VERSION + assert get_version(txn) == CURRENT_TXN_VERSIONS[NYM] assert get_protocol_version(txn) is None assert get_payload_data(txn)[VERKEY] assert get_payload_data(txn)[TARGET_NYM] @@ -133,7 +133,7 @@ def test_pool_genesis_txns(bootstrap, pool_genesis_file): assert get_txn_id(txn) assert get_payload_data(txn) assert get_type(txn) == NODE - assert get_version(txn) == CURRENT_TXN_VERSION + assert get_version(txn) == CURRENT_TXN_VERSIONS[NODE] assert get_protocol_version(txn) is None assert get_payload_data(txn)[TARGET_NYM] data = get_payload_data(txn).get(DATA) diff --git a/plenum/test/transactions/test_txn_init_utils.py b/plenum/test/transactions/test_txn_init_utils.py index 94bdc9f0ae..5a95aa7fb1 100644 --- a/plenum/test/transactions/test_txn_init_utils.py +++ b/plenum/test/transactions/test_txn_init_utils.py @@ -1,4 +1,4 @@ -from plenum.common.constants import NYM, NODE, CURRENT_PROTOCOL_VERSION, CURRENT_TXN_VERSION +from plenum.common.constants import NYM, NODE, CURRENT_PROTOCOL_VERSION, CURRENT_TXN_VERSIONS from plenum.common.txn_util import init_empty_txn, set_payload_data, append_payload_metadata, append_txn_metadata from plenum.common.util import SortedDict @@ -16,7 +16,7 @@ def test_init_empty_txn_no_protocol_ver(): }, "txnMetadata": { }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS[NYM] } assert SortedDict(expected) == SortedDict(txn) @@ -34,7 +34,7 @@ def test_init_empty_txn_with_protocol_ver(): }, "txnMetadata": { }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS[NODE] } assert SortedDict(expected) == SortedDict(txn) @@ -53,7 +53,7 @@ def test_set_payload_metadata(): }, "txnMetadata": { }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS[NODE] }) assert SortedDict(expected) == SortedDict(txn) @@ -82,7 +82,7 @@ def test_append_payload_metadata(): }, "txnMetadata": { }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS[NODE] }) assert SortedDict(expected) == SortedDict(txn) @@ -108,6 +108,6 @@ def test_append_txn_metadata(): "txnId": "dddd", "txnTime": 12345678, }, - "ver": CURRENT_TXN_VERSION + "ver": CURRENT_TXN_VERSIONS[NODE] }) assert SortedDict(expected) == SortedDict(txn) diff --git a/plenum/test/txn_author_agreement/helper.py b/plenum/test/txn_author_agreement/helper.py index 3dcb8de79c..10eb1a1153 100644 --- a/plenum/test/txn_author_agreement/helper.py +++ b/plenum/test/txn_author_agreement/helper.py @@ -15,7 +15,7 @@ OP_FIELD_NAME, DATA, TXN_TIME, REPLY, \ TXN_METADATA, TXN_METADATA_SEQ_NO, TXN_METADATA_TIME, GET_TXN_AUTHOR_AGREEMENT_AML_VERSION, \ GET_TXN_AUTHOR_AGREEMENT_AML_TIMESTAMP, TXN_AUTHOR_AGREEMENT_AML, TXN_AUTHOR_AGREEMENT_RETIRED, TXN_TYPE, \ - TXN_AUTHOR_AGREEMENT, TXN_AUTHOR_AGREEMENT_DIGEST, TXN_AUTHOR_AGREEMENT_TIMESTAMP + TXN_AUTHOR_AGREEMENT, TXN_AUTHOR_AGREEMENT_DIGEST, TXN_AUTHOR_AGREEMENT_TIMESTAMP, TXN_AUTHOR_AGREEMENT_DISABLE from plenum.common.types import f from plenum.common.util import randomString from plenum.server.request_handlers.static_taa_helper import StaticTAAHelper @@ -54,6 +54,12 @@ def sdk_send_txn_author_agreement(looper, sdk_pool_handle, sdk_wallet, text: str return sdk_get_and_check_replies(looper, [req])[0] +def sdk_send_txn_author_agreement_disable(looper, sdk_pool_handle, sdk_wallet): + operation = {TXN_TYPE: TXN_AUTHOR_AGREEMENT_DISABLE} + req = sdk_sign_and_submit_op(looper, sdk_pool_handle, sdk_wallet, operation) + return sdk_get_and_check_replies(looper, [req])[0] + + def set_txn_author_agreement( looper, sdk_pool_handle, sdk_wallet, text: str, version: str ) -> TaaData: diff --git a/plenum/test/txn_author_agreement/test_txn_author_agreement.py b/plenum/test/txn_author_agreement/test_txn_author_agreement.py index 1778548b99..e76d1e4b29 100644 --- a/plenum/test/txn_author_agreement/test_txn_author_agreement.py +++ b/plenum/test/txn_author_agreement/test_txn_author_agreement.py @@ -10,8 +10,8 @@ from plenum.test.pool_transactions.helper import sdk_sign_and_send_prepared_request from .helper import ( sdk_send_txn_author_agreement, - gen_random_txn_author_agreement -) + gen_random_txn_author_agreement, + sdk_send_txn_author_agreement_disable) def test_send_valid_txn_author_agreement_before_aml_fails(set_txn_author_agreement): diff --git a/plenum/test/txn_author_agreement/test_txn_author_agreement_disable.py b/plenum/test/txn_author_agreement/test_txn_author_agreement_disable.py new file mode 100644 index 0000000000..922245621d --- /dev/null +++ b/plenum/test/txn_author_agreement/test_txn_author_agreement_disable.py @@ -0,0 +1,37 @@ +import pytest +import json + +from indy.ledger import build_txn_author_agreement_request + +from plenum.common.exceptions import RequestNackedException, RequestRejectedException +from plenum.common.types import OPERATION, f + +from plenum.test.helper import sdk_get_and_check_replies +from plenum.test.pool_transactions.helper import sdk_sign_and_send_prepared_request +from .helper import ( + sdk_send_txn_author_agreement, + gen_random_txn_author_agreement, + sdk_send_txn_author_agreement_disable) + + +def test_send_valid_txn_author_agreement_succeeds_and_disable( + set_txn_author_agreement_aml, set_txn_author_agreement, get_txn_author_agreement, + looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_trustee +): + set_txn_author_agreement() + sdk_send_txn_author_agreement_disable(looper, sdk_pool_handle, sdk_wallet_trustee) + assert get_txn_author_agreement() is None + + +def test_send_txn_author_agreement_disable_twice( + set_txn_author_agreement_aml, set_txn_author_agreement, get_txn_author_agreement, + looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_trustee +): + set_txn_author_agreement() + sdk_send_txn_author_agreement_disable(looper, sdk_pool_handle, sdk_wallet_trustee) + with pytest.raises( + RequestRejectedException, + match='Transaction author agreement is already disabled' + ): + sdk_send_txn_author_agreement_disable(looper, sdk_pool_handle, sdk_wallet_trustee) + assert get_txn_author_agreement() is None