Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/hiero_sdk_python/transaction/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,12 @@ def sign(self, private_key: PrivateKey) -> Transaction:
# We initialize the signature map for this body_bytes if it doesn't exist yet
self._signature_map.setdefault(body_bytes, basic_types_pb2.SignatureMap())

# Append the signature pair to the signature map for this transaction body
self._signature_map[body_bytes].sigPair.append(sig_pair)
# deduplication check
already_signed = any(sp.pubKeyPrefix == public_key_bytes for sp in self._signature_map[body_bytes].sigPair)

# append only if not already signed
if not already_signed:
self._signature_map[body_bytes].sigPair.append(sig_pair)

return self

Expand Down
46 changes: 46 additions & 0 deletions tests/unit/signature_deduplication_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from __future__ import annotations
Comment thread
mohityadav8 marked this conversation as resolved.
Outdated

from hiero_sdk_python.account.account_id import AccountId
from hiero_sdk_python.crypto.private_key import PrivateKey
from hiero_sdk_python.tokens.token_id import TokenId
from hiero_sdk_python.tokens.token_mint_transaction import TokenMintTransaction
from hiero_sdk_python.transaction.transaction_id import TransactionId


def test_duplicate_signature_not_added():
tx = TokenMintTransaction()
tx.set_transaction_id(TransactionId.generate(AccountId(0, 0, 1234)))
tx.set_node_account_id(AccountId(0, 0, 3))
tx.set_token_id(TokenId(0, 0, 1))
tx.set_amount(100)
key = PrivateKey.generate_ed25519()
tx.freeze()
tx.sign(key)
tx.sign(key)
assert tx._signature_map, "signature_map should not be empty after freeze+sign" # ← ADD HERE
body_bytes = next(iter(tx._signature_map.keys()))
sig_pairs = tx._signature_map[body_bytes].sigPair
assert len(sig_pairs) == 1, "Expected 1 signature for duplicate key"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated


def test_multiple_keys_still_work():
tx = TokenMintTransaction()
tx.set_transaction_id(TransactionId.generate(AccountId(0, 0, 1234)))
tx.set_node_account_id(AccountId(0, 0, 3))
tx.set_token_id(TokenId(0, 0, 1))
tx.set_amount(100)
key1 = PrivateKey.generate_ed25519()
key2 = PrivateKey.generate_ed25519()
tx.freeze()
tx.sign(key1)
tx.sign(key2)
assert tx._signature_map, "signature_map should not be empty after freeze+sign"
body_bytes = next(iter(tx._signature_map.keys()))
sig_pairs = tx._signature_map[body_bytes].sigPair
assert len(sig_pairs) == 2, "Expected 2 signatures for different keys"
pubkey_prefixes = {sp.pubKeyPrefix for sp in sig_pairs}
expected_prefixes = {
key1.public_key().to_bytes_raw(),
key2.public_key().to_bytes_raw(),
}
assert pubkey_prefixes == expected_prefixes, "Signatures should match key1 and key2 exactly"