Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Facade implementation #88

Merged
merged 20 commits into from
Sep 9, 2024
Merged

Facade implementation #88

merged 20 commits into from
Sep 9, 2024

Conversation

popenta
Copy link
Collaborator

@popenta popenta commented Aug 13, 2024

Implemented the facade and controllers based on the specs.

@popenta popenta self-assigned this Aug 13, 2024
Copy link

github-actions bot commented Aug 13, 2024

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  multiversx_sdk
  __init__.py
  multiversx_sdk/controllers
  __init__.py
  account_controller.py 13-14, 20-28, 35-44, 49-56, 61-68
  delegation_controller.py 25-28, 36-46, 50-53, 56-57, 65-75, 82-91, 98-107, 114-123, 130-139, 147-157, 164-173, 180-189, 195-203, 209-217, 223-231, 237-245, 254-265, 272-281, 287-295, 301-309, 316-325, 331-339
  interfaces.py 9, 12
  network_provider_wrapper.py 14
  relayed_controller.py 22-30, 37-46
  smart_contract_controller.py 26, 29, 32, 35, 38, 48, 53, 58, 61, 64, 67, 132-148, 175, 178
  token_management_controller.py 30-34, 49-66, 69-70, 73-74, 88-104, 107-108, 111-112, 126-142, 145-146, 149-150, 165-182, 185-186, 189-190, 199-210, 213-214, 217-218, 224-232, 235-236, 239-240, 246-254, 257-258, 261-262, 272-284, 287-288, 291-292, 303-316, 319-320, 323-324, 336-350, 353-354, 357-358, 370-384, 387-388, 391-392, 398-406, 409-410, 413-414, 420-428, 431-432, 435-436, 443-452, 455-456, 459-460, 467-476, 479-480, 483-484, 491-500, 503-504, 507-508, 515-524, 527-528, 531-532, 539-548, 551-552, 555-556, 564-574, 577-578, 581-582, 590-600, 603-604, 607-608, 616-626, 629-630, 633-634
  transfers_controller.py 23-33, 40-49
  multiversx_sdk/core
  __init__.py
  multiversx_sdk/core/transactions_outcome_parsers
  __init__.py
  multiversx_sdk/facades
  __init__.py
  account.py 26-28, 35-37
  config.py
  entrypoints.py 33, 36, 39, 42, 51, 55, 61-62, 65-68, 75-76, 79-85, 103, 114, 117, 120, 129, 137-141, 155-159, 168
  errors.py 3, 8
  multiversx_sdk/network_providers
  api_network_provider.py
Project Total  

This report was generated by python-coverage-comment-action

Comment on lines 12 to 18
class INetworkConfig(Protocol):
chain_id: str


class INetworkProvider(Protocol):
def get_network_config(self) -> INetworkConfig:
...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context, I think we can move these interfaces (defined a few times) directly in core/controllers/interfaces.py.

Later edit: by receiving the chain_id directly in controllers (see below), these won't be needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it.


def _ensure_factory_is_initialized(self):
if self.factory is None:
self.chain_id = self.provider.get_network_config().chain_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's receive chain_id directly in constructor, maybe? Here, and in other controllers. Then, I think we won't need the network provider in the controller anymore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, now passing chain_id in the constructor of the controllers.

service_id: str) -> Transaction:
self._ensure_factory_is_initialized()

transaction = self.factory.create_transaction_for_setting_guardian( # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is type: ignore needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed anymore


@dataclass
class TestnetConfig:
api = "https://testnet-api.multiversx.com"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be network_provider_url.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

@dataclass
class TestnetConfig:
api = "https://testnet-api.multiversx.com"
kind = "api"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be network_provider_kind (I think).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

@@ -0,0 +1,13 @@
class UnsuportedFileTypeError(Exception):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it used? Can be dropped if not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

def get_network_config(self) -> INetworkConfig:
...

def query_contract(self, query: IQuery) -> IQueryResponse:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In feat/next, we should drop the old types on queries (cleanup), and only use the new ones:

https://github.com/multiversx/mx-sdk-py/blob/main/multiversx_sdk/core/smart_contract_query.py

If possible, can adjust the network provider in this PR, otherwise, should be done in a future PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do it in a future PR.

@@ -0,0 +1,163 @@

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few short unit tests would be nice. Can be based on the examples from the specs (but not necessarily):

https://github.com/multiversx/mx-sdk-specs/blob/main/facades/entrypoints.md#examples

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a few.

)

transaction.nonce = nonce
transaction.signature = sender.sign(self.tx_computer.compute_bytes_for_signing(transaction))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can have a base class for controllers, which holds common functionality - e.g a private function to sign transactions (just an idea)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will keep it in mind as it could be a good idea, but as of now I don't think it is necessary.

pass

def await_completed_execute(self, tx_hash: str):
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not implemented, perhaps throw an exception? Here & above?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

from multiversx_sdk.converters.transactions_converter import \
TransactionsConverter
from multiversx_sdk.core.interfaces import IAddress, IValidatorPublicKey
from multiversx_sdk.core.transaction import Transaction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on imports I would've group imports based on their namespace, for example
from multiversx_sdk.core.transactions_outcome_parsers import DelegationTransactionsOutcomeParser, CreateNewDelegationContractOutcome

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did some of them, will probably do the same in all the files in the future PRs.

danielailie
danielailie previously approved these changes Sep 5, 2024
self.provider = network_provider
self.factory = DelegationTransactionsFactory(TransactionsFactoryConfig(chain_id))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.provider was removed from the other controllers. Is it required in this one?

Copy link
Collaborator Author

@popenta popenta Sep 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not. Removed it from all controllers.

self.chain_id: Union[str, None] = None
self.factory: Union[DelegationTransactionsFactory, None] = None
self.parser = DelegationTransactionsOutcomeParser()
def __init__(self, chain_id: str, network_provider: Any) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is network_provider: Any necessary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, we'll use a temporary interface until the upcoming change for the network providers.

def parse_execute(self, transaction_on_network: TransactionOnNetwork, function: Optional[str] = None):
pass
def parse_execute(self, transaction_on_network: TransactionOnNetwork, function: Optional[str] = None) -> List[Any]:
raise NotImplementedError("This method is not yet implemented")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. We'll see how to use this in the future:

multiversx/mx-chain-proxy-go#446

tx_computer = TransactionComputer()
transaction.signature = signer.sign(tx_computer.compute_bytes_for_signing(transaction))
transaction.signature = account.sign(tx_computer.compute_bytes_for_signing(transaction))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type is still UserSigner, is this intended?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to Account.

Comment on lines 35 to 51
abi = Abi.load(testutils / "testdata" / "adder.abi.json")
sender = Account.new_from_pem(self.alice_pem)
sender.nonce = self.entrypoint.recall_account_nonce(sender.address)

controller = self.entrypoint.create_smart_contract_controller(abi)
bytecode = (testutils / "testdata" / "adder.wasm").read_bytes()
transaction = controller.create_transaction_for_deploy(
sender=sender,
nonce=sender.get_nonce_then_increment(),
bytecode=bytecode,
gas_limit=10_000_000,
arguments=[0]
)

tx_hash = self.entrypoint.send_transaction(transaction)
outcome = controller.await_completed_deploy(tx_hash)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Comment on lines 67 to 74
retries = 10
while retries:
time.sleep(0.5)
try:
self.entrypoint.await_completed_transaction(tx_hash)
break
except:
retries -= 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is needed.

Perhaps due a possible 404 transaction not found when invoking await_completed_transaction immediately after send_transaction? If so, let's add a trivial sleep after broadcasting the transaction.

We should make the transaction completion awaiting a bit more robust (in the future, separate PR).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it was due to a 404 error. Added a simple time.sleep(1). Will make the transaction awaiting more robust in the future.

@popenta popenta merged commit 8552aaf into feat/next Sep 9, 2024
7 checks passed
@popenta popenta deleted the facade branch September 9, 2024 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants