From ba847f674609adc933ccb16da0c127c1cb43ae16 Mon Sep 17 00:00:00 2001 From: SAIKAT KARMAKAR Date: Sat, 14 Oct 2023 22:24:07 +0100 Subject: [PATCH] 14 oct update part-1. SubDomainRegistrar, PublicResolver added & all tests added for them --- src/fds/contracts/Multibox.py | 28 ++++ src/fds/contracts/PublicResolver.py | 142 ++++++++++++++++++ src/fds/contracts/SubdomainRegistrar.py | 60 ++++++++ src/fds/contracts/multibox.py | 0 src/fds/contracts/public_resolver.py | 0 src/fds/contracts/subdomain_registrar.py | 0 src/fds/tests/conftest.py | 20 ++- src/fds/tests/unit_tests/test_ensregistry.py | 2 +- .../tests/unit_tests/test_public_resolver.py | 54 +++++++ .../unit_tests/test_subdomain_register.py | 20 +++ src/fds/utils/Exceptions.py | 4 + 11 files changed, 323 insertions(+), 7 deletions(-) create mode 100644 src/fds/contracts/Multibox.py create mode 100644 src/fds/contracts/PublicResolver.py create mode 100644 src/fds/contracts/SubdomainRegistrar.py delete mode 100644 src/fds/contracts/multibox.py delete mode 100644 src/fds/contracts/public_resolver.py delete mode 100644 src/fds/contracts/subdomain_registrar.py create mode 100644 src/fds/tests/unit_tests/test_public_resolver.py create mode 100644 src/fds/tests/unit_tests/test_subdomain_register.py diff --git a/src/fds/contracts/Multibox.py b/src/fds/contracts/Multibox.py new file mode 100644 index 0000000..0fe2b20 --- /dev/null +++ b/src/fds/contracts/Multibox.py @@ -0,0 +1,28 @@ +""" +Copyright 2023 The FairDataSociety Authors +This file is part of the FairDataSociety library. + +The FairDataSociety library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The FairDataSociety library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the FairDataSociety library. If not, see . + +handles Multibox contract +""" + +from typing import Tuple, Union + +from ape import convert, networks, project +from ape.api.accounts import AccountAPI +from ape.api.transactions import ReceiptAPI +from ape.types import AddressType + +from fds.utils.Exceptions import AccountNotSetUp diff --git a/src/fds/contracts/PublicResolver.py b/src/fds/contracts/PublicResolver.py new file mode 100644 index 0000000..c06f54f --- /dev/null +++ b/src/fds/contracts/PublicResolver.py @@ -0,0 +1,142 @@ +""" +Copyright 2023 The FairDataSociety Authors +This file is part of the FairDataSociety library. + +The FairDataSociety library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The FairDataSociety library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the FairDataSociety library. If not, see . + +handles PublicResolver contract +""" +from typing import Tuple, Union + +from ape import convert, networks, project +from ape.api.accounts import AccountAPI +from ape.api.transactions import ReceiptAPI +from ape.types import AddressType + +from fds.utils.Exceptions import AccountNotSetUp + + +class PublicResolverClass: + def __init__(self, account: AccountAPI, contract_address: Union[AddressType, None] = None): + self.account = account + self.contract_address = contract_address + self.contract = None + self.web3 = networks.provider._web3 + + if contract_address: + self.contract = project.PublicResolver.at(self.contract_address) + + def setAll( + self, + node: int, + address: AddressType, + content: str, + multihash: str, + x: int, + y: int, + name: str, + ) -> ReceiptAPI: + """ + * Sets all required params in one attempt + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param addr The address to set. + * @param content The content hash to set + * @param multihash The multihash to set + * @param x the X coordinate of the curve point for the public key. + * @param y the Y coordinate of the curve point for the public key. + * @param name The name to set. + """ + + """ + If x = b'abc' then f"{x}" or "{}".format(x) produces "b'abc'", not "abc". + If this is desired behavior, use f"{x!r}" or "{!r}".format(x). + Otherwise, decode the bytes + """ + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + self.address = address + self.content = content.encode("utf-8") + self.multihash = multihash.encode("utf-8") + self.x = x.to_bytes(32, byteorder="big") + self.y = y.to_bytes(32, byteorder="big") + self.name = name + + return self.contract.setAll( # type: ignore + self.node, + self.address, + self.content, + self.multihash, + self.x, + self.y, + self.name, + sender=self.account, + ) + + def getAll(self, node: int) -> Tuple: + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + + return self.contract.getAll(self.node) # type: ignore + + def setPublicKey(self, node: int, x: int, y: int) -> ReceiptAPI: + """ + * Sets the SECP256k1 public key associated with an ENS node. + * @param node The ENS node to query + * @param x the X coordinate of the curve point for the public key. + * @param y the Y coordinate of the curve point for the public key. + """ + if not self.account: + raise AccountNotSetUp("Set up user account first") + + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + self.x = x.to_bytes(32, byteorder="big") + self.y = y.to_bytes(32, byteorder="big") + + return self.contract.setPubkey(self.node, self.x, self.y, sender=self.account) # type: ignore # noqa: 501 + + def getPublicKey(self, node: int) -> Tuple[int, int]: + """ + * Returns the SECP256k1 public key associated with an ENS node. + * Defined in EIP 619. + * @param node The ENS node to query + * @return x, y the X and Y coordinates of the curve point for the public key. + """ + + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + + return self.contract.pubkey(self.node) # type: ignore + + def setMultiHash(self, node: int, _hash: str) -> ReceiptAPI: + """ + * Sets the multihash associated with an ENS node. + * May only be called by the owner of that node in the ENS registry. + * @param node The node to update. + * @param hash The multihash to set. + """ + if not self.account: + raise AccountNotSetUp("Set up user account first") + + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + self.hash = _hash.encode("utf-8") + + return self.contract.setMultihash(self.node, self.hash, sender=self.account) # type: ignore + + def getMultiHash(self, node: int) -> str: + """ + * Returns the multihash associated with an ENS node. + * @param node The ENS node to query. + * @return The associated multihash. + """ + self.node = f"0x{node.to_bytes(32, byteorder='big').hex()}" + + return convert(self.contract.multihash(self.node), str) # type: ignore diff --git a/src/fds/contracts/SubdomainRegistrar.py b/src/fds/contracts/SubdomainRegistrar.py new file mode 100644 index 0000000..e4e6693 --- /dev/null +++ b/src/fds/contracts/SubdomainRegistrar.py @@ -0,0 +1,60 @@ +""" +Copyright 2023 The FairDataSociety Authors +This file is part of the FairDataSociety library. + +The FairDataSociety library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +The FairDataSociety library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the FairDataSociety library. If not, see . + +handles SubdomainRegistrar contract +""" +from typing import Union + +from ape import networks, project +from ape.api.accounts import AccountAPI +from ape.api.transactions import ReceiptAPI +from ape.types import AddressType + + +class SubdomainRegistrarContractClass: + def __init__(self, account: AccountAPI, contract_address: Union[AddressType, None] = None): + self.account = account + self.contract_address = contract_address + self.contract = None + self.web3 = networks.provider._web3 + + if contract_address: + self.contract = project.SubdomainRegistrar.at(self.contract_address) + + def getRootNode(self) -> str: + return self.contract.rootNode() # type: ignore + + def register(self, label: int, owner_address: AddressType) -> ReceiptAPI: + """ + Register a name that's not currently registered + @param label The hash of the label to register. + @param owner The address of the new owner. + """ + + self.label = label.to_bytes(32, byteorder="big") + self.owner_address = owner_address + self.label = f"0x{self.label.hex()}" # type: ignore + + return self.contract.register(self.label, self.owner_address, sender=self.account) # type: ignore # noqa: 501 + + def getExpiryTime(self, label: int): + self.label = label.to_bytes(32, byteorder="big") + self.label = f"0x{self.label.hex()}" # type: ignore + + expiryTime = self.contract.expiryTimes(self.label) # type: ignore + + return expiryTime diff --git a/src/fds/contracts/multibox.py b/src/fds/contracts/multibox.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/fds/contracts/public_resolver.py b/src/fds/contracts/public_resolver.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/fds/contracts/subdomain_registrar.py b/src/fds/contracts/subdomain_registrar.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/fds/tests/conftest.py b/src/fds/tests/conftest.py index 3821973..0a5ccd1 100644 --- a/src/fds/tests/conftest.py +++ b/src/fds/tests/conftest.py @@ -235,15 +235,23 @@ def fdsContractDeploy(owner): @pytest.fixture def ensContract(owner): - contract = project.ENSRegistry.deploy(sender=owner) - - return contract + return project.ENSRegistry.deploy(sender=owner) @pytest.fixture def ENS(owner, ensContract): - contract = ensContract + return EnsRegistry(owner, ensContract.address) + + +@pytest.fixture +def subDomainRegistrarContract(owner, ensContract): + node = 1 + node = node.to_bytes(32, byteorder="big") + contract = project.SubdomainRegistrar.deploy(ensContract.address, node, sender=owner) + + return contract - ENS = EnsRegistry(owner, contract.address) - return ENS +@pytest.fixture +def publicResolverContract(owner, ensContract): + return project.PublicResolver.deploy(ensContract.address, sender=owner) diff --git a/src/fds/tests/unit_tests/test_ensregistry.py b/src/fds/tests/unit_tests/test_ensregistry.py index cebd686..60b206f 100644 --- a/src/fds/tests/unit_tests/test_ensregistry.py +++ b/src/fds/tests/unit_tests/test_ensregistry.py @@ -42,7 +42,7 @@ def test_set_n_get_ttl(ENS): assert ENS.getTTL(0) == 420 -def test_fail_setting_ttl(owner, receiver, ensContract): +def test_fail_setting_ttl(owner, ensContract): contract = ensContract ENS = EnsRegistry(owner, contract.address) diff --git a/src/fds/tests/unit_tests/test_public_resolver.py b/src/fds/tests/unit_tests/test_public_resolver.py new file mode 100644 index 0000000..86b9904 --- /dev/null +++ b/src/fds/tests/unit_tests/test_public_resolver.py @@ -0,0 +1,54 @@ +import pytest +from ape import convert +from ape.exceptions import ContractLogicError + +from fds.contracts.PublicResolver import PublicResolverClass + + +def test_set_all(owner, sender, publicResolverContract, ENS): + assert ENS.owner(0) == owner.address + + pubResClass = PublicResolverClass(owner, publicResolverContract.address) + + pubResClass.setAll(0, sender.address, "hahaha", "eeehahaha", 16, 17, "jadu") + + addr, content, multihash, x, y, name = pubResClass.getAll(0) + + assert addr == sender.address + assert content.decode().replace("\x00", "") == "hahaha" + assert multihash.decode().replace("\x00", "") == "eeehahaha" + assert convert(x, int) == 16 + assert convert(y, int) == 17 + assert name.replace("\x00", "") == "jadu" + + +def test_set_publickey(owner, publicResolverContract): + pubResClass = PublicResolverClass(owner, publicResolverContract.address) + node = 0 + pubResClass.setPublicKey(node, 22, 34) + + x, y = pubResClass.getPublicKey(node) + + assert convert(x, int) == 22 + assert convert(y, int) == 34 + + +# TODO: fixt this test +def test_multihash(owner, publicResolverContract): + pubResClass = PublicResolverClass(owner, publicResolverContract.address) + node = 0 + _hash = "fairDataProtocl" + pubResClass.setMultiHash(node, _hash) + + returned_hash = pubResClass.getMultiHash(node) + + assert returned_hash == _hash + + +def test_fail_set_publickey(owner, publicResolverContract): + pubResClass = PublicResolverClass(owner, publicResolverContract.address) + node = 1 + + with pytest.raises(ContractLogicError): + # * trying to access other node + pubResClass.setPublicKey(node, 22, 34) diff --git a/src/fds/tests/unit_tests/test_subdomain_register.py b/src/fds/tests/unit_tests/test_subdomain_register.py new file mode 100644 index 0000000..a0dd782 --- /dev/null +++ b/src/fds/tests/unit_tests/test_subdomain_register.py @@ -0,0 +1,20 @@ +import pytest +from ape.exceptions import ContractLogicError + +from fds.contracts.SubdomainRegistrar import SubdomainRegistrarContractClass + + +def test_load_ens_contract(owner, subDomainRegistrarContract): + contract = subDomainRegistrarContract + src = SubdomainRegistrarContractClass(owner, contract.address) + node = 1 + node = node.to_bytes(32, byteorder="big") + assert src.getRootNode() == node + + +def test_register(owner, ensContract): + src = SubdomainRegistrarContractClass(owner, ensContract.address) + + # ENS.setOwner(0, owner.address) + with pytest.raises(ContractLogicError): + src.register(0, owner.address) diff --git a/src/fds/utils/Exceptions.py b/src/fds/utils/Exceptions.py index 5b5f648..cb79ada 100644 --- a/src/fds/utils/Exceptions.py +++ b/src/fds/utils/Exceptions.py @@ -12,3 +12,7 @@ class ContractNotFoundException(Exception): class InaccessibleGatewayException(Exception): pass + + +class AccountNotSetUp(Exception): + pass