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

Handle proxy error #413

Merged
merged 4 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions multiversx_sdk_cli/cli_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any, Dict, List, Text, cast

from multiversx_sdk_core import Address
from multiversx_sdk_network_providers import GenericError
from multiversx_sdk_network_providers.proxy_network_provider import \
ProxyNetworkProvider

Expand All @@ -16,7 +17,7 @@
load_password)
from multiversx_sdk_cli.constants import (DEFAULT_TX_VERSION,
TRANSACTION_OPTIONS_TX_GUARDED)
from multiversx_sdk_cli.errors import ArgumentsNotProvidedError
from multiversx_sdk_cli.errors import ArgumentsNotProvidedError, ProxyError
from multiversx_sdk_cli.interfaces import ITransaction
from multiversx_sdk_cli.ledger.ledger_functions import do_get_ledger_address
from multiversx_sdk_cli.simulation import Simulator
Expand Down Expand Up @@ -268,8 +269,15 @@ def send_or_simulate(tx: ITransaction, args: Any, dump_output: bool = True) -> C
transaction_on_network = send_and_wait_for_result(tx, proxy, args.timeout)
output_builder.set_awaited_transaction(transaction_on_network)
elif send_only:
hash = proxy.send_transaction(tx)
output_builder.set_emitted_transaction_hash(hash)
try:
hash = proxy.send_transaction(tx)
output_builder.set_emitted_transaction_hash(hash)
except GenericError as ge:
url = ge.url
message = ge.data["error"]
data = ge.data["data"]
code = ge.data["code"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Just in case, perhaps use ge.get("...", "")?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

raise ProxyError(message, url, data, code)
elif simulate:
simulation = Simulator(proxy).run(tx)
output_builder.set_simulation_results(simulation)
Expand Down
11 changes: 9 additions & 2 deletions multiversx_sdk_cli/cli_transactions.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from pathlib import Path
from typing import Any, List

from multiversx_sdk_network_providers import GenericError
from multiversx_sdk_network_providers.proxy_network_provider import \
ProxyNetworkProvider

from multiversx_sdk_cli import cli_shared, utils
from multiversx_sdk_cli.cli_output import CLIOutputBuilder
from multiversx_sdk_cli.cosign_transaction import cosign_transaction
from multiversx_sdk_cli.errors import NoWalletProvided
from multiversx_sdk_cli.errors import NoWalletProvided, ProxyError
from multiversx_sdk_cli.transactions import (compute_relayed_v1_data,
do_prepare_transaction,
load_transaction_from_file)
Expand Down Expand Up @@ -88,11 +89,17 @@ def send_transaction(args: Any):

tx = load_transaction_from_file(args.infile)
output = CLIOutputBuilder()
proxy = ProxyNetworkProvider(args.proxy)

Copy link
Contributor

Choose a reason for hiding this comment

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

Try / finally was good here - so that the user sees the emitted transaction even if the send fails with exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. Added.

try:
proxy = ProxyNetworkProvider(args.proxy)
tx_hash = proxy.send_transaction(tx)
output.set_emitted_transaction_hash(tx_hash)
except GenericError as ge:
url = ge.url
message = ge.data["error"]
data = ge.data["data"]
code = ge.data["code"]
raise ProxyError(message, url, data, code)
finally:
output = output.set_emitted_transaction(tx).build()
utils.dump_out_json(output, outfile=args.outfile)
Expand Down
1 change: 1 addition & 0 deletions multiversx_sdk_cli/cli_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def wallet_new(args: Any):

mnemonic = Mnemonic.generate()
print(f"Mnemonic: {mnemonic.get_text()}")
print(f"Wallet address: {mnemonic.derive_key().generate_public_key().to_address(address_hrp).to_bech32()}")
Copy link
Contributor

Choose a reason for hiding this comment

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

Hopefully, not a breaking change for some users 🤞

People who rely on a more structured output should use the outfile argument.


if format is None:
return
Expand Down
10 changes: 10 additions & 0 deletions multiversx_sdk_cli/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,13 @@ def __init__(self, message: str):
class ArgumentsNotProvidedError(KnownError):
def __init__(self, message: str):
super().__init__(message)


class ProxyError(KnownError):
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

def __init__(self, message: str, url: str, data: str, code: str):
inner = {
"url": url,
"data": data,
"code": code
}
super().__init__(message, inner)
3 changes: 2 additions & 1 deletion multiversx_sdk_cli/tests/test_cli_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,8 @@ def test_sign_and_verify_message_with_multi_address_pem(capsys: Any):


def _read_stdout_mnemonic(capsys: Any) -> str:
return _read_stdout(capsys).replace("Mnemonic:", "").strip()
lines = _read_stdout(capsys).split("\n")
return lines[0].replace("Mnemonic:", "").strip()


def _read_stdout(capsys: Any) -> str:
Expand Down
15 changes: 12 additions & 3 deletions multiversx_sdk_cli/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import time
from typing import Any, Dict, Optional, Protocol, Sequence, TextIO, Tuple

from multiversx_sdk_core import Address, Transaction, TransactionPayload

Check failure on line 7 in multiversx_sdk_cli/transactions.py

View workflow job for this annotation

GitHub Actions / runner / mypy

[mypy] reported by reviewdog 🐶 Skipping analyzing "multiversx_sdk_core": module is installed, but missing library stubs or py.typed marker [import-untyped] Raw Output: /home/runner/work/mx-sdk-py-cli/mx-sdk-py-cli/multiversx_sdk_cli/transactions.py:7:1: error: Skipping analyzing "multiversx_sdk_core": module is installed, but missing library stubs or py.typed marker [import-untyped]
from multiversx_sdk_network_providers import GenericError

Check failure on line 8 in multiversx_sdk_cli/transactions.py

View workflow job for this annotation

GitHub Actions / runner / mypy

[mypy] reported by reviewdog 🐶 Skipping analyzing "multiversx_sdk_network_providers": module is installed, but missing library stubs or py.typed marker [import-untyped] Raw Output: /home/runner/work/mx-sdk-py-cli/mx-sdk-py-cli/multiversx_sdk_cli/transactions.py:8:1: error: Skipping analyzing "multiversx_sdk_network_providers": module is installed, but missing library stubs or py.typed marker [import-untyped]

from multiversx_sdk_cli import errors
from multiversx_sdk_cli.accounts import Account, LedgerAccount
from multiversx_sdk_cli.cli_password import (load_guardian_password,
load_password)
from multiversx_sdk_cli.cosign_transaction import cosign_transaction
from multiversx_sdk_cli.errors import NoWalletProvided
from multiversx_sdk_cli.errors import NoWalletProvided, ProxyError
from multiversx_sdk_cli.interfaces import ITransaction
from multiversx_sdk_cli.ledger.ledger_functions import do_get_ledger_address

Expand All @@ -30,7 +31,7 @@
def send_transaction(self, transaction: ITransaction) -> str:
...

def send_transactions(self, transactions: Sequence[ITransaction]) -> Tuple[int, str]:
def send_transactions(self, transactions: Sequence[ITransaction]) -> Tuple[int, Dict[str, str]]:
...

def get_transaction(self, tx_hash: str, with_process_status: Optional[bool] = False) -> ITransactionOnNetwork:
Expand Down Expand Up @@ -132,7 +133,15 @@
def _send_transaction_and_wait_for_result(proxy: INetworkProvider, payload: ITransaction, num_seconds_timeout: int = 100) -> ITransactionOnNetwork:
AWAIT_TRANSACTION_PERIOD = 5

tx_hash = proxy.send_transaction(payload)
try:
tx_hash = proxy.send_transaction(payload)
except GenericError as ge:
url = ge.url
message = ge.data["error"]
data = ge.data["data"]
code = ge.data["code"]
raise ProxyError(message, url, data, code)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we have this in several places now, perhaps use the decorator pattern, and do a custom proxy provider e.g. CustomNetworkProvider(ProxyNetworkProvider) that overrides this function, catches & re-throws?

Alternatively, catch multiversx_sdk_network_providers.GenericError in cli.py, in the main function, and handle it there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created a CustomNetworkProvider.


num_periods_to_wait = int(num_seconds_timeout / AWAIT_TRANSACTION_PERIOD)

for _ in range(0, num_periods_to_wait):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "multiversx-sdk-cli"
version = "9.5.0"
version = "9.5.1"
authors = [
{ name="MultiversX" },
]
Expand Down
Loading