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

Add gas estimation and retries #24

Merged
merged 4 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
sudo apt-get update --fix-missing
sudo apt-get autoremove
sudo apt-get autoclean
pip install tomte[tox]==0.2.14
pip install tomte[tox]==0.2.15
pip install --user --upgrade setuptools
sudo npm install -g markdown-spellcheck
- name: Security checks
Expand Down
2 changes: 1 addition & 1 deletion mech_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Mech client."""

__version__ = "0.2.8"
__version__ = "0.2.9"
23 changes: 22 additions & 1 deletion mech_client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,30 @@ def cli() -> None:
),
help="Data verification method (on-chain/off-chain)",
)
def interact(
@click.option(
"--retries",
type=int,
help="Number of retries for sending a transaction",
)
@click.option(
"--timeout",
type=float,
help="Timeout to wait for the transaction",
)
@click.option(
"--sleep",
type=float,
help="Amount of sleep before retrying the transaction",
)
def interact( # pylint: disable=too-many-arguments
prompt: str,
agent_id: int,
tool: Optional[str],
key: Optional[str],
confirm: Optional[str] = None,
retries: Optional[int] = None,
timeout: Optional[float] = None,
sleep: Optional[float] = None,
) -> None:
"""Interact with a mech specifying a prompt and tool."""
try:
Expand All @@ -76,6 +94,9 @@ def interact(
if confirm is not None
else ConfirmationType.WAIT_FOR_BOTH
),
retries=retries,
timeout=timeout,
sleep=sleep,
)
except (ValueError, FileNotFoundError) as e:
raise click.ClickException(str(e)) from e
Expand Down
71 changes: 59 additions & 12 deletions mech_client/interact.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import asyncio
import json
import os
import time
import warnings
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any, List, Optional, Tuple
Expand Down Expand Up @@ -63,6 +65,7 @@
"chain_id": 100,
"poa_chain": False,
"default_gas_price_strategy": "eip1559",
"is_gas_estimation_enabled": True,
angrybayblade marked this conversation as resolved.
Show resolved Hide resolved
}
PRIVATE_KEY_FILE_PATH = "ethereum_private_key.txt"

Expand All @@ -72,6 +75,10 @@
)
GNOSISSCAN_API_URL = "https://api.gnosisscan.io/api?module=contract&action=getabi&address={contract_address}"

MAX_RETRIES = 3
WAIT_SLEEP = 3.0
TIMEOUT = 60.0

# Ignore a specific warning message
warnings.filterwarnings("ignore", "The log with transaction hash.*")

Expand Down Expand Up @@ -179,13 +186,16 @@ def fetch_tools(agent_id: int, ledger_api: EthereumApi) -> List[str]:
return response["tools"]


def send_request( # pylint: disable=too-many-arguments
def send_request( # pylint: disable=too-many-arguments,too-many-locals
crypto: EthereumCrypto,
ledger_api: EthereumApi,
mech_contract: Web3Contract,
prompt: str,
tool: str,
price: int = 10_000_000_000_000_000,
retries: Optional[int] = None,
timeout: Optional[float] = None,
sleep: Optional[float] = None,
) -> None:
"""
Sends a request to the mech.
Expand All @@ -202,22 +212,47 @@ def send_request( # pylint: disable=too-many-arguments
:type tool: str
:param price: The price for the request (default: 10_000_000_000_000_000).
:type price: int
:param retries: Number of retries for sending a transaction
:type retries: int
:param timeout: Timeout to wait for the transaction
:type timeout: float
:param sleep: Amount of sleep before retrying the transaction
:type sleep: float
"""
v1_file_hash_hex_truncated, v1_file_hash_hex = push_metadata_to_ipfs(prompt, tool)
print(f"Prompt uploaded: https://gateway.autonolas.tech/ipfs/{v1_file_hash_hex}")
method_name = "request"
methord_args = {"data": v1_file_hash_hex_truncated}
tx_args = {"sender_address": crypto.address, "value": price}
raw_transaction = ledger_api.build_transaction(
contract_instance=mech_contract,
method_name=method_name,
method_args=methord_args,
tx_args=tx_args,
)
raw_transaction["gas"] = 50_000
angrybayblade marked this conversation as resolved.
Show resolved Hide resolved
signed_transaction = crypto.sign_transaction(raw_transaction)
transaction_digest = ledger_api.send_signed_transaction(signed_transaction)
print(f"Transaction sent: https://gnosisscan.io/tx/{transaction_digest}")

tries = 0
retries = retries or MAX_RETRIES
timeout = timeout or TIMEOUT
sleep = sleep or WAIT_SLEEP
deadline = datetime.now().timestamp() + timeout

while tries < retries and datetime.now().timestamp() < deadline:
tries += 1
try:
raw_transaction = ledger_api.build_transaction(
contract_instance=mech_contract,
method_name=method_name,
method_args=methord_args,
tx_args=tx_args,
raise_on_try=True,
)
signed_transaction = crypto.sign_transaction(raw_transaction)
transaction_digest = ledger_api.send_signed_transaction(
signed_transaction,
raise_on_try=True,
)
print(f"Transaction sent: https://gnosisscan.io/tx/{transaction_digest}")
return
except Exception as e: # pylint: disable=broad-except
print(
f"Error occured while sending the transaction: {e}; Retrying in {sleep}"
)
time.sleep(sleep)


def wait_for_data_url(
Expand Down Expand Up @@ -269,12 +304,15 @@ async def _wait_for_tasks() -> Any: # type: ignore
return result


def interact(
def interact( # pylint: disable=too-many-arguments,too-many-locals
prompt: str,
agent_id: int,
tool: Optional[str] = None,
private_key_path: Optional[str] = None,
confirmation_type: ConfirmationType = ConfirmationType.WAIT_FOR_BOTH,
retries: Optional[int] = None,
timeout: Optional[float] = None,
sleep: Optional[float] = None,
) -> Any:
"""
Interact with agent mech contract.
Expand All @@ -290,6 +328,12 @@ def interact(
:param confirmation_type: The confirmation type for the interaction (default: ConfirmationType.WAIT_FOR_BOTH).
:type confirmation_type: ConfirmationType
:return: The data received from on-chain/off-chain.
:param retries: Number of retries for sending a transaction
:type retries: int
:param timeout: Timeout to wait for the transaction
:type timeout: float
:param sleep: Amount of sleep before retrying the transaction
:type sleep: float
:rtype: Any
"""
contract_address = query_agent_address(agent_id=agent_id)
Expand Down Expand Up @@ -317,6 +361,9 @@ def interact(
mech_contract=mech_contract,
prompt=prompt,
tool=tool,
retries=retries,
timeout=timeout,
sleep=sleep,
)
request_id = watch_for_request_id(
wss=wss, mech_contract=mech_contract, ledger_api=ledger_api
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mech-client"
version = "0.2.8"
version = "0.2.9"
description = "Basic client to interact with a mech"
authors = ["David Minarsch <[email protected]>"]
readme = "README.md"
Expand Down Expand Up @@ -39,7 +39,7 @@ mechx = "mech_client.cli:cli"

[tool.poetry.group.dev.dependencies]
open-autonomy = "==0.13.8"
tomte = {extras = ["tox"], version = "==0.2.14"}
tomte = {extras = ["tox"], version = "==0.2.15"}

[build-system]
requires = ["poetry-core"]
Expand Down
27 changes: 18 additions & 9 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,45 @@ deps =
[testenv:bandit]
skipsdist = True
skip_install = True
deps = tomte[bandit]==0.2.14
deps =
tomte[bandit]==0.2.15
commands =
bandit -s B101 -r mech_client/

[testenv:black]
skipsdist = True
skip_install = True
deps = tomte[black]==0.2.14
deps =
tomte[black]==0.2.15
commands = black mech_client/

[testenv:black-check]
skipsdist = True
skip_install = True
deps = tomte[black]==0.2.14
deps =
tomte[black]==0.2.15
commands = black --check mech_client/

[testenv:isort]
skipsdist = True
skip_install = True
deps = tomte[isort]==0.2.14
deps =
tomte[isort]==0.2.15
commands =
isort mech_client/ --gitignore

[testenv:isort-check]
skipsdist = True
skip_install = True
deps = tomte[isort]==0.2.14
deps =
tomte[isort]==0.2.15
commands = isort --check-only --gitignore mech_client/

[testenv:flake8]
skipsdist = True
skip_install = True
deps = tomte[flake8]==0.2.14
deps =
tomte[flake8]==0.2.15
commands =
flake8 mech_client/

Expand All @@ -65,13 +71,15 @@ commands = pylint --ignore-patterns=".*_pb2.py" --ignore-paths="^packages/valory
[testenv:safety]
skipsdist = True
skip_install = True
deps = tomte[safety]==0.2.14
deps =
tomte[safety]==0.2.15
commands = safety check -i 37524 -i 38038 -i 37776 -i 38039 -i 39621 -i 40291 -i 39706 -i 41002 -i 51358 -i 51499

[testenv:darglint]
skipsdist = True
skip_install = True
deps = tomte[darglint]==0.2.14
deps =
tomte[darglint]==0.2.15
commands = darglint mech_client

[testenv:vulture]
Expand All @@ -86,7 +94,8 @@ commands =
whitelist_externals = mdspell
skipsdist = True
usedevelop = True
deps = tomte[cli]==0.2.14
deps =
tomte[cli]==0.2.15
commands = tomte check-spelling

[flake8]
Expand Down
Loading