diff --git a/plenum/common/constants.py b/plenum/common/constants.py index 7593d0f4b1..3580c95768 100644 --- a/plenum/common/constants.py +++ b/plenum/common/constants.py @@ -164,6 +164,7 @@ TXN_PAYLOAD_DATA = "data" TXN_PAYLOAD_METADATA = "metadata" TXN_PAYLOAD_METADATA_FROM = "from" +TXN_PAYLOAD_METADATA_ENDORSER = "endorser" TXN_PAYLOAD_METADATA_REQ_ID = "reqId" TXN_PAYLOAD_METADATA_DIGEST = "digest" TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST = "payloadDigest" diff --git a/plenum/common/request.py b/plenum/common/request.py index 417e8814e5..04d6384cd8 100644 --- a/plenum/common/request.py +++ b/plenum/common/request.py @@ -21,6 +21,7 @@ def __init__(self, signatures: Dict[str, str] = None, protocolVersion: int = None, taaAcceptance: Dict = None, + endorser: Identifier = None, # Intentionally omitting *args **kwargs): self._identifier = identifier @@ -30,6 +31,7 @@ def __init__(self, self.operation = operation self.protocolVersion = protocolVersion self.taaAcceptance = taaAcceptance + self.endorser = endorser self._digest = None self._payload_digest = None for nm in PLUGIN_CLIENT_REQUEST_FIELDS: @@ -67,6 +69,8 @@ def as_dict(self): rv[f.PROTOCOL_VERSION.nm] = self.protocolVersion if self.taaAcceptance is not None: rv[f.TAA_ACCEPTANCE.nm] = self.taaAcceptance + if self.endorser is not None: + rv[f.ENDORSER.nm] = self.endorser return rv def __eq__(self, other): @@ -112,6 +116,8 @@ def signingPayloadState(self, identifier=None): dct[f.PROTOCOL_VERSION.nm] = self.protocolVersion if self.taaAcceptance is not None: dct[f.TAA_ACCEPTANCE.nm] = self.taaAcceptance + if self.endorser is not None: + dct[f.ENDORSER.nm] = self.endorser return dct def __setstate__(self, state): diff --git a/plenum/common/txn_util.py b/plenum/common/txn_util.py index cf2829a7cc..61c30e6d14 100644 --- a/plenum/common/txn_util.py +++ b/plenum/common/txn_util.py @@ -8,7 +8,7 @@ TXN_SIGNATURE_FROM, TXN_SIGNATURE_VALUE, TXN_SIGNATURE_VALUES, TXN_PAYLOAD_DATA, TXN_PAYLOAD_METADATA_REQ_ID, \ 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_PAYLOAD_DIGEST, TXN_PAYLOAD_METADATA_TAA_ACCEPTANCE, TXN_PAYLOAD_METADATA_ENDORSER from plenum.common.request import Request from plenum.common.types import f, OPERATION from stp_core.common.log import getlogger @@ -200,7 +200,7 @@ def set_payload_data(txn, data): def append_payload_metadata( - txn, frm=None, req_id=None, digest=None, payload_digest=None, taa_acceptance=None): + txn, frm=None, req_id=None, digest=None, payload_digest=None, taa_acceptance=None, endorser=None): if frm is not None: txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA][TXN_PAYLOAD_METADATA_FROM] = frm if req_id is not None: @@ -211,6 +211,8 @@ def append_payload_metadata( txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA][TXN_PAYLOAD_METADATA_DIGEST] = digest if payload_digest is not None: txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA][TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST] = payload_digest + if endorser is not None: + txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA][TXN_PAYLOAD_METADATA_ENDORSER] = endorser return txn @@ -241,7 +243,8 @@ def reqToTxn(req): signature=req.get(f.SIG.nm, None), signatures=req.get(f.SIGS.nm, None), protocolVersion=req.get(f.PROTOCOL_VERSION.nm, None), - taaAcceptance=req.get(f.TAA_ACCEPTANCE.nm, None) + taaAcceptance=req.get(f.TAA_ACCEPTANCE.nm, None), + endorser=req.get(f.ENDORSER.nm, None) ) req = TxnUtilConfig.client_request_class(**kwargs) if isinstance(req, Request): @@ -291,7 +294,8 @@ def do_req_to_txn(req_data, req_op): req_id=req_data.pop(f.REQ_ID.nm, None), digest=req_data.pop(f.DIGEST.nm, None), payload_digest=req_data.pop(f.PAYLOAD_DIGEST.nm, None), - taa_acceptance=req_data.pop(f.TAA_ACCEPTANCE.nm, None)) + taa_acceptance=req_data.pop(f.TAA_ACCEPTANCE.nm, None), + endorser=req_data.pop(f.ENDORSER.nm, None)) # 4. Fill Payload data set_payload_data(result, req_op) diff --git a/plenum/test/helper.py b/plenum/test/helper.py index b400b9e231..4105149c8d 100644 --- a/plenum/test/helper.py +++ b/plenum/test/helper.py @@ -829,6 +829,16 @@ def sdk_multisign_request_object(looper, sdk_wallet, req): wh, did = sdk_wallet return looper.loop.run_until_complete(multi_sign_request(wh, did, req)) +def sdk_multisign_request_from_dict(looper, sdk_wallet, op, reqId=None, taa_acceptance=None, endorser=None): + wh, did = sdk_wallet + reqId = reqId or random.randint(10, 100000) + request = Request(operation=op, reqId=reqId, + protocolVersion=CURRENT_PROTOCOL_VERSION, identifier=did, + taaAcceptance=taa_acceptance, + endorser=endorser) + req_str = json.dumps(request.as_dict) + resp = looper.loop.run_until_complete(multi_sign_request(wh, did, req_str)) + return json.loads(resp) def sdk_signed_random_requests(looper, sdk_wallet, count): _, did = sdk_wallet @@ -1062,12 +1072,13 @@ def sdk_send_batches_of_random(looper, txnPoolNodeSet, sdk_pool, sdk_wallet, return sdk_reqs -def sdk_sign_request_from_dict(looper, sdk_wallet, op, reqId=None, taa_acceptance=None): +def sdk_sign_request_from_dict(looper, sdk_wallet, op, reqId=None, taa_acceptance=None, endorser=None): wallet_h, did = sdk_wallet reqId = reqId or random.randint(10, 100000) request = Request(operation=op, reqId=reqId, protocolVersion=CURRENT_PROTOCOL_VERSION, identifier=did, - taaAcceptance=taa_acceptance) + taaAcceptance=taa_acceptance, + endorser=endorser) req_str = json.dumps(request.as_dict) resp = looper.loop.run_until_complete(sign_request(wallet_h, did, req_str)) return json.loads(resp) diff --git a/plenum/test/node_catchup/test_catchup_with_old_txn_metadata_digest_format.py b/plenum/test/node_catchup/test_catchup_with_old_txn_metadata_digest_format.py index 88bfe0ec44..da44f5fb84 100644 --- a/plenum/test/node_catchup/test_catchup_with_old_txn_metadata_digest_format.py +++ b/plenum/test/node_catchup/test_catchup_with_old_txn_metadata_digest_format.py @@ -33,12 +33,14 @@ def check_nodes_domain_ledger(nodes: Iterable, txn_count: int): # Patch payload metadata, note that it will prevent pool from sending adequate replies to clients def append_old_payload_metadata( txn, frm=None, req_id=None, - digest=None, payload_digest=None, taa_acceptance=None): - txn = append_payload_metadata(txn, frm, req_id, digest, payload_digest, taa_acceptance) + digest=None, payload_digest=None, taa_acceptance=None, + endorser=None): + txn = append_payload_metadata(txn, frm, req_id, digest, payload_digest, taa_acceptance, endorser) metadata = txn[TXN_PAYLOAD][TXN_PAYLOAD_METADATA] del metadata[TXN_PAYLOAD_METADATA_PAYLOAD_DIGEST] metadata[TXN_PAYLOAD_METADATA_DIGEST] = payload_digest return txn + monkeypatch.setattr(txn_util, 'append_payload_metadata', append_old_payload_metadata) # Check pool initial state diff --git a/plenum/test/test_request.py b/plenum/test/test_request.py index f5d410bded..c401ba0d61 100644 --- a/plenum/test/test_request.py +++ b/plenum/test/test_request.py @@ -1,7 +1,107 @@ +import pytest + +from plenum.common.constants import CURRENT_PROTOCOL_VERSION from plenum.common.request import Request +from plenum.common.types import OPERATION, f +from plenum.test.helper import sdk_sign_request_from_dict, sdk_multisign_request_from_dict + + +@pytest.fixture(params=['with_endorser', 'no_endorser']) +def endorser(request): + if request.param == 'with_endorser': + return '5gC6mJq5MoGPwubtU8F5Qc' + return None + + +@pytest.fixture(params=['all', 'sig_only', 'sigs_only', 'no_protocol_vers', + 'all_sdk', 'sig_only_sdk', 'sigs_only_sdk', 'no_protocol_vers_sdk', + 'endorser']) +def req(request, looper, sdk_wallet_client, endorser): + op = {'type': '1', + 'something': 'nothing'} + taaa = { + 'a': 'b', + 'c': 3 + } + if request.param.endswith('_sdk'): + request.param = request.param[:-4] + if request.param == 'sigs_only': + req = sdk_multisign_request_from_dict(looper, sdk_wallet_client, + op, reqId=1513945121191691, + taa_acceptance=taaa, + endorser=endorser) + else: + req = sdk_sign_request_from_dict(looper, sdk_wallet_client, + op, reqId=1513945121191691, + taa_acceptance=taaa, + endorser=endorser) + + if request.param == 'no_protocol_vers': # TODO INDY-2072 always false here + req.pop('protocolVersion') + req = Request( + req.get(f.IDENTIFIER.nm, None), + req.get(f.REQ_ID.nm, None), + req.get(OPERATION, None), + req.get(f.SIG.nm, None), + req.get(f.SIGS.nm, None), + req.get(f.PROTOCOL_VERSION.nm, None), + req.get(f.TAA_ACCEPTANCE.nm, None), + req.get(f.ENDORSER.nm, None) + ) + else: + req = Request(operation=op, reqId=1513945121191691, + protocolVersion=CURRENT_PROTOCOL_VERSION, identifier="6ouriXMZkLeHsuXrN1X1fd", + taaAcceptance=taaa, endorser=endorser) + sign = "2DaRm3nt6H5fJu2TP5vxqbaDCtABPYmUTSX4ocnY8fVGgyJMVNaeh2z6JZhcW1gbmGKJcZopZMKZJwADuXFFJobM" + req.signature = sign + req.add_signature("6ouriXMZkLeHsuXrN1X1fd", + sign) + if request.param == 'sig_only': + req.signatures = None + if request.param == 'sigs_only': + req.signature = None + if request.param == 'no_protocol_vers': + req.protocolVersion = None + + return req def test_request_all_identifiers_returns_empty_list_for_request_without_signatures(): req = Request() - assert req.all_identifiers == [] + + +def test_as_dict(req, endorser): + req_dct = req.as_dict + assert req_dct.get(f.REQ_ID.nm) == req.reqId + assert req_dct.get(OPERATION) == req.operation + assert req_dct.get(f.IDENTIFIER.nm) == req.identifier + assert req_dct.get(f.SIGS.nm) == req.signatures + assert req_dct.get(f.SIG.nm) == req.signature + assert req_dct.get(f.PROTOCOL_VERSION.nm) == req.protocolVersion + assert req_dct.get(f.TAA_ACCEPTANCE.nm) == req.taaAcceptance + assert req_dct.get(f.ENDORSER.nm) == req.endorser + + +def test_signing_payload_state(req, endorser): + signing_state = req.signingPayloadState() + assert signing_state.get(f.REQ_ID.nm) == req.reqId + assert signing_state.get(OPERATION) == req.operation + assert signing_state.get(f.IDENTIFIER.nm) == req.identifier + assert signing_state.get(f.PROTOCOL_VERSION.nm) == req.protocolVersion + assert signing_state.get(f.TAA_ACCEPTANCE.nm) == req.taaAcceptance + assert signing_state.get(f.ENDORSER.nm) == req.endorser + assert f.SIGS.nm not in signing_state + assert f.SIG.nm not in signing_state + + +def test_signing_state(req, endorser): + signing_state = req.signingState() + assert signing_state.get(f.REQ_ID.nm) == req.reqId + assert signing_state.get(OPERATION) == req.operation + assert signing_state.get(f.IDENTIFIER.nm) == req.identifier + assert signing_state.get(f.PROTOCOL_VERSION.nm) == req.protocolVersion + assert signing_state.get(f.TAA_ACCEPTANCE.nm) == req.taaAcceptance + assert signing_state.get(f.ENDORSER.nm) == req.endorser + assert signing_state.get(f.SIGS.nm) == req.signatures + assert signing_state.get(f.SIG.nm) == req.signature diff --git a/plenum/test/transactions/test_req_to_txn.py b/plenum/test/transactions/test_req_to_txn.py index b8d6b00205..d69cefa7cd 100644 --- a/plenum/test/transactions/test_req_to_txn.py +++ b/plenum/test/transactions/test_req_to_txn.py @@ -5,12 +5,19 @@ from plenum.common.txn_util import reqToTxn, append_txn_metadata from plenum.common.types import OPERATION, f from plenum.common.util import SortedDict -from plenum.test.helper import sdk_sign_request_from_dict +from plenum.test.helper import sdk_sign_request_from_dict, sdk_multisign_request_from_dict + + +@pytest.fixture(params=['with_endorser', 'no_endorser']) +def endorser(request): + if request.param == 'with_endorser': + return '5gC6mJq5MoGPwubtU8F5Qc' + return None @pytest.fixture(params=['all', 'sig_only', 'sigs_only', 'no_protocol_vers', 'all_sdk', 'sig_only_sdk', 'sigs_only_sdk', 'no_protocol_vers_sdk']) -def req_and_expected(request, looper, sdk_wallet_client): +def req_and_expected(request, looper, sdk_wallet_client, endorser): op = {'type': '1', 'something': 'nothing'} taaa = { @@ -18,15 +25,17 @@ def req_and_expected(request, looper, sdk_wallet_client): 'c': 3 } if request.param.endswith('_sdk'): - req = sdk_sign_request_from_dict(looper, sdk_wallet_client, - op, reqId=1513945121191691, - taa_acceptance=taaa) request.param = request.param[:-4] - # TODO: support multi-sig in SDK - # if request.param == 'sig_only': - # req.pop('signatures') - # if request.param == 'sigs_only': - # req.pop('signature') + if request.param == 'sigs_only': + req = sdk_multisign_request_from_dict(looper, sdk_wallet_client, + op, reqId=1513945121191691, + taa_acceptance=taaa, + endorser=endorser) + else: + req = sdk_sign_request_from_dict(looper, sdk_wallet_client, + op, reqId=1513945121191691, + taa_acceptance=taaa, + endorser=endorser) if request.param == 'no_protocol_vers': # TODO INDY-2072 always false here req.pop('protocolVersion') r = Request( @@ -36,15 +45,16 @@ def req_and_expected(request, looper, sdk_wallet_client): req.get(f.SIG.nm, None), req.get(f.SIGS.nm, None), req.get(f.PROTOCOL_VERSION.nm, None), - req.get(f.TAA_ACCEPTANCE.nm, None) + req.get(f.TAA_ACCEPTANCE.nm, None), + req.get(f.ENDORSER.nm, None) ) digest = r.digest payload_digest = r.payload_digest - sign = req.get(f.SIG.nm) + sign = req.get(f.SIG.nm) if request.param != 'sigs_only' else next(iter(req.get(f.SIGS.nm).values())) else: req = Request(operation=op, reqId=1513945121191691, protocolVersion=CURRENT_PROTOCOL_VERSION, identifier="6ouriXMZkLeHsuXrN1X1fd", - taaAcceptance=taaa) + taaAcceptance=taaa, endorser=endorser) sign = "2DaRm3nt6H5fJu2TP5vxqbaDCtABPYmUTSX4ocnY8fVGgyJMVNaeh2z6JZhcW1gbmGKJcZopZMKZJwADuXFFJobM" req.signature = sign req.add_signature("6ouriXMZkLeHsuXrN1X1fd", @@ -96,6 +106,8 @@ def req_and_expected(request, looper, sdk_wallet_client): new_expected["txn"]["metadata"]["digest"] = digest if payload_digest is not None: new_expected["txn"]["metadata"]["payloadDigest"] = payload_digest + if endorser is not None: + new_expected["txn"]["metadata"]["endorser"] = endorser return req, new_expected