def test_update_state(txn_author_agreement_handler, taa_request): seq_no = 1 txn_time = 1560241033 txn_id = "id" txn = reqToTxn(taa_request) payload = get_payload_data(txn) text = payload[TXN_AUTHOR_AGREEMENT_TEXT] version = payload[TXN_AUTHOR_AGREEMENT_VERSION] digest = StaticTAAHelper.taa_digest(text, version) append_txn_metadata(txn, seq_no, txn_time, txn_id) state_value = { TXN_AUTHOR_AGREEMENT_TEXT: text, TXN_AUTHOR_AGREEMENT_VERSION: version } txn_author_agreement_handler.update_state(txn, None, taa_request) assert txn_author_agreement_handler.get_from_state( StaticTAAHelper.state_path_taa_digest(digest)) == (state_value, seq_no, txn_time) assert txn_author_agreement_handler.state.get( StaticTAAHelper.state_path_taa_latest()) == digest assert txn_author_agreement_handler.state.get( StaticTAAHelper.state_path_taa_version(version)) == digest
def _validate_update_taa(self, request, digest): ledger_taa = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest))[0] # check TAA text taa_text = ledger_taa.get(TXN_AUTHOR_AGREEMENT_TEXT) if request.operation.get(TXN_AUTHOR_AGREEMENT_TEXT, taa_text) != taa_text: raise InvalidClientRequest(request.identifier, request.reqId, "Changing a text of existing transaction author agreement is forbidden") # check TAA ratification timestamp taa_ratified = ledger_taa.get(TXN_AUTHOR_AGREEMENT_RATIFICATION_TS) if request.operation.get(TXN_AUTHOR_AGREEMENT_RATIFICATION_TS, taa_ratified) != taa_ratified: raise InvalidClientRequest(request.identifier, request.reqId, "Changing ratification date of existing " "transaction author agreement is forbidden") # TODO: Following code assumes that the only reason for updating TAA is changing its retirement date. # If this is no longer the case this needs to be changed. Also this cries for adding separate transaction # for TAA retirement # check if TAA enforcement is disabled last_taa_digest = StaticTAAHelper.get_latest_taa(self.state) if last_taa_digest is None: raise InvalidClientRequest(request.identifier, request.reqId, "Retirement date cannot be changed when TAA enforcement is disabled.") # check if we are trying to modify latest TAA if last_taa_digest == digest: raise InvalidClientRequest(request.identifier, request.reqId, "The latest transaction author agreement cannot be retired.")
def get_result(self, request: Request): version = request.operation.get(GET_TXN_AUTHOR_AGREEMENT_VERSION) digest = request.operation.get(GET_TXN_AUTHOR_AGREEMENT_DIGEST) timestamp = request.operation.get(GET_TXN_AUTHOR_AGREEMENT_TIMESTAMP) if version is not None: path = StaticTAAHelper.state_path_taa_version(version) digest, proof = self._get_value_from_state(path, with_proof=True) return self._return_txn_author_agreement(request, proof, digest=digest) if digest is not None: path = StaticTAAHelper.state_path_taa_digest(digest) data, proof = self._get_value_from_state(path, with_proof=True) return self._return_txn_author_agreement(request, proof, data=data) if timestamp is not None: head_hash = self.database_manager.ts_store.get_equal_or_prev( timestamp, CONFIG_LEDGER_ID) if head_hash is None: return self._return_txn_author_agreement(request, None) path = StaticTAAHelper.state_path_taa_latest() digest, proof = self._get_value_from_state(path, head_hash, with_proof=True) return self._return_txn_author_agreement(request, proof, head_hash=head_hash, digest=digest) path = StaticTAAHelper.state_path_taa_latest() digest, proof = self._get_value_from_state(path, with_proof=True) return self._return_txn_author_agreement(request, proof, digest=digest)
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, last_seq_no, last_update_time = self._decode_state_value( taa[0]) digest = StaticTAAHelper.get_digest_from_state_key(encode_key) if TXN_AUTHOR_AGREEMENT_RETIREMENT_TS not in taa or taa.get( TXN_AUTHOR_AGREEMENT_RETIREMENT_TS, 0) > txn_time: self._set_taa_to_state( digest, seq_no, txn_time, taa[TXN_AUTHOR_AGREEMENT_TEXT], taa[TXN_AUTHOR_AGREEMENT_VERSION], taa.get(TXN_AUTHOR_AGREEMENT_RATIFICATION_TS, last_update_time), retirement_ts=txn_time) self.state.remove(StaticTAAHelper.state_path_taa_latest())
def _update_taa_to_state(self, digest, seq_no, txn_time, retirement_ts=None): ledger_data = self.get_from_state(StaticTAAHelper.state_path_taa_digest(digest)) if ledger_data is None: return ledger_taa, last_seq_no, last_update_time = ledger_data ratification_ts = ledger_taa.get(TXN_AUTHOR_AGREEMENT_RATIFICATION_TS, last_update_time) text = ledger_taa.get(TXN_AUTHOR_AGREEMENT_TEXT) version = ledger_taa.get(TXN_AUTHOR_AGREEMENT_VERSION) self._set_taa_to_state(digest, seq_no, txn_time, text, version, ratification_ts, retirement_ts)
def _update_txn_author_agreement(self, seq_no, txn_time, text, version): digest = StaticTAAHelper.taa_digest(text, version) data = encode_state_value( { TXN_AUTHOR_AGREEMENT_TEXT: text, TXN_AUTHOR_AGREEMENT_VERSION: version }, 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)
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] version = payload[TXN_AUTHOR_AGREEMENT_VERSION] seq_no = get_seq_no(txn) txn_time = get_txn_time(txn) digest = StaticTAAHelper.taa_digest(text, version) data = encode_state_value({ TXN_AUTHOR_AGREEMENT_TEXT: text, TXN_AUTHOR_AGREEMENT_VERSION: version }, 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)
def test_update_state_one_by_one(txn_author_agreement_handler, taa_request, taa_pp_time, retired_time): txn, digest, state_data = create_taa_txn(taa_request, taa_pp_time) state_value, seq_no, txn_time_first = state_data payload = get_payload_data(txn) txn_time_second = get_utc_epoch() # update state txn_author_agreement_handler.update_state(txn, None, None) if retired_time and retired_time != "without": payload[TXN_AUTHOR_AGREEMENT_RETIREMENT_TS] = retired_time state_value[TXN_AUTHOR_AGREEMENT_RETIREMENT_TS] = retired_time txn[TXN_METADATA][TXN_METADATA_TIME] = txn_time_second txn_author_agreement_handler.update_state(txn, None, None) assert txn_author_agreement_handler.get_from_state( StaticTAAHelper.state_path_taa_digest(digest)) == (state_value, seq_no, txn_time_second)
def _return_txn_author_agreement(self, request, proof, head_hash=None, digest=None, data=None): if digest is not None: head_hash = head_hash if head_hash else self.state.committedHeadHash data = self.state.get_for_root_hash( head_hash, StaticTAAHelper.state_path_taa_digest(digest.decode())) if data is not None: value, last_seq_no, last_update_time = decode_state_value( data, serializer=config_state_serializer) return self.make_result(request, value, last_seq_no, last_update_time, proof) return self.make_result(request, None, proof=proof)
def test_fill_ts_store_for_config_after_catchup(txnPoolNodeSet, looper, sdk_pool_handle, sdk_wallet_trustee, tconf, tdir, allPluginsPath, set_txn_author_agreement_aml): sdk_send_txn_author_agreement(looper, sdk_pool_handle, sdk_wallet_trustee, *create_random_taa(), ratified=get_utc_epoch() - 600) node_to_disconnect = txnPoolNodeSet[-1] disconnect_node_and_ensure_disconnected(looper, txnPoolNodeSet, node_to_disconnect) looper.removeProdable(name=node_to_disconnect.name) sdk_reply = sdk_send_txn_author_agreement(looper, sdk_pool_handle, sdk_wallet_trustee, *create_random_taa(), ratified=get_utc_epoch() - 600) node_to_disconnect = start_stopped_node(node_to_disconnect, looper, tconf, tdir, allPluginsPath) txnPoolNodeSet[-1] = node_to_disconnect looper.run(checkNodesConnected(txnPoolNodeSet)) waitNodeDataEquality(looper, node_to_disconnect, *txnPoolNodeSet, exclude_from_check=['check_last_ordered_3pc_backup']) req_handler = node_to_disconnect.read_manager.request_handlers[ GET_TXN_AUTHOR_AGREEMENT] last_digest = StaticTAAHelper.get_taa_digest(req_handler.state) key = StaticTAAHelper.state_path_taa_digest(last_digest) root_hash = req_handler.database_manager.ts_store.get_equal_or_prev( get_txn_time(sdk_reply[1]['result'])) assert root_hash from_state = req_handler.state.get_for_root_hash(root_hash=root_hash, key=key) assert config_state_serializer.deserialize(from_state)['val']['text'] == \ get_payload_data(sdk_reply[1]['result'])['text']
def _set_taa_to_state(self, digest, seq_no, txn_time, text, version, ratification_ts, retirement_ts=None): state_value = { TXN_AUTHOR_AGREEMENT_TEXT: text, TXN_AUTHOR_AGREEMENT_VERSION: version, TXN_AUTHOR_AGREEMENT_RATIFICATION_TS: ratification_ts, TXN_AUTHOR_AGREEMENT_DIGEST: digest } if retirement_ts: state_value[TXN_AUTHOR_AGREEMENT_RETIREMENT_TS] = retirement_ts data = encode_state_value(state_value, seq_no, txn_time, serializer=config_state_serializer) self.state.set(StaticTAAHelper.state_path_taa_digest(digest), data)
def check_taa_in_state(handler, digest, version, state_data): assert handler.get_from_state( StaticTAAHelper.state_path_taa_digest(digest)) == state_data assert handler.state.get(StaticTAAHelper.state_path_taa_version(version), isCommitted=False) == digest.encode()