Skip to content

Commit b024705

Browse files
committed
wip tck support
Signed-off-by: LukeBair <[email protected]>
1 parent b3f2aeb commit b024705

File tree

9 files changed

+341
-3
lines changed

9 files changed

+341
-3
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ dependencies = [
1818
"grpcio==1.68.1",
1919
"cryptography==44.0.0",
2020
"python-dotenv==1.0.1",
21-
"requests==2.32.3"
21+
"requests==2.32.3",
22+
"jsonrpcserver>=5.0.9",
2223
]
2324
classifiers = [
2425
"Development Status :: 2 - Pre-Alpha",

tck/README.md

Whitespace-only changes.

tck/__init__.py

Whitespace-only changes.

tck/account_create.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import utils
2+
3+
from jsonrpcserver import method, Success
4+
from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
5+
from key_identifier import KeyIdentifier
6+
7+
# NOTE: The problem is I need to use a string to identify whether or not a key is ecdsa, ed25519, public or private
8+
# The PrivateKey class has a 'from_string' class which I can take advantage of easily
9+
# The PublicKey doesnt have anything helpful, once you have a reference to it you can check if it is ed25519 or ecdsa
10+
# So I will likely have to add a way to check for the public key, this can be done outside of the PublicKey class,
11+
# but to keep consistency with the PrivateKey class it would be really nice to have a 'from_string' class in there
12+
# Ill take a look into it rn to see if it is something I am capable of doing well (I know a way I could but its dookie)
13+
# It doesnt look like something that I really have any right doing, Im not really sure where to start with the ec key,
14+
# I'll look into it again
15+
# Ignoring KeyLists right now
16+
# The """...""" block is taken directly from the tck AccountCreateTransaction.md & combined with the intellij
17+
# autogenerated """...""" block
18+
@method
19+
def createAccount(key: str = None, initialBalance: str = None, receiverSignatureRequired: bool = None, autoRenewPeriod: str = None,
20+
memo: str = None, maxAutoTokenAssociations: int = None, stakedAccountId: str = None, stakedNodeId: str = None,
21+
declineStakingReward: bool = None, alias: str = None, commonTransactionParams: dict = None):
22+
"""
23+
:param key: string, optional, DER-encoded hex string representation for private or public keys. Keylists and threshold keys are the hex of the serialized protobuf bytes.
24+
:param initialBalance: Units of tinybars, optional
25+
:param receiverSignatureRequired: bool, optional
26+
:param autoRenewPeriod: string, Units of seconds, optional
27+
:param memo: string, optional
28+
:param maxAutoTokenAssociations: int32, optional
29+
:param stakedAccountId: string, optional
30+
:param stakedNodeId: string, optional
31+
:param declineStakingReward: bool, optional
32+
:param alias: string, optional, Hex string representation of the keccak-256 hash of an ECDSAsecp256k1 public key type.
33+
:param commonTransactionParams: JSON object, optional
34+
35+
:return accountId: string, The ID of the created account.
36+
:return status: string, The status of the submitted AccountCreateTransaction (from a TransactionReceipt).
37+
"""
38+
key_and_public = KeyIdentifier.identify(key)
39+
40+
if key_and_public[1] is False:
41+
public_key = key_and_public[0].public_key()
42+
else:
43+
public_key = key_and_public[0]
44+
45+
# TODO: add all of the other transaction parameters
46+
transaction = (
47+
AccountCreateTransaction()
48+
.set_key(public_key)
49+
.set_account_memo(memo)
50+
.freeze_with(utils.__client)
51+
)
52+
# WARNING: I believe that this is right, but im not sure what the case is if the key parameter is a Private Key
53+
# why the heck are they giving me a private key anyways...
54+
transaction.sign(utils.__operatorPrivateKey)
55+
receipt = transaction.execute(utils.__client)
56+
57+
return Success({
58+
"accountId": receipt.accountId,
59+
"status": receipt.status,
60+
})

tck/key_identifier.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from cryptography.hazmat.primitives.asymmetric import ed25519, ec
2+
from hiero_sdk_python import PublicKey, PrivateKey
3+
4+
class KeyIdentifier:
5+
6+
# NOTE: after having AI try and fail to write this code for a couple tries Im going to give it a crack
7+
# to prove that AI isnt better than a 19 year old bum. Also cause they cant do it and im cocky.
8+
# So this method will have to do a couple things, it will need to be able to identify from bytes and a string.
9+
# Hedera's DER keys seem to be in a hex format
10+
# TODO: The fact that identify() and is_public() have super similar code is disgusting
11+
# NOTE: You can probably take some of this code and use it for importing an existing key: https://docs.hedera.com/hedera/sdks-and-apis/sdks/keys/import-an-existing-key
12+
13+
@classmethod
14+
def identify(cls, key: str) -> tuple[None | PublicKey | PrivateKey, bool | None]:
15+
"""
16+
This function will either return a cryptography ...Key object, or it will return None, should not be used
17+
for anything outside of the TCK code.
18+
"""
19+
try:
20+
return PublicKey.from_string(key), True
21+
except ValueError:
22+
try:
23+
return PrivateKey.from_string(key), False
24+
except ValueError:
25+
return None, None

tck/server.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import logging
2+
import utils
3+
import account_create
4+
from jsonrpcserver import serve, method
5+
6+
logging.basicConfig(level=logging.DEBUG)
7+
8+
if __name__ == '__main__':
9+
serve(port=8545) # Specify your desired port here

tck/utils.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from hiero_sdk_python.account.account_id import AccountId
2+
from hiero_sdk_python.client.client import Client
3+
from jsonrpcserver import Success, method, InvalidParams
4+
from hiero_sdk_python.crypto.private_key import PrivateKey
5+
6+
__operatorAccountId: AccountId
7+
__operatorPrivateKey: PrivateKey
8+
__client: Client = Client()
9+
10+
@method
11+
def setup(operatorAccountId: str=None, operatorPrivateKey: str=None, nodeIp: str=None, nodeAccountId: str=None, mirrorNetworkIp: str=None):
12+
global __client, __operatorAccountId, __operatorPrivateKey
13+
__operatorAccountId = AccountId.from_string(operatorAccountId)
14+
__operatorPrivateKey = PrivateKey.from_string(operatorPrivateKey[2:])
15+
__client.set_operator(__operatorAccountId, __operatorPrivateKey)
16+
17+
return Success({
18+
"message":"Successfully setup custom client.",
19+
"status":"SUCCESS"
20+
})
21+
22+
@method
23+
def reset():
24+
global __operatorAccountId, __operatorPrivateKey, __client
25+
26+
__operatorAccountId = None
27+
__operatorPrivateKey = None
28+
__client = Client()
29+
30+
return Success({
31+
"message":"Successfully reset client.",
32+
"status":"SUCCESS"
33+
})
34+
35+
@method
36+
def generateKey(type: str=None, fromKey: str=None, threshold: int=None, keys: list=None):
37+
if type == "ed25519PublicKey":
38+
new_account_private_key = PrivateKey.from_string(fromKey)
39+
new_account_public_key = new_account_private_key.public_key()
40+
return Success({"key": new_account_public_key.to_string_raw()})
41+
42+
elif type == "ecdsaSecp256k1PublicKey":
43+
new_account_private_key = PrivateKey.from_string(fromKey)
44+
new_account_public_key = new_account_private_key.public_key()
45+
return Success({"key": new_account_public_key.to_string_raw()})
46+
47+
elif type == "ed25519PrivateKey":
48+
new_account_private_key = PrivateKey.generate()
49+
return Success({"key": new_account_private_key.to_string_raw()})
50+
51+
else:
52+
return InvalidParams("Unknown type")
53+

tests/key_identifier_tester.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
2+
3+
from tck.key_identifier import KeyIdentifier
4+
5+
6+
def test_key_identifier():
7+
assert isinstance(KeyIdentifier().identify("302d300706052b8104000a03220002ffda8e4c9faf6d2b89189196f76c8c6448f7f04e00f56ccff63ba857c2782661"), EllipticCurvePublicKey)

0 commit comments

Comments
 (0)