Skip to content

Commit 290b6b6

Browse files
Merge branch 'main' into fix-add-repr-to-custom-fee-base
Signed-off-by: Prakhar Jain <[email protected]>
2 parents d22527a + a3cfa1a commit 290b6b6

19 files changed

+848
-218
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
1010
- Unified balance and transfer logging format — both now consistently display values in hbars for clarity.
1111

1212
### Added
13-
14-
- Add `__repr__` method to CustomFee base class for better debugging by displaying fee_collector_account_id and all_collectors_are_exempt.
1513
- Refactored `examples/topic_create.py` into modular functions for better readability and reuse.
1614
- Add Rebasing and Signing section to signing.md with instructions for maintaining commit verification during rebase operations (#556)
1715
- Add `examples/account_id.py` demonstrating AccountId class usage including creating standard AccountIds, parsing from strings, comparing instances, and creating AccountIds with public key aliases
@@ -25,6 +23,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
2523
- docs: Add Google-style docstrings to `AbstractTokenTransferTransaction` class and its methods in `abstract_token_transfer_transaction.py`.
2624
- docs: Add Google-style docstrings to `TokenRelationship` class and its methods in `token_relationship.py`.
2725
- feat: add initial testing guide structure
26+
- Added `checksum` filed for TopicId, FileId, ContractId, ScheduleId class
2827

2928
### Changed
3029

@@ -49,6 +48,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
4948

5049
- Add type hints to `setup_client()` and `create_new_account()` functions in `examples/account_create.py` (#418)
5150
- Added explicit read and write permissions to test.yml
51+
- Type hinting for `Topic` related transactions.
5252

5353
### Removed
5454
- Remove deprecated camelCase alias support and `_DeprecatedAliasesMixin`; SDK now only exposes snake_case attributes for `NftId`, `TokenInfo`, and `TransactionReceipt`. (Issue #428)
@@ -80,6 +80,10 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
8080
- Added checksum validation for TokenId
8181
- Refactor examples/token_cancel_airdrop
8282
- Refactor token creation examples for modularity and consistency
83+
- Updated `signing.md` to clarify commit signing requirements, including DCO, GPG, and branch-specific guidelines (#459)
84+
85+
### Changed
86+
8387
- Rearranged running_examples.md to be alphabetical
8488
- Refactor token_associate.py for better structure, add association verification query (#367)
8589
- Refactored `examples/account_create.py` to improve modularity and readability (#363)

docs/sdk_developers/signing.md

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
To contribute to this repository, **both DCO sign-off and GPG signature verification** are required for your commits to be merged successfully.
44

5-
This guide walks you through how to correctly configure and sign your commits.
5+
This guide walks you through how to correctly configure and sign your commits, and how to ensure **all commits are properly signed**.
66

77
---
88

99
## 🛡️ Why Commit Signing?
1010

11-
- **DCO (`Signed-off-by`)** ensures you agree to the developer certificate of origin.
12-
- **GPG Signature** proves the commit was authored by a trusted and verified identity.
11+
* **DCO (`Signed-off-by`)** ensures you agree to the developer certificate of origin.
12+
* **GPG Signature** proves the commit was authored by a trusted and verified identity.
1313

1414
---
1515

@@ -25,22 +25,21 @@ gpg --full-generate-key
2525

2626
Choose:
2727

28-
Kind: RSA and RSA
29-
30-
Key size: 4096
31-
32-
Expiration: 0 (or choose as per your need)
33-
34-
Name, Email: Must match your GitHub email
35-
36-
Passphrase: Set a strong passphrase
28+
* Kind: RSA and RSA
29+
* Key size: 4096
30+
* Expiration: 0 (or choose as per your need)
31+
* Name, Email: Must match your GitHub email
32+
* Passphrase: Set a strong passphrase
3733

3834
To list your keys:
3935

4036
```bash
41-
gpg --list-secret-keys --keyid-format LONG
37+
gpg --list-secret-keys --keyid-format LONG
4238
```
43-
Copy the key ID (it looks like 34AA6DBC)
39+
40+
Copy the key ID (looks like `34AA6DBC`).
41+
42+
---
4443

4544
### 2. Add Your GPG Key to GitHub
4645

@@ -49,35 +48,69 @@ Export your GPG public key:
4948
```bash
5049
gpg --armor --export YOUR_KEY_ID
5150
```
52-
Paste the output into GitHub here:
5351

52+
Paste the output into GitHub:
53+
54+
* [Add GPG key on Github](https://github.com/settings/gpg/new)
5455

55-
- [Add GPG key on Github ](https://github.com/settings/gpg/new)
56+
---
5657

57-
### 3. Tell Git to Use Your GPG Key
58+
### 3. Configure Git to Use Your GPG Key
5859

5960
```bash
6061
git config --global user.signingkey YOUR_KEY_ID
6162
git config --global commit.gpgsign true
6263
```
6364

64-
### 4. Make a Signed Commit
65+
---
66+
67+
## ✨ Make Signed Commits
6568

66-
Use both DCO sign-off and GPG signing:
69+
**All commits must be signed using both DCO and GPG.**
6770

6871
```bash
6972
git commit -S -s -m "chore: your commit message"
7073
```
7174

72-
-S = GPG sign
73-
-s = DCO sign-off
75+
* `-S` = GPG sign
76+
* `-s` = DCO sign-off
77+
78+
> ⚠️ Ensure **every commit** in your branch follows this rule.
7479
75-
### Fixing an Unsigned Commit
80+
---
81+
82+
## 🛠️ Fixing Unsigned Commits
83+
84+
If you accidentally forgot to sign commits, there are **two ways to fix them**:
85+
86+
### 1. Soft Reverting Commits (Recommended for New Contributors)
87+
88+
Soft revert the impacted commits while keeping changes locally:
89+
90+
```bash
91+
git reset --soft HEAD~n
92+
```
93+
94+
* `HEADn` = number of commits to go back
95+
* Example: To fix the last 3 commits: `git reset --soft HEAD`
7696

77-
If you forgot to sign or DCO a commit:
97+
Then, recommit each commit with proper signing:
98+
99+
```bash
100+
git commit -S -s -m "chore: your commit message"
101+
```
102+
103+
Repeat for each impacted commit.
104+
105+
---
106+
107+
### 2. Retroactively Signing Commits
108+
109+
Alternatively, you can **amend commits retroactively**:
78110

79111
```bash
80112
git commit --amend -S -s
113+
git rebase -i HEAD~n # For multiple commits
81114
git push --force-with-lease
82115
```
83116
## Rebasing and Signing
@@ -91,16 +124,39 @@ When rebasing, you must use this command to ensure your commits remain verified:
91124
git rebase main -S
92125
```
93126

127+
> **Note:** `--force-with-lease` safely updates the remote branch without overwriting others’ changes.
128+
129+
---
130+
131+
## ✅ Verify Signed Status of Commits
132+
133+
To check that your commits are signed correctly:
134+
135+
```bash
136+
git log --show-signature
137+
```
138+
139+
* Ensure each commit shows both **GPG verified** and **DCO signed-off**.
140+
* For a quick check of recent commits:
141+
142+
```bash
143+
git log -n 5 --pretty=format:'%h %an %G? %s'
144+
```
145+
146+
* `G?` column shows the signature status (`G` = good, `B` = bad, `U` = unsigned)
147+
148+
---
149+
94150
## ✅ Final Checklist
95151

96-
- [ ] Signed your commit with `-S`
97-
- [ ] Added DCO with `-s`
98-
- [ ] GPG key is added to GitHub
99-
- [ ] Verified badge appears in PR
152+
* [ ] All commits signed with `-S`
153+
* [ ] DCO added with `-s`
154+
* [ ] GPG key added to GitHub
155+
* [ ] Verified badge appears in PR
100156

157+
---
101158

102159
### Still Need Help?
103160

104-
If you run into issues:
105-
106-
- Refer to [GitHub’s GPG Docs](https://docs.github.com/en/authentication/managing-commit-signature-verification)
161+
* Refer to [GitHub’s GPG Docs](https://docs.github.com/en/authentication/managing-commit-signature-verification)
162+
* Ask maintainers on the **Hiero Discord** if stuck

src/hiero_sdk_python/account/account_id.py

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22
AccountId class.
33
"""
44

5-
from typing import List
5+
import re
6+
from typing import TYPE_CHECKING
67

78
from hiero_sdk_python.crypto.public_key import PublicKey
89
from hiero_sdk_python.hapi.services import basic_types_pb2
10+
from hiero_sdk_python.utils.entity_id_helper import (
11+
parse_from_string,
12+
validate_checksum,
13+
format_to_string_with_checksum
14+
)
915

16+
if TYPE_CHECKING:
17+
from hiero_sdk_python.client.client import Client
18+
19+
ALIAS_REGEX = re.compile(r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.((?:[0-9a-fA-F][0-9a-fA-F])+)$")
1020

1121
class AccountId:
1222
"""
@@ -37,17 +47,42 @@ def __init__(
3747
self.realm = realm
3848
self.num = num
3949
self.alias_key = alias_key
50+
self.__checksum: str | None = None
4051

4152
@classmethod
4253
def from_string(cls, account_id_str: str) -> "AccountId":
4354
"""
4455
Creates an AccountId instance from a string in the format 'shard.realm.num'.
4556
"""
46-
parts: List[str] = account_id_str.strip().split(".")
47-
if len(parts) != 3:
48-
raise ValueError("Invalid account ID string format. Expected 'shard.realm.num'")
49-
shard, realm, num = map(int, parts)
50-
return cls(shard, realm, num)
57+
if account_id_str is None or not isinstance(account_id_str, str):
58+
raise ValueError(f"Invalid account ID string '{account_id_str}'. Expected format 'shard.realm.num'.")
59+
60+
try:
61+
shard, realm, num, checksum = parse_from_string(account_id_str)
62+
63+
account_id: AccountId = cls(
64+
shard=int(shard),
65+
realm=int(realm),
66+
num=int(num)
67+
)
68+
account_id.__checksum = checksum
69+
70+
return account_id
71+
except Exception as e:
72+
alias_match = ALIAS_REGEX.match(account_id_str)
73+
74+
if alias_match:
75+
shard, realm, alias = alias_match.groups()
76+
return cls(
77+
shard=int(shard),
78+
realm=int(realm),
79+
num=0,
80+
alias_key=PublicKey.from_bytes(bytes.fromhex(alias))
81+
)
82+
83+
raise ValueError(
84+
f"Invalid account ID string '{account_id_str}'. Expected format 'shard.realm.num'."
85+
) from e
5186

5287
@classmethod
5388
def _from_proto(cls, account_id_proto: basic_types_pb2.AccountID) -> "AccountId":
@@ -89,6 +124,24 @@ def _to_proto(self) -> basic_types_pb2.AccountID:
89124

90125
return account_id_proto
91126

127+
@property
128+
def checksum(self) -> str | None:
129+
"""Checksum of the accountId"""
130+
return self.__checksum
131+
132+
def validate_checksum(self, client: "Client") -> None:
133+
"""Validate the checksum for the accountId"""
134+
if self.alias_key is not None:
135+
raise ValueError("Cannot calculate checksum with an account ID that has a aliasKey")
136+
137+
validate_checksum(
138+
self.shard,
139+
self.realm,
140+
self.num,
141+
self.__checksum,
142+
client,
143+
)
144+
92145
def __str__(self) -> str:
93146
"""
94147
Returns the string representation of the AccountId in 'shard.realm.num' format.
@@ -97,6 +150,21 @@ def __str__(self) -> str:
97150
return f"{self.shard}.{self.realm}.{self.alias_key.to_string()}"
98151
return f"{self.shard}.{self.realm}.{self.num}"
99152

153+
def to_string_with_checksum(self, client: "Client") -> str:
154+
"""
155+
Returns the string representation of the AccountId with checksum
156+
in 'shard.realm.num-checksum' format.
157+
"""
158+
if self.alias_key is not None:
159+
raise ValueError("Cannot calculate checksum with an account ID that has a aliasKey")
160+
161+
return format_to_string_with_checksum(
162+
self.shard,
163+
self.realm,
164+
self.num,
165+
client
166+
)
167+
100168
def __repr__(self):
101169
"""
102170
Returns the repr representation of the AccountId.

src/hiero_sdk_python/consensus/topic_delete_transaction.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
"""
88

99
from typing import Optional
10+
from hiero_sdk_python.consensus.topic_id import TopicId
1011
from hiero_sdk_python.transaction.transaction import Transaction
1112
from hiero_sdk_python.hapi.services import (
1213
consensus_delete_topic_pb2,
13-
transaction_pb2,
14-
basic_types_pb2
14+
transaction_pb2
1515
)
1616
from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import (
1717
SchedulableTransactionBody,
@@ -27,12 +27,12 @@ class TopicDeleteTransaction(Transaction):
2727
2828
"""
2929

30-
def __init__(self, topic_id: Optional[basic_types_pb2.TopicID] = None) -> None:
30+
def __init__(self, topic_id: Optional[TopicId] = None) -> None:
3131
super().__init__()
32-
self.topic_id: Optional[basic_types_pb2.TopicID] = topic_id
32+
self.topic_id: Optional[TopicId] = topic_id
3333
self.transaction_fee: int = 10_000_000
3434

35-
def set_topic_id(self, topic_id: basic_types_pb2.TopicID ) -> "TopicDeleteTransaction":
35+
def set_topic_id(self, topic_id:TopicId ) -> "TopicDeleteTransaction":
3636
"""
3737
Sets the topic ID for the transaction.
3838

0 commit comments

Comments
 (0)