Skip to content

Commit d18f803

Browse files
authored
fix: Rename memo field to topicMemo to eliminate name collision (#2477)
Signed-off-by: iron-prog <dt915725@gmail.com>
1 parent b6c9074 commit d18f803

4 files changed

Lines changed: 97 additions & 8 deletions

File tree

src/hiero_sdk_python/consensus/topic_create_transaction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def __init__(
6363
fee_exempt_keys (list[Key], optional): Optional list of fee exempt keys for the topic (PrivateKey or PublicKey).
6464
"""
6565
super().__init__()
66-
self.memo: str = memo or ""
66+
self.topic_memo: str = memo or ""
6767
self.admin_key: Key | None = admin_key
6868
self.submit_key: Key | None = submit_key
6969
self.auto_renew_period: Duration = auto_renew_period or Duration(7890000)
@@ -84,7 +84,7 @@ def set_memo(self, memo: str) -> TopicCreateTransaction:
8484
TopicCreateTransaction: The current instance for method chaining.
8585
"""
8686
self._require_not_frozen()
87-
self.memo = memo
87+
self.topic_memo = memo
8888
return self
8989

9090
def set_admin_key(self, key: Key) -> TopicCreateTransaction:
@@ -237,7 +237,7 @@ def _build_proto_body(self) -> consensus_create_topic_pb2.ConsensusCreateTopicTr
237237
submitKey=key_to_proto(self.submit_key),
238238
autoRenewPeriod=(self.auto_renew_period._to_proto() if self.auto_renew_period is not None else None),
239239
autoRenewAccount=(self.auto_renew_account._to_proto() if self.auto_renew_account is not None else None),
240-
memo=self.memo,
240+
memo=self.topic_memo,
241241
custom_fees=[custom_fee._to_topic_fee_proto() for custom_fee in self.custom_fees],
242242
fee_schedule_key=key_to_proto(self.fee_schedule_key),
243243
fee_exempt_key_list=[key_to_proto(key) for key in self.fee_exempt_keys],

src/hiero_sdk_python/consensus/topic_update_transaction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __init__(
5757
"""
5858
super().__init__()
5959
self.topic_id: TopicId | None = topic_id
60-
self.memo: str = memo or ""
60+
self.topic_memo: str | None = memo
6161
self.admin_key: Key | None = admin_key
6262
self.submit_key: Key | None = submit_key
6363
self.auto_renew_period: Duration | None = auto_renew_period
@@ -93,7 +93,7 @@ def set_memo(self, memo: str) -> TopicUpdateTransaction:
9393
TopicUpdateTransaction: Returns the instance for method chaining.
9494
"""
9595
self._require_not_frozen()
96-
self.memo = memo
96+
self.topic_memo = memo
9797
return self
9898

9999
def set_admin_key(self, key: Key) -> TopicUpdateTransaction:
@@ -271,7 +271,7 @@ def _build_proto_body(self) -> consensus_update_topic_pb2.ConsensusUpdateTopicTr
271271
),
272272
autoRenewAccount=(self.auto_renew_account._to_proto() if self.auto_renew_account else None),
273273
expirationTime=self.expiration_time._to_protobuf() if self.expiration_time else None,
274-
memo=_wrappers_pb2.StringValue(value=self.memo) if self.memo is not None else None,
274+
memo=_wrappers_pb2.StringValue(value=self.topic_memo) if self.topic_memo is not None else None,
275275
custom_fees=custom_fees,
276276
fee_schedule_key=key_to_proto(self.fee_schedule_key) if self.fee_schedule_key else None,
277277
fee_exempt_key_list=fee_exempt_key_list,

tests/unit/topic_create_transaction_test.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ def test_constructor(multiple_custom_fees, key_type, use_private):
328328
fee_exempt_keys=fee_exempt_keys,
329329
)
330330

331-
assert tx.memo == "Test Topic"
331+
assert tx.topic_memo == "Test Topic"
332332
assert tx.admin_key == admin_key
333333
assert tx.submit_key == submit_key
334334
assert tx.custom_fees == multiple_custom_fees
@@ -339,7 +339,7 @@ def test_constructor(multiple_custom_fees, key_type, use_private):
339339
def test_constructor_default_values():
340340
"""Test constructor with default values."""
341341
tx_default = TopicCreateTransaction()
342-
assert tx_default.memo == ""
342+
assert tx_default.topic_memo == ""
343343
assert tx_default.admin_key is None
344344
assert tx_default.submit_key is None
345345
assert tx_default.custom_fees == []
@@ -627,3 +627,27 @@ def test_freeze_with_leaves_auto_renew_account_unset_without_operator(mock_clien
627627
body = frozen_tx.build_transaction_body()
628628

629629
assert not body.consensusCreateTopic.HasField("autoRenewAccount")
630+
631+
632+
def test_topic_memo_does_not_collide_with_transaction_memo():
633+
"""Regression test for: topic and transaction memos remain independent."""
634+
tx = TopicCreateTransaction(memo="my topic memo")
635+
assert tx.topic_memo == "my topic memo"
636+
assert tx.memo == "" # base Transaction-level memo defaults independently
637+
638+
tx.set_transaction_memo("some unrelated audit note")
639+
640+
assert tx.topic_memo == "my topic memo", "topic_memo was clobbered by set_transaction_memo()"
641+
assert tx.memo == "some unrelated audit note"
642+
643+
644+
def test_topic_memo_reflected_in_protobuf_independent_of_transaction_memo(mock_client):
645+
"""Verify protobuf preserves separate topic and transaction memos."""
646+
tx = TopicCreateTransaction(memo="my topic memo")
647+
tx.set_transaction_memo("some unrelated audit note")
648+
tx.transaction_id = TransactionId.generate(AccountId(0, 0, 1234))
649+
frozen_tx = tx.freeze_with(mock_client)
650+
body = frozen_tx.build_transaction_body()
651+
652+
assert body.consensusCreateTopic.memo == "my topic memo"
653+
assert body.memo == "some unrelated audit note"

tests/unit/topic_update_transaction_test.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,3 +359,68 @@ def test_topic_update_transaction_with_all_fields(topic_id):
359359

360360
# Verify the receipt contains the expected values
361361
assert receipt.status == ResponseCode.SUCCESS
362+
363+
364+
def test_topic_memo_and_transaction_memo_independent_in_protobuf(
365+
mock_account_ids,
366+
topic_id,
367+
):
368+
"""Topic and transaction memos serialize independently."""
369+
370+
_, _, node_account_id, _, _ = mock_account_ids
371+
372+
tx = TopicUpdateTransaction(
373+
topic_id=topic_id,
374+
memo="my topic memo",
375+
)
376+
377+
tx.operator_account_id = AccountId(0, 0, 2)
378+
tx.node_account_id = node_account_id
379+
380+
tx.set_transaction_memo("some unrelated audit note")
381+
382+
body = tx.build_transaction_body()
383+
384+
assert body.memo == "some unrelated audit note"
385+
assert body.consensusUpdateTopic.memo.value == "my topic memo"
386+
387+
388+
def test_set_memo_updates_topic_memo_only():
389+
"""Verify set_memo() only updates the topic memo."""
390+
tx = TopicUpdateTransaction()
391+
tx.set_transaction_memo("audit note")
392+
tx.set_memo("new topic memo")
393+
394+
assert tx.topic_memo == "new topic memo"
395+
assert tx.memo == "audit note"
396+
397+
398+
def test_topic_memo_serialization_distinguishes_unset_and_empty(
399+
mock_account_ids,
400+
topic_id,
401+
):
402+
"""Unset and explicit empty topic memos serialize differently."""
403+
_, _, node_account_id, _, _ = mock_account_ids
404+
405+
tx = TopicUpdateTransaction(topic_id=topic_id)
406+
tx.operator_account_id = AccountId(0, 0, 2)
407+
tx.node_account_id = node_account_id
408+
409+
body = tx.build_transaction_body().consensusUpdateTopic
410+
assert not body.HasField("memo")
411+
412+
tx = TopicUpdateTransaction(topic_id=topic_id, memo="")
413+
tx.operator_account_id = AccountId(0, 0, 2)
414+
tx.node_account_id = node_account_id
415+
416+
body = tx.build_transaction_body().consensusUpdateTopic
417+
assert body.HasField("memo")
418+
assert body.memo.value == ""
419+
420+
tx = TopicUpdateTransaction(topic_id=topic_id, memo="hello")
421+
tx.operator_account_id = AccountId(0, 0, 2)
422+
tx.node_account_id = node_account_id
423+
424+
body = tx.build_transaction_body().consensusUpdateTopic
425+
assert body.HasField("memo")
426+
assert body.memo.value == "hello"

0 commit comments

Comments
 (0)