Skip to content

Commit

Permalink
INDY-2302: Add a new txn TXN_AUTHOR_AGREEMENT_DISABLE
Browse files Browse the repository at this point in the history
Signed-off-by: toktar <renata.toktar@dsr-corporation.com>
  • Loading branch information
Toktar committed Dec 15, 2019
1 parent fdc3d8f commit 01e8f50
Show file tree
Hide file tree
Showing 19 changed files with 235 additions and 58 deletions.
6 changes: 5 additions & 1 deletion plenum/common/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# inter-node communication
from collections import defaultdict
from enum import IntEnum, unique

from plenum.common.plenum_protocol_version import PlenumProtocolVersion
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
10 changes: 9 additions & 1 deletion plenum/common/messages/client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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)),
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions plenum/common/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
4 changes: 2 additions & 2 deletions plenum/common/txn_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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] = {}
Expand Down
4 changes: 2 additions & 2 deletions plenum/server/batch_handlers/audit_batch_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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: {},
Expand Down
3 changes: 3 additions & 0 deletions plenum/server/ledgers_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
49 changes: 49 additions & 0 deletions plenum/server/request_handlers/base_taa_handler.py
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 5 additions & 0 deletions plenum/server/request_handlers/static_taa_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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". \
Expand Down
Original file line number Diff line number Diff line change
@@ -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())
60 changes: 28 additions & 32 deletions plenum/server/request_handlers/txn_author_agreement_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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.")
6 changes: 3 additions & 3 deletions plenum/test/audit_ledger/helper.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
21 changes: 21 additions & 0 deletions plenum/test/input_validation/test_client_taa_disable_op.py
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 01e8f50

Please sign in to comment.