Skip to content

Commit

Permalink
Handle custom errors from subtensor
Browse files Browse the repository at this point in the history
  • Loading branch information
thewhaleking committed Sep 19, 2024
1 parent 6fa457f commit e9492d2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 16 deletions.
8 changes: 6 additions & 2 deletions bittensor_cli/src/bittensor/extrinsics/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,10 @@ async def get_neuron_for_pubkey_and_subnet():
if not await response.is_success:
success, err_msg = (
False,
format_error_message(await response.error_message),
format_error_message(
await response.error_message,
substrate=subtensor.substrate,
),
)

if not success:
Expand Down Expand Up @@ -786,7 +789,8 @@ async def run_faucet_extrinsic(
await response.process_events()
if not await response.is_success:
err_console.print(
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message)}"
f":cross_mark: [red]Failed[/red]: "
f"{format_error_message(await response.error_message, subtensor.substrate)}"
)
if attempts == max_allowed_attempts:
raise MaxAttemptsException
Expand Down
4 changes: 3 additions & 1 deletion bittensor_cli/src/bittensor/subtensor_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,9 @@ async def sign_and_send_extrinsic(
if await response.is_success:
return True, ""
else:
return False, format_error_message(await response.error_message)
return False, format_error_message(
await response.error_message, substrate=self.substrate
)
except SubstrateRequestException as e:
return False, e

Expand Down
64 changes: 54 additions & 10 deletions bittensor_cli/src/bittensor/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

if TYPE_CHECKING:
from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
from bittensor_cli.src.bittensor.async_substrate_interface import (
AsyncSubstrateInterface,
)

console = Console()
err_console = Console(stderr=True)
Expand Down Expand Up @@ -442,24 +445,65 @@ def get_explorer_url_for_network(
return explorer_urls


def format_error_message(error_message: dict) -> str:
def format_error_message(
error_message: dict, substrate: "AsyncSubstrateInterface"
) -> str:
"""
Formats an error message from the Subtensor error information to using in extrinsics.
Formats an error message from the Subtensor error information for use in extrinsics.
:param error_message: A dictionary containing the error information from Subtensor.
Args:
error_message: A dictionary containing the error information from Subtensor.
substrate: The substrate interface to use.
:return: A formatted error message string.
Returns:
str: A formatted error message string.
"""
err_type = "UnknownType"
err_name = "UnknownError"
err_type = "UnknownType"
err_description = "Unknown Description"

if isinstance(error_message, dict):
err_type = error_message.get("type", err_type)
err_name = error_message.get("name", err_name)
err_docs = error_message.get("docs", [])
err_description = err_docs[0] if len(err_docs) > 0 else err_description
return f"Subtensor returned `{err_name} ({err_type})` error. This means: `{err_description}`"
# subtensor error structure
if (
error_message.get("code")
and error_message.get("message")
and error_message.get("data")
):
err_name = "SubstrateRequestException"
err_type = error_message.get("message", "")
err_data = error_message.get("data", "")

# subtensor custom error marker
if err_data.startswith("Custom error:") and substrate:
if substrate.metadata:
try:
pallet = substrate.metadata.get_metadata_pallet(
"SubtensorModule"
)
error_index = int(err_data.split("Custom error:")[-1])

error_dict = pallet.errors[error_index].value
err_type = error_dict.get("message", err_type)
err_docs = error_dict.get("docs", [])
err_description = err_docs[0] if err_docs else err_description
except AttributeError:
err_console.print(
"Substrate pallets data unavailable. This is usually caused by an uninitialized substrate."
)
else:
err_description = err_data

elif (
error_message.get("type")
and error_message.get("name")
and error_message.get("docs")
):
err_type = error_message.get("type", err_type)
err_name = error_message.get("name", err_name)
err_docs = error_message.get("docs", [err_description])
err_description = err_docs[0] if err_docs else err_description

return f"Subtensor returned `{err_name}({err_type})` error. This means: `{err_description}`."


def convert_blocks_to_time(blocks: int, block_time: int = 12) -> tuple[int, int, int]:
Expand Down
2 changes: 1 addition & 1 deletion bittensor_cli/src/commands/subnets.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async def _find_event_attributes_in_extrinsic_receipt(
await response.process_events()
if not await response.is_success:
err_console.print(
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message)}"
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message, substrate)}"
)
await asyncio.sleep(0.5)
return False
Expand Down
8 changes: 6 additions & 2 deletions bittensor_cli/src/commands/weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ async def _do_set_weights():
if await response.is_success:
return True, "Successfully set weights."
else:
return False, format_error_message(await response.error_message)
return False, format_error_message(
await response.error_message, self.subtensor.substrate
)

with console.status(
f":satellite: Setting weights on [white]{self.subtensor.network}[/white] ..."
Expand Down Expand Up @@ -327,7 +329,9 @@ async def reveal_weights_extrinsic(
else:
success, error_message = (
False,
format_error_message(await response.error_message),
format_error_message(
await response.error_message, self.subtensor.substrate
),
)

if success:
Expand Down

0 comments on commit e9492d2

Please sign in to comment.