-
Notifications
You must be signed in to change notification settings - Fork 0
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
Conversation
class INetworkConfig(Protocol): | ||
chain_id: str | ||
|
||
|
||
class INetworkProvider(Protocol): | ||
def get_network_config(self) -> INetworkConfig: | ||
... |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is type: ignore
needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed anymore
multiversx_sdk/facades/config.py
Outdated
|
||
@dataclass | ||
class TestnetConfig: | ||
api = "https://testnet-api.multiversx.com" |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed
multiversx_sdk/facades/config.py
Outdated
@dataclass | ||
class TestnetConfig: | ||
api = "https://testnet-api.multiversx.com" | ||
kind = "api" |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed
multiversx_sdk/facades/errors.py
Outdated
@@ -0,0 +1,13 @@ | |||
class UnsuportedFileTypeError(Exception): |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 @@ | |||
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)) |
There was a problem hiding this comment.
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)?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
self.provider = network_provider | ||
self.factory = DelegationTransactionsFactory(TransactionsFactoryConfig(chain_id)) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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:
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)) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to Account
.
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) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀
retries = 10 | ||
while retries: | ||
time.sleep(0.5) | ||
try: | ||
self.entrypoint.await_completed_transaction(tx_hash) | ||
break | ||
except: | ||
retries -= 1 |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
Implemented the
facade
andcontrollers
based on the specs.