def two_requests(looper, sdk_wallet_steward): wh, did = sdk_wallet_steward op = {TXN_TYPE: AUCTION_START, DATA: {'id': 'xyz'}} req1 = sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, identifier=did).as_dict field = list(PLUGIN_CLIENT_REQUEST_FIELDS.keys())[0] req1[field] = 'x' * 10 req2 = copy.deepcopy(req1) req2[field] = 'z' * 10 req1 = sdk_multisign_request_object(looper, sdk_wallet_steward, json.dumps(req1)) req_obj1 = Request(**json.loads(req1)) req2 = sdk_multisign_request_object(looper, sdk_wallet_steward, json.dumps(req2)) req_obj2 = Request(**json.loads(req2)) assert req_obj1.payload_digest == req_obj2.payload_digest assert req_obj1.digest != req_obj2.digest return req1, req2
def signRequest(self, req: Request, identifier: Identifier = None) -> Request: """ Signs request. Modifies reqId and signature. May modify identifier. :param req: request :param requestIdStore: request id generator :param identifier: signer identifier :return: signed request """ idr = self.requiredIdr(idr=identifier or req._identifier) # idData = self._getIdData(idr) req._identifier = idr req.reqId = req.gen_req_id() # req.digest = req.getDigest() # QUESTION: `self.ids[idr]` would be overwritten if same identifier # is used to send 2 requests, why is `IdData` persisted? # self.ids[idr] = IdData(idData.signer, req.reqId) req.signature = self.signMsg(msg=req.signingState(identifier=idr), identifier=idr, otherIdentifier=req.identifier) return req
def test_get_txn_response_as_expected(looper, steward1, stewardWallet): req, wallet = sendAddNewClient(STEWARD, "name", steward1, stewardWallet) timeout = waits.expectedTransactionExecutionTime(len( steward1.inBox)) + c_delay nym_response = \ looper.run(eventually(check_sufficient_replies_received, steward1, req.identifier, req.reqId, retryWait=1, timeout=timeout)) op = { TXN_TYPE: GET_TXN, f.LEDGER_ID.nm: DOMAIN_LEDGER_ID, DATA: nym_response['seqNo'] } req = Request(identifier=stewardWallet.defaultId, operation=op, reqId=Request.gen_req_id(), protocolVersion=CURRENT_PROTOCOL_VERSION) steward1.submitReqs(req) get_txn_response = \ looper.run(eventually(check_sufficient_replies_received, steward1, req.identifier, req.reqId, retryWait=1, timeout=timeout)) nym_response.pop('txnTime', None) get_txn_response[DATA].pop('txnTime', None) assert nym_response == get_txn_response[DATA]
def test_plugin_client_req_fields(txn_pool_node_set_post_creation, looper, stewardWallet, steward1, sdk_wallet_steward, sdk_pool_handle): """ Test that plugin's addition of request fields and their validation is successful """ op = {TXN_TYPE: GET_BAL, DATA: {'id': '123'}} # Valid field value results in successful processing req_obj = sdk_gen_request( op, identifier=sdk_wallet_steward[1], fix_length_dummy=randomString(dummy_field_length)) req = sdk_sign_and_submit_req_obj(looper, sdk_pool_handle, sdk_wallet_steward, req_obj) sdk_get_reply(looper, req) # Invalid field value results in proper failure req = Request(operation=op, reqId=Request.gen_req_id(), protocolVersion=CURRENT_PROTOCOL_VERSION, identifier=stewardWallet.defaultId, fix_length_dummy=randomString(dummy_field_length + 1)) steward1.submitReqs(req) for node in txn_pool_node_set_post_creation: looper.run( eventually(checkReqNackWithReason, steward1, 'should have length', node.clientstack.name, retryWait=1))
def signRequest(self, req: Request, identifier: Identifier=None) -> Request: """ Signs request. Modifies reqId and signature. May modify identifier. :param req: request :param requestIdStore: request id generator :param identifier: signer identifier :return: signed request """ idr = self.requiredIdr(idr=identifier or req._identifier) # idData = self._getIdData(idr) req._identifier = idr req.reqId = req.gen_req_id() # req.digest = req.getDigest() # QUESTION: `self.ids[idr]` would be overwritten if same identifier # is used to send 2 requests, why is `IdData` persisted? # self.ids[idr] = IdData(idData.signer, req.reqId) req.signature = self.signMsg(msg=req.signingState(identifier=idr), identifier=idr, otherIdentifier=req.identifier) return req
def sign_using_output(self, id, seq_no, op: Dict = None, request: Request = None): assert lxor(op, request) if op: request = Request(reqId=Request.gen_req_id(), operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION) # existing_inputs = request.operation.get(INPUTS, []) # request.operation[INPUTS] = [[id, seq_no], ] # payload = deepcopy(request.signingState(id)) # # TEMPORARY # payload[OPERATION].pop(SIGS) # payload.pop(f.IDENTIFIER.nm) # # signature = self.addresses[id].signer.sign(payload) # request.operation[INPUTS] = existing_inputs + [[id, seq_no], ] # TODO: Account for `extra` field payload = [[ { "address": id, "seqNo": seq_no }, ], request.operation[OUTPUTS]] signature = self.addresses[id].signer.sign(payload) request.operation[INPUTS] = request.operation.get(INPUTS, []) + [ { "address": id, "seqNo": seq_no }, ] request.operation[SIGS].append(signature) return request
def _create_request(self, payload, identifier=None): return Request( reqId=Request.gen_req_id(), operation=payload, protocolVersion=CURRENT_PROTOCOL_VERSION, identifier=identifier )
def test_static_validation(get_txn_author_agreement_aml_handler): request = Request(operation={TXN_TYPE: GET_TXN_AUTHOR_AGREEMENT_AML, GET_TXN_AUTHOR_AGREEMENT_AML_VERSION: "VERSION"}) get_txn_author_agreement_aml_handler.static_validation(request) request = Request(operation={TXN_TYPE: GET_TXN_AUTHOR_AGREEMENT_AML, GET_TXN_AUTHOR_AGREEMENT_AML_TIMESTAMP: 1559299045}) get_txn_author_agreement_aml_handler.static_validation(request)
def evilCreatePropagate(self, request: Request, identifier: str) -> Propagate: logger.debug("EVIL: Creating propagate request for client request {}". format(request)) request.operation["amount"] += random.random() request._digest = request.getDigest() if isinstance(identifier, bytes): identifier = identifier.decode() return Propagate(request.as_dict, identifier)
def evilCreatePropagate(self, request: Request, identifier: str) -> Propagate: logger.debug("EVIL: Creating propagate request for client request {}". format(request)) request.operation["amount"] = random.randint(10, 100000) request._digest = request.digest if isinstance(identifier, bytes): identifier = identifier.decode() return Propagate(request.as_dict, identifier)
def sign_using_multi_sig(self, op: Dict=None, request: Request=None, identifier=None) -> Request: # One and only 1 of `op` and `request` must be provided. # If `request` is provided it must have `reqId` assert lxor(op, request) identifier = identifier or self.defaultId if op: request = Request(reqId=Request.gen_req_id(), operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION) self.do_multi_sig_on_req(request, identifier) return request
def test_get_txn_for_invalid_ledger_id(looper, txnPoolNodeSet, steward1, stewardWallet): op = {TXN_TYPE: GET_TXN, f.LEDGER_ID.nm: 5908, DATA: 1} req = Request(identifier=stewardWallet.defaultId, operation=op, reqId=Request.gen_req_id(), protocolVersion=CURRENT_PROTOCOL_VERSION) steward1.submitReqs(req) for node in txnPoolNodeSet: waitReqNackWithReason(looper, steward1, 'expected one of', node.clientstack.name)
def test_get_txn_for_invalid_seq_no(looper, txnPoolNodeSet, steward1, stewardWallet): op = {TXN_TYPE: GET_TXN, f.LEDGER_ID.nm: DOMAIN_LEDGER_ID, DATA: -23} req = Request(identifier=stewardWallet.defaultId, operation=op, reqId=Request.gen_req_id(), protocolVersion=CURRENT_PROTOCOL_VERSION) steward1.submitReqs(req) for node in txnPoolNodeSet: waitReqNackWithReason(looper, steward1, 'cannot be smaller', node.clientstack.name)
def requests(): def _getDigest(req: Request): return sha256(req.identifier.encode()) requests = Requests() req = Request("1") req.getDigest = functools.partial(_getDigest, req) requests.add(req) assert len(requests) == 1 return requests, req.key
def requests(): def _getDigest(req: Request): return sha256(req.identifier.encode()) requests = Requests() for id in req_identifiers: req = Request(id) req.getDigest = functools.partial(_getDigest, req) requests.add(req) assert len(requests) == 3 return requests
def two_requests(looper, op, sdk_wallet_stewards): wh, did = sdk_wallet_stewards[0] req = json.dumps(sdk_gen_request(op, protocol_version=CURRENT_PROTOCOL_VERSION, identifier=did).as_dict) req1 = sdk_multisign_request_object(looper, sdk_wallet_stewards[0], req) req_obj1 = Request(**json.loads(req1)) req2 = sdk_multisign_request_object(looper, sdk_wallet_stewards[1], req1) req_obj2 = Request(**json.loads(req2)) assert req_obj1.payload_digest == req_obj2.payload_digest assert req_obj1.digest != req_obj2.digest return req1, req2
def reqToTxn(req): """ Transform a client request such that it can be stored in the ledger. Also this is what will be returned to the client in the reply :param req: :return: """ if isinstance(req, str): req = json.loads(req) if isinstance(req, dict): req = Request(identifier=req.get(f.IDENTIFIER.nm, None), reqId=req.get(f.REQ_ID.nm, None), operation=req.get(OPERATION, None), signature=req.get(f.SIG.nm, None), signatures=req.get(f.SIGS.nm, None), protocolVersion=req.get(f.PROTOCOL_VERSION.nm, None)) if isinstance(req, Request): req_data = req.as_dict req_data[f.DIGEST.nm] = req.digest else: raise TypeError("Expected dict or str as input, but got: {}".format( type(req))) req_data = deepcopy(req_data) return do_req_to_txn(req_data=req_data, req_op=req_data[OPERATION])
def revoc_reg_entry_request(): return Request(identifier=randomString(), reqId=5, operation={ 'type': REVOC_REG_ENTRY, REVOC_REG_DEF_ID: 'sample' })
def testSendGetTxnReqSameAsExpected(looper, steward1, stewardWallet): req, wallet = sendAddNewClient(STEWARD, "name", steward1, stewardWallet) timeout = waits.expectedTransactionExecutionTime(len( steward1.inBox)) + c_delay nym_response = looper.run( eventually(checkSufficientRepliesReceived, steward1.inBox, req.reqId, fValue, retryWait=1, timeout=timeout)) op = {TXN_TYPE: GET_TXN, DATA: nym_response['seqNo']} req = Request(identifier=stewardWallet.defaultId, operation=op, reqId=getTimeBasedId()) steward1.submitReqs(req) get_txn_response = looper.run( eventually(checkSufficientRepliesReceived, steward1.inBox, req.reqId, fValue, retryWait=1, timeout=timeout)) get_txn_response = json.loads(get_txn_response[DATA]) del nym_response['txnTime'] del get_txn_response['txnTime'] assert nym_response == get_txn_response
def isFinalised(self, f): if self.finalised is None: req = checkIfMoreThanFSameItems([v.__getstate__() for v in self.propagates.values()], f) if req: self.finalised = Request.fromState(req) return self.finalised
def node(): n = FakeSomething() n.new_future_primaries_needed = False n.requests = { 'a': ReqState( Request( operation={ TARGET_NYM: 'nym7', TXN_TYPE: NODE, DATA: { SERVICES: ['VALIDATOR'], ALIAS: 'n7' } })) } n.nodeReg = {'n1': 1, 'n2': 1, 'n3': 1, 'n4': 1, 'n5': 1, 'n6': 1} n.primaries = ['n1', 'n2'] n.nodeIds = n.nodeReg n.primaries_selector = FakeSomething() n.primaries_selector.select_primaries = lambda view_no, instance_count, validators: [ 'n1', 'n2' ] n.viewNo = 0 return n
def get_auth_rule_request(creator): return Request(identifier=creator, reqId=5, operation={ TXN_TYPE: GET_AUTH_RULE, **generate_key() })
def taa_disable_request(tconf, domain_state): identifier = "identifier" update_nym(domain_state, identifier, TRUSTEE) operation = {TXN_TYPE: TXN_AUTHOR_AGREEMENT_DISABLE} return Request(identifier=identifier, signature="sign", operation=operation)
def test_suspicious_primary_send_same_request_with_same_signatures( looper, txnPoolNodeSet, sdk_pool_handle, two_requests, sdk_wallet_stewards, tconf): couple = sdk_send_random_and_check(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards[0], 1)[0] req = Request(**couple[0]) replica = getPrimaryReplica(txnPoolNodeSet) replica._ordering_service._do_dynamic_validation = types.MethodType( malicious_dynamic_validation, replica.node) txnPoolNodeSet.remove(replica.node) old_reverts = {} for i, node in enumerate(txnPoolNodeSet): old_reverts[i] = node.master_replica._ordering_service.spylog.count( OrderingService._revert) node.seqNoDB._keyValueStorage.remove(req.digest) node.seqNoDB._keyValueStorage.remove(req.payload_digest) ppReq = replica._ordering_service.create_3pc_batch(DOMAIN_LEDGER_ID) ppReq._fields['reqIdr'] = [req.digest, req.digest] replica._ordering_service.send_pre_prepare(ppReq) def reverts(): for i, node in enumerate(txnPoolNodeSet): assert old_reverts[ i] + 1 == node.master_replica._ordering_service.spylog.count( OrderingService._revert) looper.run(eventually(reverts))
def test_static_validation_fail_context_is_list_with_dict_and_bad_uri(): context = [{ "favoriteColor": "https://example.com/vocab#favoriteColor" }, "this is a bad uri"] operation = { META: { "name": "TestContext", "version": 1, "type": CONTEXT_TYPE }, DATA: { CONTEXT_CONTEXT: context }, RS_TYPE: "200" } req = Request( "test", 1, operation, "sig", ) ch = ContextHandler(None, None) with pytest.raises(InvalidClientRequest) as e: ch.static_validation(req) assert "@context URI this is a bad uri badly formed" in str(e.value)
def sdk_gen_request(operation, protocol_version=CURRENT_PROTOCOL_VERSION, identifier=None): return Request(operation=operation, reqId=random.randint(10, 100000), protocolVersion=protocol_version, identifier=identifier)
def test_future_primaries_replicas_increase(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards, tdir, tconf, allPluginsPath): # Don't delete NodeStates, so we could check them. global old_commit old_commit = txnPoolNodeSet[0].write_manager.future_primary_handler.commit_batch for node in txnPoolNodeSet: node.write_manager.future_primary_handler.commit_batch = lambda three_pc_batch, prev_handler_result=None: 0 initial_primaries = copy.copy(txnPoolNodeSet[0].primaries) last_ordered = txnPoolNodeSet[0].master_replica.last_ordered_3pc starting_view_number = checkViewNoForNodes(txnPoolNodeSet) # Increase replicas count add_new_node(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards[0], tdir, tconf, allPluginsPath) new_view_no = checkViewNoForNodes(txnPoolNodeSet) assert new_view_no == starting_view_number + 1 # "seq_no + 2" because 1 domain and 1 pool txn. node = txnPoolNodeSet[0] with delay_rules(node.nodeIbStasher, cDelay()): req = sdk_send_random_and_check(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards[0], 1)[0][0] req = Request(**req) three_pc_batch = ThreePcBatch(DOMAIN_LEDGER_ID, 0, 0, 1, time.time(), randomString(), randomString(), ['a', 'b', 'c'], [req.digest], pp_digest='') primaries = node.write_manager.future_primary_handler.post_batch_applied(three_pc_batch) assert len(primaries) == len(initial_primaries) + 1 assert len(primaries) == len(node.primaries)
def _req_to_txn(self, req: Request): sigs = req.operation.pop(SIGS) txn = super()._req_to_txn(req) req.operation[SIGS] = sigs sigs = [(i["address"], s) for i, s in zip(req.operation[INPUTS], sigs)] add_sigs_to_txn(txn, sigs, sig_type=ED25519) return txn
def auth_rules_request(creator): return Request(identifier=creator, reqId=5, operation={ TXN_TYPE: AUTH_RULES, RULES: [generate_auth_rule()] })
def node(): n = FakeSomething() n.new_future_primaries_needed = False n.requests = { 'a': ReqState( Request( operation={ TARGET_NYM: 'nym7', TXN_TYPE: NODE, DATA: { SERVICES: ['VALIDATOR'], ALIAS: 'n7' } })) } n.nodeReg = {'n1': 1, 'n2': 1, 'n3': 1, 'n4': 1, 'n5': 1, 'n6': 1} n.nodeIds = { 'nym1': 'n1', 'nym2': 'n2', 'nym3': 'n3', 'nym4': 'n4', 'nym5': 'n5', 'nym6': 'n6' } n.primaries = {'n1', 'n2'} n.elector = FakeSomething() n.elector.process_selection = lambda a, b, c: ['n1', 'n2'] return n
def test_static_validation_pass_context_w3c_example_15(): context = { "@context": { "referenceNumber": "https://example.com/vocab#referenceNumber", "favoriteFood": "https://example.com/vocab#favoriteFood" } } operation = { META: { "name": "TestContext", "version": 1, "type": CONTEXT_TYPE }, DATA: { CONTEXT_CONTEXT: context }, RS_TYPE: "200" } req = Request( "test", 1, operation, "sig", ) ch = ContextHandler(None, None) ch.static_validation(req)
def test_future_primaries_replicas_decrease(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards, tdir, tconf, allPluginsPath): assert len(txnPoolNodeSet) == 7 initial_primaries = copy.copy(txnPoolNodeSet[0].primaries) last_ordered = txnPoolNodeSet[0].master_replica.last_ordered_3pc starting_view_number = checkViewNoForNodes(txnPoolNodeSet) # Decrease replicas count demote_node(looper, sdk_wallet_stewards[-1], sdk_pool_handle, txnPoolNodeSet[-2]) txnPoolNodeSet.remove(txnPoolNodeSet[-2]) ensureElectionsDone(looper=looper, nodes=txnPoolNodeSet) new_view_no = checkViewNoForNodes(txnPoolNodeSet) assert new_view_no == starting_view_number + 1 node = txnPoolNodeSet[0] with delay_rules(node.nodeIbStasher, cDelay()): req = sdk_send_random_and_check(looper, txnPoolNodeSet, sdk_pool_handle, sdk_wallet_stewards[0], 1)[0][0] req = Request(**req) three_pc_batch = ThreePcBatch(DOMAIN_LEDGER_ID, 0, 0, 1, time.time(), randomString(), randomString(), ['a', 'b', 'c'], [req.digest], pp_digest='') primaries = node.write_manager.future_primary_handler.post_batch_applied(three_pc_batch) assert len(primaries) + 1 == len(initial_primaries) assert len(primaries) == len(txnPoolNodeSet[0].primaries) for node in txnPoolNodeSet: node.write_manager.future_primary_handler.commit_batch = old_commit
def get_reply_identifier(result): if f.IDENTIFIER.nm in result: return result[f.IDENTIFIER.nm] elif TXN_PAYLOAD in result and TXN_PAYLOAD_METADATA in result[TXN_PAYLOAD] and \ TXN_PAYLOAD_METADATA_FROM in result[TXN_PAYLOAD][TXN_PAYLOAD_METADATA]: return result[TXN_PAYLOAD][TXN_PAYLOAD_METADATA][TXN_PAYLOAD_METADATA_FROM] else: return Request.gen_idr_from_sigs(result.get(f.SIGS.nm, {}))
def set_finalised(self, req): # TODO: make it much explicitly and simpler # !side affect! if `req` is an instance of a child of `Request` class # here we construct the parent from child it is rather implicit that # `finalised` contains not the same type than `propagates` has self.finalised = Request.fromState(req.__getstate__()) self.added_ts = None self.finalised_ts = time.perf_counter()
def deserializeReq(serReq: str) -> Request: return Request.fromState(json.loads(serReq))
def req_and_expected(request, looper, sdk_wallet_client): op = {'type': '1', 'something': 'nothing'} if request.param.endswith('_sdk'): req = sdk_sign_request_from_dict(looper, sdk_wallet_client, op, reqId=1513945121191691) 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 == 'no_protocol_vers': req.pop('protocolVersion') digest = 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) ).digest sign = req.get(f.SIG.nm) else: req = Request(operation=op, reqId=1513945121191691, protocolVersion=CURRENT_PROTOCOL_VERSION, identifier="6ouriXMZkLeHsuXrN1X1fd") 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 digest = req.digest new_expected = SortedDict({ "reqSignature": { "type": "ED25519", "values": [{ "from": "6ouriXMZkLeHsuXrN1X1fd", "value": sign }] }, "txn": { "data": { "something": "nothing", }, "metadata": { "from": "6ouriXMZkLeHsuXrN1X1fd", "reqId": 1513945121191691 }, "protocolVersion": CURRENT_PROTOCOL_VERSION, "type": "1", }, "txnMetadata": { "txnTime": 1513945121, }, "ver": "1" }) if request.param == 'no_protocol_vers': new_expected["txn"].pop("protocolVersion", None) if digest is not None: new_expected["txn"]["metadata"]["digest"] = digest return req, new_expected
def do_multi_sig_on_req(self, request: Request, identifier: str): idr = self.requiredIdr(idr=identifier) signature = self.signMsg(msg=request.signingState(identifier), identifier=idr) request.add_signature(idr, signature)
def serializeReq(req: Request) -> str: return json.dumps(req.__getstate__())
def idr_from_req_data(data): if data.get(f.IDENTIFIER.nm): return data[f.IDENTIFIER.nm] else: return Request.gen_idr_from_sigs(data.get(f.SIGS.nm, {}))
def evilCreatePropagate(self, request: Request, clientName: str) -> Propagate: logger.debug("EVIL: Creating propagate request for client request {}". format(request)) request.operation["amount"] += random.random() return Propagate(request.__getstate__(), clientName)
def applyForced(self, req: Request): if not req.isForced(): raise LogicError('requestHandler.applyForce method is called ' 'for not forced request: {}'.format(req))