From 3b4e40030837a8e1907a7c37d64ead8b12a80dd6 Mon Sep 17 00:00:00 2001 From: Ardian Date: Tue, 21 Nov 2023 19:57:31 +0100 Subject: [PATCH 1/8] feat: add funds splitting logic --- .gitignore | 1 + .../skills/task_submission_abci/behaviours.py | 180 ++++++++++++++++++ .../skills/task_submission_abci/models.py | 2 + .../skills/task_submission_abci/skill.yaml | 2 + 4 files changed, 185 insertions(+) diff --git a/.gitignore b/.gitignore index 595566b2..41b47dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ leak_report agent/ backup_mech/ +/packages/valory/skills/termination_abci/ diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index d5f04052..0a290b9b 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -39,7 +39,9 @@ MultiSendContract, MultiSendOperation, ) +from packages.valory.contracts.service_registry.contract import ServiceRegistryContract from packages.valory.protocols.contract_api import ContractApiMessage +from packages.valory.protocols.ledger_api import LedgerApiMessage from packages.valory.skills.abstract_round_abci.base import AbstractRound from packages.valory.skills.abstract_round_abci.behaviours import ( AbstractRoundBehaviour, @@ -392,6 +394,184 @@ def _get_mech_update_hash_tx(self) -> Generator: "data": data, } + def _get_transfer_txs(self) -> Generator: + """Get the transfer txs.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(AgentRegistryContract.contract_id), + contract_callable="get_transfer_txs", + token_id=self.params.agent_id, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_transfer_txs unsuccessful!: {contract_api_msg}" + ) + return None + + def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: + """Return the total number of requests delivered.""" + reqs_by_agent = yield from self._get_num_reqs_by_agent() + if reqs_by_agent is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + total_reqs = sum(reqs_by_agent.values()) + return total_reqs + + def _get_num_reqs_by_agent(self) -> Generator[None, None, Dict[str, int]]: + """Return the total number of requests delivered.""" + # TODO: implement once the storage is ready + return { + "agent0": 0, + "agent1": 1, + "agent2": 2, + "agent3": 3, + } + yield + + def _should_split_profits(self) -> Generator[None, None, bool]: + """ + Returns true if profits from the mech should be split. + + Profits will be split based on the number of requests that have been delivered. + I.e. We will be splitting every n-th request. Where, n- is configurable + + :returns: True if profits should be split, False otherwise. + :yields: None + """ + total_reqs = yield from self._get_num_requests_delivered() + if total_reqs is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return False + return total_reqs % self.params.profit_split_freq == 0 + + def _get_profits(self, address: str) -> Generator[None, None, int]: + """Get the profits.""" + ledger_api_response = yield from self.get_ledger_api_response( + performative=LedgerApiMessage.Performative.GET_STATE, + ledger_callable="get_balance", + account=address, + ) + if ledger_api_response.performative != LedgerApiMessage.Performative.STATE: + return False # transition to await top-up round + balance = cast(int, ledger_api_response.state.body.get("get_balance_result")) + return balance + + def _split_funds(self, profits: int) -> Generator[None, None, Optional[Dict[str, int]]]: + """ + Split the funds among the operators based on the number of txs their agents have made. + + :param profits: the amount of funds to split. + :returns: a dictionary mapping operator addresses to the amount of funds they should receive. + :yields: None + """ + service_owner = yield from self._get_service_owner(self.params.on_chain_service_id) + if service_owner is None: + self.context.logger.warning( + "Could not get service owner. Don't split profits." + ) + return None + + funds_by_address = {} + service_owner_share = int(self.params.service_owner_share * profits) + funds_by_address[service_owner] = service_owner_share + + operator_share = profits - service_owner_share + funds_by_operator = yield from self._get_funds_by_operator(operator_share) + if funds_by_operator is None: + self.context.logger.warning( + "Could not get funds by operator. Don't split profits." + ) + return None + + # accumulate the funds + funds_by_address.update(funds_by_operator) + return funds_by_address + + def _get_service_owner(self, service_id: int) -> Generator[None, None, Optional[str]]: + """Get the service owner address.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, + contract_address=self.params.service_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_service_owner", + service_id=service_id, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): + self.context.logger.warning( + f"get_service_owner unsuccessful!: {contract_api_msg}" + ) + return None + return cast(str, contract_api_msg.state.body["service_owner"]) + + + def _get_funds_by_operator(self, operator_share: int) -> Generator[None, None, Optional[Dict[str, int]]]: + """Split the funds among the operators based on the number of txs their agents have made.""" + reqs_by_agent = yield from self._get_num_reqs_by_agent() + if reqs_by_agent is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + total_reqs = sum(reqs_by_agent.values()) + if total_reqs == 0: + # nothing to split + return { + agent: 0 + for agent in reqs_by_agent.keys() + } + + accumulated_reqs_by_operator = yield from self._accumulate_reqs_by_operator(reqs_by_agent) + if accumulated_reqs_by_operator is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + for agent, reqs in accumulated_reqs_by_operator.items(): + accumulated_reqs_by_operator[agent] = int(operator_share * (reqs / total_reqs)) + + return accumulated_reqs_by_operator + + def _accumulate_reqs_by_operator(self, reqs_by_agent: Dict[str, int]) -> Generator[None, None, Optional[Dict[str, int]]]: + """Accumulate requests by operator.""" + agent_instances = list(reqs_by_agent.keys()) + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_operators_mapping", + agent_instances=agent_instances, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_operators_mapping unsuccessful!: {contract_api_msg}" + ) + return None + agent_to_operator = cast(Dict[str, str], contract_api_msg.state.body) + + # accumulate reqs by operator + reqs_by_operator = {} + for agent, reqs in reqs_by_agent.items(): + operator = agent_to_operator[agent] + if operator not in reqs_by_operator: + reqs_by_operator[operator] = reqs + else: + reqs_by_operator[operator] += reqs + return reqs_by_operator + class TaskSubmissionRoundBehaviour(AbstractRoundBehaviour): """TaskSubmissionRoundBehaviour""" diff --git a/packages/valory/skills/task_submission_abci/models.py b/packages/valory/skills/task_submission_abci/models.py index ae731bfd..a00ef15a 100644 --- a/packages/valory/skills/task_submission_abci/models.py +++ b/packages/valory/skills/task_submission_abci/models.py @@ -64,6 +64,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.metadata_hash: str = self._ensure("metadata_hash", kwargs, str) self.task_mutable_params = MutableParams() self.manual_gas_limit = self._ensure("manual_gas_limit", kwargs, int) + self.service_owner_share = self._ensure("service_owner_share", kwargs, float) + self.profit_split_freq = self._ensure("profit_split_freq", kwargs, int) super().__init__(*args, **kwargs) diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index 09188364..4343c282 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -138,6 +138,8 @@ models: manual_gas_limit: 1000000 validate_timeout: 1205 use_slashing: false + service_owner_share: 0.1 + profit_split_freq: 1000 slash_cooldown_hours: 3 slash_threshold_amount: 10000000000000000 light_slash_unit_amount: 5000000000000000 From 772eddadf1577ef05a300be30d823324edff409d Mon Sep 17 00:00:00 2001 From: Ardian Date: Wed, 22 Nov 2023 16:53:30 +0100 Subject: [PATCH 2/8] feat: add mech interactions --- .../valory/contracts/agent_mech/contract.py | 32 +- .../skills/task_submission_abci/behaviours.py | 614 ++++++++++-------- 2 files changed, 385 insertions(+), 261 deletions(-) diff --git a/packages/valory/contracts/agent_mech/contract.py b/packages/valory/contracts/agent_mech/contract.py index 00392d8b..5279b371 100644 --- a/packages/valory/contracts/agent_mech/contract.py +++ b/packages/valory/contracts/agent_mech/contract.py @@ -18,7 +18,7 @@ # ------------------------------------------------------------------------------ """This module contains the dynamic_contribution contract definition.""" - +from enum import Enum from typing import Any, Dict, List, cast from aea.common import JSONLike @@ -81,6 +81,13 @@ ] +class MechOperation(Enum): + """Operation types.""" + + CALL = 0 + DELEGATE_CALL = 1 + + class AgentMechContract(Contract): """The scaffold contract class for a smart contract.""" @@ -272,3 +279,26 @@ def get_multiple_undelivered_reqs( ).get("data") pending_tasks.extend(pending_tasks_batch) return {"data": pending_tasks} + + @classmethod + def get_exec_tx_data( + cls, + ledger_api: LedgerApi, + contract_address: str, + to: str, + value: int, + data: bytes, + operation: int, + tx_gas: int, + ) -> JSONLike: + """Get tx data""" + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI( + fn_name="exec", args=[to, value, data, operation, tx_gas] + ) + return {"data": bytes.fromhex(data[2:])} # type: ignore diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index 0a290b9b..8eb8c924 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -29,7 +29,10 @@ from multibase import multibase from multicodec import multicodec -from packages.valory.contracts.agent_mech.contract import AgentMechContract +from packages.valory.contracts.agent_mech.contract import ( + AgentMechContract, + MechOperation, +) from packages.valory.contracts.agent_registry.contract import AgentRegistryContract from packages.valory.contracts.gnosis_safe.contract import ( GnosisSafeContract, @@ -62,9 +65,10 @@ ZERO_ETHER_VALUE = 0 -SAFE_GAS = 0 +AUTO_GAS = SAFE_GAS = 0 DONE_TASKS = "ready_tasks" DONE_TASKS_LOCK = "lock" +NO_DATA = b"" class TaskExecutionBaseBehaviour(BaseBehaviour, abc.ABC): @@ -118,6 +122,22 @@ def remove_tasks(self, submitted_tasks: List[Dict[str, Any]]) -> None: not_submitted.append(done_task) self.context.shared_state[DONE_TASKS] = not_submitted + @property + def mech_addresses(self) -> List[str]: + """Get the addresses of the MECHs.""" + return self.context.params.mech_addresses + + @staticmethod + def to_multihash(hash_string: str) -> str: + """To multihash string.""" + # Decode the Base32 CID to bytes + cid_bytes = multibase.decode(hash_string) + # Remove the multicodec prefix (0x01) from the bytes + multihash_bytes = multicodec.remove_prefix(cid_bytes) + # Convert the multihash bytes to a hexadecimal string + hex_multihash = multihash_bytes.hex() + return hex_multihash[6:] + class TaskPoolingBehaviour(TaskExecutionBaseBehaviour): """TaskPoolingBehaviour""" @@ -168,248 +188,8 @@ def handle_submitted_tasks(self) -> None: self.remove_tasks(submitted_tasks) -class TransactionPreparationBehaviour(TaskExecutionBaseBehaviour): - """TransactionPreparationBehaviour""" - - matching_round: Type[AbstractRound] = TransactionPreparationRound - - def async_act(self) -> Generator: # pylint: disable=R0914,R0915 - """Do the act, supporting asynchronous execution.""" - with self.context.benchmark_tool.measure(self.behaviour_id).local(): - payload_content = yield from self.get_payload_content() - sender = self.context.agent_address - payload = TransactionPayload(sender=sender, content=payload_content) - with self.context.benchmark_tool.measure(self.behaviour_id).consensus(): - yield from self.send_a2a_transaction(payload) - yield from self.wait_until_round_end() - self.set_done() - - def get_payload_content(self) -> Generator[None, None, str]: - """Prepare the transaction""" - all_txs = [] - should_update_hash = yield from self._should_update_hash() - if should_update_hash: - update_hash_tx = yield from self._get_mech_update_hash_tx() - if update_hash_tx is None: - # something went wrong, respond with ERROR payload for now - return TransactionPreparationRound.ERROR_PAYLOAD - all_txs.append(update_hash_tx) - - for task in self.synchronized_data.done_tasks: - deliver_tx = yield from self._get_deliver_tx(task) - if deliver_tx is None: - # something went wrong, respond with ERROR payload for now - return TransactionPreparationRound.ERROR_PAYLOAD - all_txs.append(deliver_tx) - response_tx = task.get("transaction", None) - if response_tx is not None: - all_txs.append(response_tx) - - multisend_tx_str = yield from self._to_multisend(all_txs) - if multisend_tx_str is None: - # something went wrong, respond with ERROR payload for now - return TransactionPreparationRound.ERROR_PAYLOAD - - return multisend_tx_str - - def _to_multisend( - self, transactions: List[Dict] - ) -> Generator[None, None, Optional[str]]: - """Transform payload to MultiSend.""" - multi_send_txs = [] - for transaction in transactions: - transaction = { - "operation": transaction.get("operation", MultiSendOperation.CALL), - "to": transaction["to"], - "value": transaction["value"], - "data": transaction.get("data", b""), - } - multi_send_txs.append(transaction) - - response = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore - contract_address=self.params.multisend_address, - contract_id=str(MultiSendContract.contract_id), - contract_callable="get_tx_data", - multi_send_txs=multi_send_txs, - ) - if response.performative != ContractApiMessage.Performative.RAW_TRANSACTION: - self.context.logger.error( - f"Couldn't compile the multisend tx. " - f"Expected performative {ContractApiMessage.Performative.RAW_TRANSACTION.value}, " # type: ignore - f"received {response.performative.value}." - ) - return None - - # strip "0x" from the response - multisend_data_str = cast(str, response.raw_transaction.body["data"])[2:] - tx_data = bytes.fromhex(multisend_data_str) - tx_hash = yield from self._get_safe_tx_hash(tx_data) - if tx_hash is None: - # something went wrong - return None - - payload_data = hash_payload_to_hex( - safe_tx_hash=tx_hash, - ether_value=ZERO_ETHER_VALUE, - safe_tx_gas=SAFE_GAS, - operation=SafeOperation.DELEGATE_CALL.value, - to_address=self.params.multisend_address, - data=tx_data, - gas_limit=self.params.manual_gas_limit, - ) - return payload_data - - def _get_safe_tx_hash(self, data: bytes) -> Generator[None, None, Optional[str]]: - """ - Prepares and returns the safe tx hash. - - This hash will be signed later by the agents, and submitted to the safe contract. - Note that this is the transaction that the safe will execute, with the provided data. - - :param data: the safe tx data. - :return: the tx hash - """ - response = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.synchronized_data.safe_contract_address, - contract_id=str(GnosisSafeContract.contract_id), - contract_callable="get_raw_safe_transaction_hash", - to_address=self.params.multisend_address, # we send the tx to the multisend address - value=ZERO_ETHER_VALUE, - data=data, - safe_tx_gas=SAFE_GAS, - operation=SafeOperation.DELEGATE_CALL.value, - ) - - if response.performative != ContractApiMessage.Performative.STATE: - self.context.logger.error( - f"Couldn't get safe hash. " - f"Expected response performative {ContractApiMessage.Performative.STATE.value}, " # type: ignore - f"received {response.performative.value}." - ) - return None - - # strip "0x" from the response hash - tx_hash = cast(str, response.state.body["tx_hash"])[2:] - return tx_hash - - def _get_deliver_tx( - self, task_data: Dict[str, Any] - ) -> Generator[None, None, Optional[Dict]]: - """Get the deliver tx.""" - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=task_data["mech_address"], - contract_id=str(AgentMechContract.contract_id), - contract_callable="get_deliver_data", - request_id=task_data["request_id"], - data=task_data["task_result"], - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_deliver_data unsuccessful!: {contract_api_msg}" - ) - return None - - data = cast(bytes, contract_api_msg.state.body["data"]) - return { - "to": task_data["mech_address"], - "value": ZERO_ETHER_VALUE, - "data": data, - } - - def _get_latest_hash(self) -> Generator[None, None, Optional[bytes]]: - """Get latest update hash.""" - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.params.agent_registry_address, - contract_id=str(AgentRegistryContract.contract_id), - contract_callable="get_token_hash", - token_id=self.params.agent_id, - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_token_hash unsuccessful!: {contract_api_msg}" - ) - return None - - latest_hash = cast(bytes, contract_api_msg.state.body["data"]) - return latest_hash - - def _should_update_hash(self) -> Generator: - """Check if the agent should update the hash.""" - if self.params.task_mutable_params.latest_metadata_hash is None: - latest_hash = yield from self._get_latest_hash() - if latest_hash is None: - self.context.logger.warning( - "Could not get latest hash. Don't update the metadata." - ) - return False - self.params.task_mutable_params.latest_metadata_hash = latest_hash - - configured_hash = self.to_multihash(self.params.metadata_hash) - latest_hash = self.params.task_mutable_params.latest_metadata_hash - return configured_hash != latest_hash - - @staticmethod - def to_multihash(hash_string: str) -> str: - """To multihash string.""" - # Decode the Base32 CID to bytes - cid_bytes = multibase.decode(hash_string) - # Remove the multicodec prefix (0x01) from the bytes - multihash_bytes = multicodec.remove_prefix(cid_bytes) - # Convert the multihash bytes to a hexadecimal string - hex_multihash = multihash_bytes.hex() - return hex_multihash[6:] - - def _get_mech_update_hash_tx(self) -> Generator: - """Get the mech update hash tx.""" - metadata_str = self.to_multihash(self.params.metadata_hash) - metadata = bytes.fromhex(metadata_str) - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.params.agent_registry_address, - contract_id=str(AgentRegistryContract.contract_id), - contract_callable="get_update_hash_tx_data", - token_id=self.params.agent_id, - metadata_hash=metadata, - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_mech_update_hash unsuccessful!: {contract_api_msg}" - ) - return None - - data = cast(bytes, contract_api_msg.state.body["data"]) - return { - "to": self.params.agent_registry_address, - "value": ZERO_ETHER_VALUE, - "data": data, - } - - def _get_transfer_txs(self) -> Generator: - """Get the transfer txs.""" - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.params.agent_registry_address, - contract_id=str(AgentRegistryContract.contract_id), - contract_callable="get_transfer_txs", - token_id=self.params.agent_id, - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_transfer_txs unsuccessful!: {contract_api_msg}" - ) - return None +class FundsSplittingBehaviour(TaskExecutionBaseBehaviour): + """FundsSplittingBehaviour""" def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: """Return the total number of requests delivered.""" @@ -452,6 +232,50 @@ def _should_split_profits(self) -> Generator[None, None, bool]: return False return total_reqs % self.params.profit_split_freq == 0 + def get_split_profit_txs( + self, + ) -> Generator[None, None, Optional[List[Dict[str, Any]]]]: + """Get and split all the profits from all the mechs.""" + should_split_profits = yield from self._should_split_profits() + if not should_split_profits: + self.context.logger.info("Not splitting profits.") + return [] + + self.context.logger.info(f"Splitting profits {self.mech_addresses}.") + txs = [] + for mech_address in self.mech_addresses: + profits = yield from self._get_profits(mech_address) + if profits is None: + self.context.logger.error( + f"Could not get profits from mech {mech_address}. Don't split profits." + ) + return None + + self.context.logger.info(f"Got {profits} profits from mech {mech_address}") + split_funds = yield from self._split_funds(profits) + if split_funds is None: + self.context.logger.error( + f"Could not split profits from mech {mech_address}. Don't split profits." + ) + return None + + self.context.logger.info( + f"Split {profits} profits from mech {mech_address} into {split_funds}" + ) + for receiver_address, amount in split_funds.items(): + tx = yield from self._get_transfer_tx( + mech_address, receiver_address, amount + ) + if tx is None: + self.context.logger.error( + f"Could not get transfer tx from mech {mech_address} to {receiver_address}. " + f"Don't split profits." + ) + return None + txs.append(tx) + + return txs + def _get_profits(self, address: str) -> Generator[None, None, int]: """Get the profits.""" ledger_api_response = yield from self.get_ledger_api_response( @@ -464,7 +288,9 @@ def _get_profits(self, address: str) -> Generator[None, None, int]: balance = cast(int, ledger_api_response.state.body.get("get_balance_result")) return balance - def _split_funds(self, profits: int) -> Generator[None, None, Optional[Dict[str, int]]]: + def _split_funds( + self, profits: int + ) -> Generator[None, None, Optional[Dict[str, int]]]: """ Split the funds among the operators based on the number of txs their agents have made. @@ -472,7 +298,9 @@ def _split_funds(self, profits: int) -> Generator[None, None, Optional[Dict[str, :returns: a dictionary mapping operator addresses to the amount of funds they should receive. :yields: None """ - service_owner = yield from self._get_service_owner(self.params.on_chain_service_id) + service_owner = yield from self._get_service_owner( + self.params.on_chain_service_id + ) if service_owner is None: self.context.logger.warning( "Could not get service owner. Don't split profits." @@ -495,7 +323,40 @@ def _split_funds(self, profits: int) -> Generator[None, None, Optional[Dict[str, funds_by_address.update(funds_by_operator) return funds_by_address - def _get_service_owner(self, service_id: int) -> Generator[None, None, Optional[str]]: + def _get_transfer_tx( + self, mech_address: str, receiver_address: str, amount: int + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the transfer tx.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=mech_address, + contract_id=str(AgentMechContract.contract_id), + contract_callable="get_exec_tx_data", + to=receiver_address, + value=amount, + data=NO_DATA, + tx_gas=AUTO_GAS, + operation=MechOperation.CALL, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_exec_tx_data unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": mech_address, + # the safe is not moving any funds, the mech contract is + "value": ZERO_ETHER_VALUE, + "data": data, + } + + def _get_service_owner( + self, service_id: int + ) -> Generator[None, None, Optional[str]]: """Get the service owner address.""" contract_api_msg = yield from self.get_contract_api_response( performative=ContractApiMessage.Performative.GET_STATE, @@ -504,17 +365,16 @@ def _get_service_owner(self, service_id: int) -> Generator[None, None, Optional[ contract_callable="get_service_owner", service_id=service_id, ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): + if contract_api_msg.performative != ContractApiMessage.Performative.STATE: self.context.logger.warning( f"get_service_owner unsuccessful!: {contract_api_msg}" ) return None return cast(str, contract_api_msg.state.body["service_owner"]) - - def _get_funds_by_operator(self, operator_share: int) -> Generator[None, None, Optional[Dict[str, int]]]: + def _get_funds_by_operator( + self, operator_share: int + ) -> Generator[None, None, Optional[Dict[str, int]]]: """Split the funds among the operators based on the number of txs their agents have made.""" reqs_by_agent = yield from self._get_num_reqs_by_agent() if reqs_by_agent is None: @@ -526,12 +386,11 @@ def _get_funds_by_operator(self, operator_share: int) -> Generator[None, None, O total_reqs = sum(reqs_by_agent.values()) if total_reqs == 0: # nothing to split - return { - agent: 0 - for agent in reqs_by_agent.keys() - } + return {agent: 0 for agent in reqs_by_agent.keys()} - accumulated_reqs_by_operator = yield from self._accumulate_reqs_by_operator(reqs_by_agent) + accumulated_reqs_by_operator = yield from self._accumulate_reqs_by_operator( + reqs_by_agent + ) if accumulated_reqs_by_operator is None: self.context.logger.warning( "Could not get number of requests delivered. Don't split profits." @@ -539,11 +398,15 @@ def _get_funds_by_operator(self, operator_share: int) -> Generator[None, None, O return None for agent, reqs in accumulated_reqs_by_operator.items(): - accumulated_reqs_by_operator[agent] = int(operator_share * (reqs / total_reqs)) + accumulated_reqs_by_operator[agent] = int( + operator_share * (reqs / total_reqs) + ) return accumulated_reqs_by_operator - def _accumulate_reqs_by_operator(self, reqs_by_agent: Dict[str, int]) -> Generator[None, None, Optional[Dict[str, int]]]: + def _accumulate_reqs_by_operator( + self, reqs_by_agent: Dict[str, int] + ) -> Generator[None, None, Optional[Dict[str, int]]]: """Accumulate requests by operator.""" agent_instances = list(reqs_by_agent.keys()) contract_api_msg = yield from self.get_contract_api_response( @@ -554,7 +417,7 @@ def _accumulate_reqs_by_operator(self, reqs_by_agent: Dict[str, int]) -> Generat agent_instances=agent_instances, ) if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE + contract_api_msg.performative != ContractApiMessage.Performative.STATE ): # pragma: nocover self.context.logger.warning( f"get_operators_mapping unsuccessful!: {contract_api_msg}" @@ -573,6 +436,237 @@ def _accumulate_reqs_by_operator(self, reqs_by_agent: Dict[str, int]) -> Generat return reqs_by_operator +class HashUpdateBehaviour(TaskExecutionBaseBehaviour): + """HashUpdateBehaviour""" + + def _get_latest_hash(self) -> Generator[None, None, Optional[bytes]]: + """Get latest update hash.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(AgentRegistryContract.contract_id), + contract_callable="get_token_hash", + token_id=self.params.agent_id, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_token_hash unsuccessful!: {contract_api_msg}" + ) + return None + + latest_hash = cast(bytes, contract_api_msg.state.body["data"]) + return latest_hash + + def _should_update_hash(self) -> Generator: + """Check if the agent should update the hash.""" + if self.params.task_mutable_params.latest_metadata_hash is None: + latest_hash = yield from self._get_latest_hash() + if latest_hash is None: + self.context.logger.warning( + "Could not get latest hash. Don't update the metadata." + ) + return False + self.params.task_mutable_params.latest_metadata_hash = latest_hash + + configured_hash = self.to_multihash(self.params.metadata_hash) + latest_hash = self.params.task_mutable_params.latest_metadata_hash + return configured_hash != latest_hash + + def get_mech_update_hash_tx(self) -> Generator: + """Get the mech update hash tx.""" + should_update_hash = yield from self._should_update_hash() + if not should_update_hash: + return None + + metadata_str = self.to_multihash(self.params.metadata_hash) + metadata = bytes.fromhex(metadata_str) + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(AgentRegistryContract.contract_id), + contract_callable="get_update_hash_tx_data", + token_id=self.params.agent_id, + metadata_hash=metadata, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_mech_update_hash unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": self.params.agent_registry_address, + "value": ZERO_ETHER_VALUE, + "data": data, + } + + +class TransactionPreparationBehaviour(FundsSplittingBehaviour, HashUpdateBehaviour): + """TransactionPreparationBehaviour""" + + matching_round: Type[AbstractRound] = TransactionPreparationRound + + def async_act(self) -> Generator: # pylint: disable=R0914,R0915 + """Do the act, supporting asynchronous execution.""" + with self.context.benchmark_tool.measure(self.behaviour_id).local(): + payload_content = yield from self.get_payload_content() + sender = self.context.agent_address + payload = TransactionPayload(sender=sender, content=payload_content) + with self.context.benchmark_tool.measure(self.behaviour_id).consensus(): + yield from self.send_a2a_transaction(payload) + yield from self.wait_until_round_end() + self.set_done() + + def get_payload_content(self) -> Generator[None, None, str]: + """Prepare the transaction""" + all_txs = [] + update_hash_tx = yield from self.get_mech_update_hash_tx() + if update_hash_tx is not None: + # in case of None, the agent should not update the hash + # if this is caused by an error, the agent should still proceed with the rest + # of the txs. The error will be logged. + all_txs.append(update_hash_tx) + + split_profit_txs = yield from self.get_split_profit_txs() + if split_profit_txs is not None: + # in case of None, the agent should not update the hash + # if this is caused by an error, the agent should still proceed with the rest + # of the txs. The error will be logged. + all_txs.extend(split_profit_txs) + + for task in self.synchronized_data.done_tasks: + deliver_tx = yield from self._get_deliver_tx(task) + if deliver_tx is None: + # something went wrong, respond with ERROR payload for now + # nothing should proceed if this happens + return TransactionPreparationRound.ERROR_PAYLOAD + all_txs.append(deliver_tx) + response_tx = task.get("transaction", None) + if response_tx is not None: + all_txs.append(response_tx) + + multisend_tx_str = yield from self._to_multisend(all_txs) + if multisend_tx_str is None: + # something went wrong, respond with ERROR payload for now + return TransactionPreparationRound.ERROR_PAYLOAD + + return multisend_tx_str + + def _to_multisend( + self, transactions: List[Dict] + ) -> Generator[None, None, Optional[str]]: + """Transform payload to MultiSend.""" + multi_send_txs = [] + for transaction in transactions: + transaction = { + "operation": transaction.get("operation", MultiSendOperation.CALL), + "to": transaction["to"], + "value": transaction["value"], + "data": transaction.get("data", b""), + } + multi_send_txs.append(transaction) + + response = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION, # type: ignore + contract_address=self.params.multisend_address, + contract_id=str(MultiSendContract.contract_id), + contract_callable="get_tx_data", + multi_send_txs=multi_send_txs, + ) + if response.performative != ContractApiMessage.Performative.RAW_TRANSACTION: + self.context.logger.error( + f"Couldn't compile the multisend tx. " + f"Expected performative {ContractApiMessage.Performative.RAW_TRANSACTION.value}, " # type: ignore + f"received {response.performative.value}." + ) + return None + + # strip "0x" from the response + multisend_data_str = cast(str, response.raw_transaction.body["data"])[2:] + tx_data = bytes.fromhex(multisend_data_str) + tx_hash = yield from self._get_safe_tx_hash(tx_data) + if tx_hash is None: + # something went wrong + return None + + payload_data = hash_payload_to_hex( + safe_tx_hash=tx_hash, + ether_value=ZERO_ETHER_VALUE, + safe_tx_gas=SAFE_GAS, + operation=SafeOperation.DELEGATE_CALL.value, + to_address=self.params.multisend_address, + data=tx_data, + gas_limit=self.params.manual_gas_limit, + ) + return payload_data + + def _get_safe_tx_hash(self, data: bytes) -> Generator[None, None, Optional[str]]: + """ + Prepares and returns the safe tx hash. + + This hash will be signed later by the agents, and submitted to the safe contract. + Note that this is the transaction that the safe will execute, with the provided data. + + :param data: the safe tx data. + :return: the tx hash + """ + response = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.synchronized_data.safe_contract_address, + contract_id=str(GnosisSafeContract.contract_id), + contract_callable="get_raw_safe_transaction_hash", + to_address=self.params.multisend_address, # we send the tx to the multisend address + value=ZERO_ETHER_VALUE, + data=data, + safe_tx_gas=SAFE_GAS, + operation=SafeOperation.DELEGATE_CALL.value, + ) + + if response.performative != ContractApiMessage.Performative.STATE: + self.context.logger.error( + f"Couldn't get safe hash. " + f"Expected response performative {ContractApiMessage.Performative.STATE.value}, " # type: ignore + f"received {response.performative.value}." + ) + return None + + # strip "0x" from the response hash + tx_hash = cast(str, response.state.body["tx_hash"])[2:] + return tx_hash + + def _get_deliver_tx( + self, task_data: Dict[str, Any] + ) -> Generator[None, None, Optional[Dict]]: + """Get the deliver tx.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=task_data["mech_address"], + contract_id=str(AgentMechContract.contract_id), + contract_callable="get_deliver_data", + request_id=task_data["request_id"], + data=task_data["task_result"], + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_deliver_data unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": task_data["mech_address"], + "value": ZERO_ETHER_VALUE, + "data": data, + } + + class TaskSubmissionRoundBehaviour(AbstractRoundBehaviour): """TaskSubmissionRoundBehaviour""" From ef645282567aa0ab616cf156203b324758b58f10 Mon Sep 17 00:00:00 2001 From: Ardian Date: Thu, 23 Nov 2023 21:24:26 +0100 Subject: [PATCH 3/8] feat: add HashCheckpoint --- .../contracts/hash_checkpoint/__init__.py | 20 ++ .../hash_checkpoint/build/HashCheckpoint.json | 241 ++++++++++++++++++ .../contracts/hash_checkpoint/contract.py | 127 +++++++++ .../contracts/hash_checkpoint/contract.yaml | 21 ++ .../skills/task_execution/behaviours.py | 10 +- .../skills/task_submission_abci/behaviours.py | 98 ++++++- .../skills/task_submission_abci/models.py | 1 + .../skills/task_submission_abci/skill.yaml | 1 + 8 files changed, 514 insertions(+), 5 deletions(-) create mode 100644 packages/valory/contracts/hash_checkpoint/__init__.py create mode 100644 packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json create mode 100644 packages/valory/contracts/hash_checkpoint/contract.py create mode 100644 packages/valory/contracts/hash_checkpoint/contract.yaml diff --git a/packages/valory/contracts/hash_checkpoint/__init__.py b/packages/valory/contracts/hash_checkpoint/__init__.py new file mode 100644 index 00000000..ea5f140e --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the support resources for the agent mech contract.""" diff --git a/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json b/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json new file mode 100644 index 00000000..a9d5413d --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json @@ -0,0 +1,241 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "HashCheckpoint", + "sourceName": "contracts/HashCheckpoint.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "_baseURI", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "baseURI", + "type": "string" + } + ], + "name": "BaseURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "emitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "HashUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "CID_PREFIX", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "checkpoint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "latestHash", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "latestHashURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "latestHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "bURI", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052600080553480156200001557600080fd5b5060405162001d4538038062001d4583398101604081905262000038916200039f565b604080516001600160a01b038516602082015280820184905281518082038301815260609091019091528390839062000071816200014a565b5050506001600160a01b0383166200009c5760405163d92e233d60e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa158015620000e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010b9190620003d7565b90506001600160a01b0381166200013d57604051630ede975960e01b8152600481018490526024015b60405180910390fd5b5060015550620004b39050565b62000154620001b2565b5115620001a45760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a656400000000000000000000000000604482015260640162000134565b620001af816200021f565b50565b60606200021a62000214604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b620002ed565b905090565b60006200022c8262000346565b905060008151602083016000f0905062000297604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614620002e85760405162461bcd60e51b815260206004820152600c60248201526b15dc9a5d194819985a5b195960a21b604482015260640162000134565b505050565b6060813b6001811162000310575050604080516020810190915260008152919050565b806200031c8162000412565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b6060815160016200035891906200042c565b826040516020016200036c92919062000448565b6040516020818303038152906040529050919050565b80516001600160a01b03811681146200039a57600080fd5b919050565b600080600060608486031215620003b557600080fd5b620003c08462000382565b925060208401519150604084015190509250925092565b600060208284031215620003ea57600080fd5b620003f58262000382565b9392505050565b634e487b7160e01b600052601160045260246000fd5b600081620004245762000424620003fc565b506000190190565b80820180821115620004425762000442620003fc565b92915050565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201526000600e82018190528251815b81811015620004a1576020818601810151600f86840101520162000482565b5060009201600f019182525092915050565b61188280620004c36000396000f3fe60806040526004361061012c5760003560e01c8063a4f9edbf116100a5578063bc197c8111610074578063e00b911811610059578063e00b911814610371578063f23a6e6114610391578063fc0c546a146103be57600080fd5b8063bc197c8114610315578063c7dec3fc1461034457600080fd5b8063a4f9edbf14610292578063affed0e0146102b2578063b0d691fe146102c7578063b94207d31461030257600080fd5b806317d70f7c116100fc5780636d70f7ae116100e15780636d70f7ae1461022c57806391b7f5ed1461025c578063a035b1fe1461027c57600080fd5b806317d70f7c146101e95780633a871cdd1461020c57600080fd5b806223de2914610138578063150b7a021461015f578063157305fe146101a95780631626ba7e146101c957600080fd5b3661013357005b600080fd5b34801561014457600080fd5b5061015d610153366004611118565b5050505050505050565b005b34801561016b57600080fd5b5061018b61017a3660046111c9565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101b557600080fd5b5061015d6101c43660046112df565b6103d3565b3480156101d557600080fd5b5061018b6101e43660046112df565b6104ae565b3480156101f557600080fd5b506101fe6105db565b6040519081526020016101a0565b34801561021857600080fd5b506101fe610227366004611326565b610600565b34801561023857600080fd5b5061024c61024736600461137a565b61063e565b60405190151581526020016101a0565b34801561026857600080fd5b5061015d610277366004611397565b6106ed565b34801561028857600080fd5b506101fe60015481565b34801561029e57600080fd5b5061015d6102ad3660046113b0565b6107c1565b3480156102be57600080fd5b506000546101fe565b3480156102d357600080fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b6040516001600160a01b0390911681526020016101a0565b6101fe6103103660046113b0565b610823565b34801561032157600080fd5b5061018b610330366004611432565b63bc197c8160e01b98975050505050505050565b34801561035057600080fd5b5061036461035f3660046114d0565b6108a9565b6040516101a09190611598565b34801561037d57600080fd5b506101fe61038c3660046115ab565b61097a565b34801561039d57600080fd5b5061018b6103ac3660046115e5565b63f23a6e6160e01b9695505050505050565b3480156103ca57600080fd5b506102ea6109ae565b6103dc3361063e565b806103fa575033730576a174d229e3cfa37253523e645a78a0c91b57145b6104715760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b7f3ec84da2cdc1ce60c063642b69ff2e65f3b69787a2b90443457ba274e51e7c7282826040516104a2929190611661565b60405180910390a15050565b6000806000806104d1856020810151604082015160609092015160001a92909190565b9094509250905060ff811660000361059f57828583016020016104f38261063e565b15801561050957506001600160a01b0382163014155b1561052457506001600160e01b031994506105d59350505050565b604051630b135d3f60e11b81526001600160a01b03831690631626ba7e90610552908b908590600401611661565b602060405180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061167a565b955050505050506105d5565b6105ae610247878386866109cc565b156105c65750630b135d3f60e11b92506105d5915050565b506001600160e01b0319925050505b92915050565b6000806105e66109ea565b8060200190518101906105f991906116a4565b9392505050565b600061060a610a59565b6106148484610abe565b905061062360408501856116d2565b90506000036106355761063584610b91565b6105f982610bf6565b600080600061064b6109ea565b80602001905181019061065e91906116a4565b91509150836001600160a01b0316826001600160a01b0316636352211e836040518263ffffffff1660e01b815260040161069a91815260200190565b602060405180830381865afa1580156106b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106db9190611719565b6001600160a01b031614949350505050565b6106f63361063e565b80610714575033730576a174d229e3cfa37253523e645a78a0c91b57145b6107865760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b6107c96109ea565b51156108175760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610468565b61082081610c4f565b50565b6000600154341015610855576001546040516316912f0560e31b81523460048201526024810191909152604401610468565b61085f338361097a565b9050336001600160a01b03167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc828460405161089c929190611661565b60405180910390a2919050565b60606108b43361063e565b806108d2575033730576a174d229e3cfa37253523e645a78a0c91b57145b6109445760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b600061095f8787878787156109595787610d2e565b5a610d2e565b925090508061097057815160208301fd5b5095945050505050565b6000828260405160200161098f929190611736565b60408051601f1981840301815291905280516020909101209392505050565b6000806109b96109ea565b8060200190518101906105d59190611719565b60008060006109dd87878787610e1e565b9150915061097081610ee2565b6060610a54610a4f604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b61102c565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b5714610abc5760405162461bcd60e51b815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152606401610468565b565b600080610b18836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050630b135d3f60e11b610b6e82610b346101408801886116d2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104ae92505050565b6001600160e01b03191614610b875760019150506105d5565b5060009392505050565b6000805460208301359180610ba58361176e565b91905055146108205760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610468565b801561082057604051600090339060001990849084818181858888f193505050503d8060008114610c43576040519150601f19603f3d011682016040523d82523d6000602084013e610c48565b606091505b5050505050565b6000610c5a82611082565b905060008151602083016000f09050610cc9604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614610d295760405162461bcd60e51b815260206004820152600c60248201527f5772697465206661696c656400000000000000000000000000000000000000006044820152606401610468565b505050565b600060606001846001811115610d4657610d46611787565b03610db057866001600160a01b03168386604051610d64919061179d565b6000604051808303818686f4925050503d8060008114610da0576040519150601f19603f3d011682016040523d82523d6000602084013e610da5565b606091505b509092509050610e14565b866001600160a01b0316838787604051610dca919061179d565b600060405180830381858888f193505050503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b5090925090505b9550959350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610e555750600090506003610ed9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ea9573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ed257600060019250925050610ed9565b9150600090505b94509492505050565b6000816004811115610ef657610ef6611787565b03610efe5750565b6001816004811115610f1257610f12611787565b03610f5f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610468565b6002816004811115610f7357610f73611787565b03610fc05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610468565b6003816004811115610fd457610fd4611787565b036108205760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610468565b6060813b6001811161104e575050604080516020810190915260008152919050565b80611058816117b9565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b60608151600161109291906117d0565b826040516020016110a49291906117e3565b6040516020818303038152906040529050919050565b6001600160a01b038116811461082057600080fd5b60008083601f8401126110e157600080fd5b50813567ffffffffffffffff8111156110f957600080fd5b60208301915083602082850101111561111157600080fd5b9250929050565b60008060008060008060008060c0898b03121561113457600080fd5b883561113f816110ba565b9750602089013561114f816110ba565b9650604089013561115f816110ba565b955060608901359450608089013567ffffffffffffffff8082111561118357600080fd5b61118f8c838d016110cf565b909650945060a08b01359150808211156111a857600080fd5b506111b58b828c016110cf565b999c989b5096995094979396929594505050565b6000806000806000608086880312156111e157600080fd5b85356111ec816110ba565b945060208601356111fc816110ba565b935060408601359250606086013567ffffffffffffffff81111561121f57600080fd5b61122b888289016110cf565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261126357600080fd5b813567ffffffffffffffff8082111561127e5761127e61123c565b604051601f8301601f19908116603f011681019082821181831017156112a6576112a661123c565b816040528381528660208588010111156112bf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156112f257600080fd5b82359150602083013567ffffffffffffffff81111561131057600080fd5b61131c85828601611252565b9150509250929050565b60008060006060848603121561133b57600080fd5b833567ffffffffffffffff81111561135257600080fd5b8401610160818703121561136557600080fd5b95602085013595506040909401359392505050565b60006020828403121561138c57600080fd5b81356105f9816110ba565b6000602082840312156113a957600080fd5b5035919050565b6000602082840312156113c257600080fd5b813567ffffffffffffffff8111156113d957600080fd5b6113e584828501611252565b949350505050565b60008083601f8401126113ff57600080fd5b50813567ffffffffffffffff81111561141757600080fd5b6020830191508360208260051b850101111561111157600080fd5b60008060008060008060008060a0898b03121561144e57600080fd5b8835611459816110ba565b97506020890135611469816110ba565b9650604089013567ffffffffffffffff8082111561148657600080fd5b6114928c838d016113ed565b909850965060608b01359150808211156114ab57600080fd5b6114b78c838d016113ed565b909650945060808b01359150808211156111a857600080fd5b600080600080600060a086880312156114e857600080fd5b85356114f3816110ba565b945060208601359350604086013567ffffffffffffffff81111561151657600080fd5b61152288828901611252565b93505060608601356002811061153757600080fd5b949793965091946080013592915050565b60005b8381101561156357818101518382015260200161154b565b50506000910152565b60008151808452611584816020860160208601611548565b601f01601f19169290920160200192915050565b6020815260006105f9602083018461156c565b600080604083850312156115be57600080fd5b82356115c9816110ba565b9150602083013567ffffffffffffffff81111561131057600080fd5b60008060008060008060a087890312156115fe57600080fd5b8635611609816110ba565b95506020870135611619816110ba565b94506040870135935060608701359250608087013567ffffffffffffffff81111561164357600080fd5b61164f89828a016110cf565b979a9699509497509295939492505050565b8281526040602082015260006113e5604083018461156c565b60006020828403121561168c57600080fd5b81516001600160e01b0319811681146105f957600080fd5b600080604083850312156116b757600080fd5b82516116c2816110ba565b6020939093015192949293505050565b6000808335601e198436030181126116e957600080fd5b83018035915067ffffffffffffffff82111561170457600080fd5b60200191503681900382131561111157600080fd5b60006020828403121561172b57600080fd5b81516105f9816110ba565b6001600160a01b03831681526040602082015260006113e5604083018461156c565b634e487b7160e01b600052601160045260246000fd5b60006001820161178057611780611758565b5060010190565b634e487b7160e01b600052602160045260246000fd5b600082516117af818460208701611548565b9190910192915050565b6000816117c8576117c8611758565b506000190190565b808201808211156105d5576105d5611758565b606360f81b815263ffffffff60e01b8360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201526000600e8201526000825161183e81600f850160208701611548565b91909101600f01939250505056fea26469706673582212202a03e14f0f05f58be9cbbba4646c39d989209350f0ee3edaaf0da00994a368d164736f6c63430008130033", + "deployedBytecode": "0x60806040526004361061012c5760003560e01c8063a4f9edbf116100a5578063bc197c8111610074578063e00b911811610059578063e00b911814610371578063f23a6e6114610391578063fc0c546a146103be57600080fd5b8063bc197c8114610315578063c7dec3fc1461034457600080fd5b8063a4f9edbf14610292578063affed0e0146102b2578063b0d691fe146102c7578063b94207d31461030257600080fd5b806317d70f7c116100fc5780636d70f7ae116100e15780636d70f7ae1461022c57806391b7f5ed1461025c578063a035b1fe1461027c57600080fd5b806317d70f7c146101e95780633a871cdd1461020c57600080fd5b806223de2914610138578063150b7a021461015f578063157305fe146101a95780631626ba7e146101c957600080fd5b3661013357005b600080fd5b34801561014457600080fd5b5061015d610153366004611118565b5050505050505050565b005b34801561016b57600080fd5b5061018b61017a3660046111c9565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101b557600080fd5b5061015d6101c43660046112df565b6103d3565b3480156101d557600080fd5b5061018b6101e43660046112df565b6104ae565b3480156101f557600080fd5b506101fe6105db565b6040519081526020016101a0565b34801561021857600080fd5b506101fe610227366004611326565b610600565b34801561023857600080fd5b5061024c61024736600461137a565b61063e565b60405190151581526020016101a0565b34801561026857600080fd5b5061015d610277366004611397565b6106ed565b34801561028857600080fd5b506101fe60015481565b34801561029e57600080fd5b5061015d6102ad3660046113b0565b6107c1565b3480156102be57600080fd5b506000546101fe565b3480156102d357600080fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b6040516001600160a01b0390911681526020016101a0565b6101fe6103103660046113b0565b610823565b34801561032157600080fd5b5061018b610330366004611432565b63bc197c8160e01b98975050505050505050565b34801561035057600080fd5b5061036461035f3660046114d0565b6108a9565b6040516101a09190611598565b34801561037d57600080fd5b506101fe61038c3660046115ab565b61097a565b34801561039d57600080fd5b5061018b6103ac3660046115e5565b63f23a6e6160e01b9695505050505050565b3480156103ca57600080fd5b506102ea6109ae565b6103dc3361063e565b806103fa575033730576a174d229e3cfa37253523e645a78a0c91b57145b6104715760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b7f3ec84da2cdc1ce60c063642b69ff2e65f3b69787a2b90443457ba274e51e7c7282826040516104a2929190611661565b60405180910390a15050565b6000806000806104d1856020810151604082015160609092015160001a92909190565b9094509250905060ff811660000361059f57828583016020016104f38261063e565b15801561050957506001600160a01b0382163014155b1561052457506001600160e01b031994506105d59350505050565b604051630b135d3f60e11b81526001600160a01b03831690631626ba7e90610552908b908590600401611661565b602060405180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061167a565b955050505050506105d5565b6105ae610247878386866109cc565b156105c65750630b135d3f60e11b92506105d5915050565b506001600160e01b0319925050505b92915050565b6000806105e66109ea565b8060200190518101906105f991906116a4565b9392505050565b600061060a610a59565b6106148484610abe565b905061062360408501856116d2565b90506000036106355761063584610b91565b6105f982610bf6565b600080600061064b6109ea565b80602001905181019061065e91906116a4565b91509150836001600160a01b0316826001600160a01b0316636352211e836040518263ffffffff1660e01b815260040161069a91815260200190565b602060405180830381865afa1580156106b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106db9190611719565b6001600160a01b031614949350505050565b6106f63361063e565b80610714575033730576a174d229e3cfa37253523e645a78a0c91b57145b6107865760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b6107c96109ea565b51156108175760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610468565b61082081610c4f565b50565b6000600154341015610855576001546040516316912f0560e31b81523460048201526024810191909152604401610468565b61085f338361097a565b9050336001600160a01b03167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc828460405161089c929190611661565b60405180910390a2919050565b60606108b43361063e565b806108d2575033730576a174d229e3cfa37253523e645a78a0c91b57145b6109445760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b600061095f8787878787156109595787610d2e565b5a610d2e565b925090508061097057815160208301fd5b5095945050505050565b6000828260405160200161098f929190611736565b60408051601f1981840301815291905280516020909101209392505050565b6000806109b96109ea565b8060200190518101906105d59190611719565b60008060006109dd87878787610e1e565b9150915061097081610ee2565b6060610a54610a4f604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b61102c565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b5714610abc5760405162461bcd60e51b815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152606401610468565b565b600080610b18836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050630b135d3f60e11b610b6e82610b346101408801886116d2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104ae92505050565b6001600160e01b03191614610b875760019150506105d5565b5060009392505050565b6000805460208301359180610ba58361176e565b91905055146108205760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610468565b801561082057604051600090339060001990849084818181858888f193505050503d8060008114610c43576040519150601f19603f3d011682016040523d82523d6000602084013e610c48565b606091505b5050505050565b6000610c5a82611082565b905060008151602083016000f09050610cc9604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614610d295760405162461bcd60e51b815260206004820152600c60248201527f5772697465206661696c656400000000000000000000000000000000000000006044820152606401610468565b505050565b600060606001846001811115610d4657610d46611787565b03610db057866001600160a01b03168386604051610d64919061179d565b6000604051808303818686f4925050503d8060008114610da0576040519150601f19603f3d011682016040523d82523d6000602084013e610da5565b606091505b509092509050610e14565b866001600160a01b0316838787604051610dca919061179d565b600060405180830381858888f193505050503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b5090925090505b9550959350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610e555750600090506003610ed9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ea9573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ed257600060019250925050610ed9565b9150600090505b94509492505050565b6000816004811115610ef657610ef6611787565b03610efe5750565b6001816004811115610f1257610f12611787565b03610f5f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610468565b6002816004811115610f7357610f73611787565b03610fc05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610468565b6003816004811115610fd457610fd4611787565b036108205760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610468565b6060813b6001811161104e575050604080516020810190915260008152919050565b80611058816117b9565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b60608151600161109291906117d0565b826040516020016110a49291906117e3565b6040516020818303038152906040529050919050565b6001600160a01b038116811461082057600080fd5b60008083601f8401126110e157600080fd5b50813567ffffffffffffffff8111156110f957600080fd5b60208301915083602082850101111561111157600080fd5b9250929050565b60008060008060008060008060c0898b03121561113457600080fd5b883561113f816110ba565b9750602089013561114f816110ba565b9650604089013561115f816110ba565b955060608901359450608089013567ffffffffffffffff8082111561118357600080fd5b61118f8c838d016110cf565b909650945060a08b01359150808211156111a857600080fd5b506111b58b828c016110cf565b999c989b5096995094979396929594505050565b6000806000806000608086880312156111e157600080fd5b85356111ec816110ba565b945060208601356111fc816110ba565b935060408601359250606086013567ffffffffffffffff81111561121f57600080fd5b61122b888289016110cf565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261126357600080fd5b813567ffffffffffffffff8082111561127e5761127e61123c565b604051601f8301601f19908116603f011681019082821181831017156112a6576112a661123c565b816040528381528660208588010111156112bf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156112f257600080fd5b82359150602083013567ffffffffffffffff81111561131057600080fd5b61131c85828601611252565b9150509250929050565b60008060006060848603121561133b57600080fd5b833567ffffffffffffffff81111561135257600080fd5b8401610160818703121561136557600080fd5b95602085013595506040909401359392505050565b60006020828403121561138c57600080fd5b81356105f9816110ba565b6000602082840312156113a957600080fd5b5035919050565b6000602082840312156113c257600080fd5b813567ffffffffffffffff8111156113d957600080fd5b6113e584828501611252565b949350505050565b60008083601f8401126113ff57600080fd5b50813567ffffffffffffffff81111561141757600080fd5b6020830191508360208260051b850101111561111157600080fd5b60008060008060008060008060a0898b03121561144e57600080fd5b8835611459816110ba565b97506020890135611469816110ba565b9650604089013567ffffffffffffffff8082111561148657600080fd5b6114928c838d016113ed565b909850965060608b01359150808211156114ab57600080fd5b6114b78c838d016113ed565b909650945060808b01359150808211156111a857600080fd5b600080600080600060a086880312156114e857600080fd5b85356114f3816110ba565b945060208601359350604086013567ffffffffffffffff81111561151657600080fd5b61152288828901611252565b93505060608601356002811061153757600080fd5b949793965091946080013592915050565b60005b8381101561156357818101518382015260200161154b565b50506000910152565b60008151808452611584816020860160208601611548565b601f01601f19169290920160200192915050565b6020815260006105f9602083018461156c565b600080604083850312156115be57600080fd5b82356115c9816110ba565b9150602083013567ffffffffffffffff81111561131057600080fd5b60008060008060008060a087890312156115fe57600080fd5b8635611609816110ba565b95506020870135611619816110ba565b94506040870135935060608701359250608087013567ffffffffffffffff81111561164357600080fd5b61164f89828a016110cf565b979a9699509497509295939492505050565b8281526040602082015260006113e5604083018461156c565b60006020828403121561168c57600080fd5b81516001600160e01b0319811681146105f957600080fd5b600080604083850312156116b757600080fd5b82516116c2816110ba565b6020939093015192949293505050565b6000808335601e198436030181126116e957600080fd5b83018035915067ffffffffffffffff82111561170457600080fd5b60200191503681900382131561111157600080fd5b60006020828403121561172b57600080fd5b81516105f9816110ba565b6001600160a01b03831681526040602082015260006113e5604083018461156c565b634e487b7160e01b600052601160045260246000fd5b60006001820161178057611780611758565b5060010190565b634e487b7160e01b600052602160045260246000fd5b600082516117af818460208701611548565b9190910192915050565b6000816117c8576117c8611758565b506000190190565b808201808211156105d5576105d5611758565b606360f81b815263ffffffff60e01b8360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201526000600e8201526000825161183e81600f850160208701611548565b91909101600f01939250505056fea26469706673582212202a03e14f0f05f58be9cbbba4646c39d989209350f0ee3edaaf0da00994a368d164736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/packages/valory/contracts/hash_checkpoint/contract.py b/packages/valory/contracts/hash_checkpoint/contract.py new file mode 100644 index 00000000..835db5aa --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/contract.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the hash checkpoint contract definition.""" +from enum import Enum +from typing import Any, Dict, List, cast + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi +from aea_ledger_ethereum import EthereumApi +from web3.types import BlockIdentifier, TxReceipt + + +class HashCheckpointContract(Contract): + """The scaffold contract class for a smart contract.""" + + contract_id = PublicId.from_str("valory/hash_checkpoint:0.1.0") + + @classmethod + def get_raw_transaction( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_RAW_TRANSACTION' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_raw_message( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> bytes: + """ + Handler method for the 'GET_RAW_MESSAGE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_state( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_STATE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_checkpoint_data( + cls, ledger_api: LedgerApi, contract_address: str, data: bytes + ) -> JSONLike: + """ + Deliver a response to a request. + + :param ledger_api: LedgerApi object + :param contract_address: the address of the token to be used + :param data: the ipfs hash + :return: the deliver data + """ + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI( + fn_name="checkpoint", args=[data] + ) + return {"data": data} + + @classmethod + def get_latest_hash( + cls, + ledger_api: LedgerApi, + contract_address: str, + sender_address: str, + ) -> JSONLike: + """Get the Request events emitted by the contract.""" + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + sender_address = ledger_api.api.to_checksum_address(sender_address) + latest_ipfs_hash = contract_instance.functions.latestHash(sender_address).call() + return {"data": latest_ipfs_hash} diff --git a/packages/valory/contracts/hash_checkpoint/contract.yaml b/packages/valory/contracts/hash_checkpoint/contract.yaml new file mode 100644 index 00000000..50872f62 --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/contract.yaml @@ -0,0 +1,21 @@ +name: hash_checkpoint +author: valory +version: 0.1.0 +type: contract +description: Hash checkpoint contract +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeigpq5lxfj2aza6ok3fjuywtdafelkbvoqwaits7regfbgu4oynmku + build/HashCheckpoint.json: bafybeidrlu7vpusp2tzovyf5rbnqy2jicuq3e6czizfkzswjq4rjusu72i + contract.py: bafybeihm4bmidifvp225rpxtg5xu5dyd5k65gm33jkoms2brrshvu5lige +fingerprint_ignore_patterns: [] +class_name: HashCheckpointContract +contract_interface_paths: + ethereum: build/HashCheckpoint.json +dependencies: + open-aea-ledger-ethereum: + version: ==1.41.0.post1 + web3: + version: <7,>=6.0.0 +contracts: [] diff --git a/packages/valory/skills/task_execution/behaviours.py b/packages/valory/skills/task_execution/behaviours.py index 0c8908ec..3adc51ef 100644 --- a/packages/valory/skills/task_execution/behaviours.py +++ b/packages/valory/skills/task_execution/behaviours.py @@ -274,8 +274,15 @@ def _handle_done_task(self, task_result: Any) -> None: executing_task = cast(Dict[str, Any], self._executing_task) req_id = executing_task.get("requestId", None) mech_address = executing_task.get("contract_address", None) + tool = executing_task.get("tool", None) response = {"requestId": req_id, "result": "Invalid response"} - self._done_task = {"request_id": req_id, "mech_address": mech_address} + task_executor = self.context.agent_address + self._done_task = { + "request_id": req_id, + "mech_address": mech_address, + "task_executor_address": task_executor, + "tool": tool, + } if task_result is not None: # task succeeded deliver_msg, prompt, transaction = task_result @@ -358,6 +365,7 @@ def _prepare_task(self, task_data: Dict[str, Any]) -> None: future = self._submit_task(tool_task.execute, **task_data) executing_task = cast(Dict[str, Any], self._executing_task) executing_task["timeout_deadline"] = time.time() + self.params.task_deadline + executing_task["tool"] = task_data["tool"] self._async_result = cast(Optional[Future], future) def _build_ipfs_message( diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index 8eb8c924..93590dc2 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -22,8 +22,9 @@ import json import threading import time +from abc import ABC from copy import deepcopy -from typing import Any, Dict, Generator, List, Optional, Set, Type, cast +from typing import Any, Dict, Generator, List, Optional, Set, Type, cast, Tuple import openai # noqa from multibase import multibase @@ -38,6 +39,7 @@ GnosisSafeContract, SafeOperation, ) +from packages.valory.contracts.hash_checkpoint.contract import HashCheckpointContract from packages.valory.contracts.multisend.contract import ( MultiSendContract, MultiSendOperation, @@ -71,7 +73,7 @@ NO_DATA = b"" -class TaskExecutionBaseBehaviour(BaseBehaviour, abc.ABC): +class TaskExecutionBaseBehaviour(BaseBehaviour, ABC): """Base behaviour for the task_execution_abci skill.""" @property @@ -139,7 +141,7 @@ def to_multihash(hash_string: str) -> str: return hex_multihash[6:] -class TaskPoolingBehaviour(TaskExecutionBaseBehaviour): +class TaskPoolingBehaviour(TaskExecutionBaseBehaviour, ABC): """TaskPoolingBehaviour""" matching_round: Type[AbstractRound] = TaskPoolingRound @@ -188,7 +190,7 @@ def handle_submitted_tasks(self) -> None: self.remove_tasks(submitted_tasks) -class FundsSplittingBehaviour(TaskExecutionBaseBehaviour): +class FundsSplittingBehaviour(TaskExecutionBaseBehaviour, ABC): """FundsSplittingBehaviour""" def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: @@ -436,6 +438,94 @@ def _accumulate_reqs_by_operator( return reqs_by_operator +class TrackingBehaviour(TaskExecutionBaseBehaviour, ABC): + """Behaviour to track the execution of a task.""" + + def _get_checkpoint_tx( + self, + hashcheckpoint_address: str, + ipfs_hash: bytes, + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the transfer tx.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=hashcheckpoint_address, + contract_id=str(HashCheckpointContract.contract_id), + contract_callable="get_checkpoint_data", + ipfs_hash=ipfs_hash, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_checkpoint_data unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": hashcheckpoint_address, + "value": ZERO_ETHER_VALUE, + "data": data, + } + + def _get_current_usage( + self + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the current .""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, + contract_address=self.params.hash_checkpoint_address, + contract_id=str(HashCheckpointContract.contract_id), + contract_callable="get_latest_hash", + sender_address=self.synchronized_data.safe_contract_address, + ) + if contract_api_msg.performative != ContractApiMessage.Performative.STATE: + self.context.logger.warning( + f"get_latest_hash unsuccessful!: {contract_api_msg}" + ) + return None + latest_ipfs_hash = cast(str, contract_api_msg.state.body["data"]) + usage_data = yield from self.get_from_ipfs(latest_ipfs_hash) + if usage_data is None: + self.context.logger.warning( + f"Could not get usage data from IPFS: {latest_ipfs_hash}" + ) + return None + return usage_data + + def _update_usage( + self, + current_usage: Dict[str, Any], + done_tasks: List[Dict[str, Any]], + ) -> Generator[None, None, Optional[Tuple[str, Dict[str, Any]]]]: + """Update the usage of the tool on IPFS.""" + for task in done_tasks: + agent, tool = task["executor_address"], task["tool"] + if agent not in current_usage: + current_usage[agent] = {} + if tool not in current_usage[agent]: + current_usage[agent][tool] = 0 + current_usage[agent][tool] += 1 + ipfs_hash = yield from self.send_to_ipfs("usage", current_usage) + if ipfs_hash is None: + self.context.logger.warning("Could not update usage.") + return None + return ipfs_hash, current_usage + + def get_update_usage_tx(self) -> Generator: + """Get a tx to update the usage.""" + current_usage = yield from self._get_current_usage() + if current_usage is None: + # something went wrong + self.context.logger.warning("Could not get current usage.") + return None + + updated_usage, ipfs_hash = yield from self._update_usage(current_usage, self.synchronized_data.done_tasks) + tx = yield from self._get_checkpoint_tx(self.params.hash_checkpoint_address, ipfs_hash) + return tx + + class HashUpdateBehaviour(TaskExecutionBaseBehaviour): """HashUpdateBehaviour""" diff --git a/packages/valory/skills/task_submission_abci/models.py b/packages/valory/skills/task_submission_abci/models.py index a00ef15a..c5534b1c 100644 --- a/packages/valory/skills/task_submission_abci/models.py +++ b/packages/valory/skills/task_submission_abci/models.py @@ -66,6 +66,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.manual_gas_limit = self._ensure("manual_gas_limit", kwargs, int) self.service_owner_share = self._ensure("service_owner_share", kwargs, float) self.profit_split_freq = self._ensure("profit_split_freq", kwargs, int) + self.hash_checkpoint_address = self._ensure("hash_checkpoint_address", kwargs, str) super().__init__(*args, **kwargs) diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index 4343c282..70adc0ca 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -110,6 +110,7 @@ models: keeper_timeout: 30.0 max_attempts: 10 max_healthcheck: 120 + hash_checkpoint_address: '0x0000000000000000000000000000000000000000' on_chain_service_id: null request_retry_delay: 1.0 request_timeout: 10.0 From d7609c465adf885df1f0a965e816e6535949f2e5 Mon Sep 17 00:00:00 2001 From: Ardian Date: Fri, 24 Nov 2023 19:54:38 +0100 Subject: [PATCH 4/8] fix: misc issues discovered during testing --- packages/packages.json | 18 +- packages/valory/agents/mech/aea-config.yaml | 8 +- .../valory/contracts/agent_mech/contract.yaml | 2 +- .../contracts/hash_checkpoint/contract.yaml | 4 +- packages/valory/services/mech/service.yaml | 2 +- packages/valory/skills/mech_abci/skill.yaml | 5 +- .../skills/task_execution/behaviours.py | 1 + .../valory/skills/task_execution/skill.yaml | 4 +- .../skills/task_submission_abci/behaviours.py | 181 ++++++++++++------ .../skills/task_submission_abci/skill.yaml | 9 +- 10 files changed, 152 insertions(+), 82 deletions(-) diff --git a/packages/packages.json b/packages/packages.json index f17ae2a0..4630afc5 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,16 +2,17 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeifw2qj6n7kwpjdhupjkcwdz4ydqur4j7744jb3vtevcucxcylpd2e", - "skill/valory/mech_abci/0.1.0": "bafybeihm6tdacrqw3fg4tpujrsi3p3owx4qxem3ehmzntjvxdjie4twcom", - "contract/valory/agent_mech/0.1.0": "bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u", - "service/valory/mech/0.1.0": "bafybeigjxfgvkjotfodzell24wvcg74lm2t7rcxdhsdgty2aczhhxcpudy", + "agent/valory/mech/0.1.0": "bafybeic67wwmmkkygnz5klo5zn4jgixc2mnyugsrcilx3oe4ut4ya4v66u", + "skill/valory/mech_abci/0.1.0": "bafybeige2sthqncsypcav5mxr2xbbwrkylgnjjzgtaetvmzexucfwqrhye", + "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", + "service/valory/mech/0.1.0": "bafybeie6ygxmy2fvvitro4f54qaapn2hqdazz6vnku3wfofbpqecjvbnai", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra", - "skill/valory/task_execution/0.1.0": "bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue", + "skill/valory/task_submission_abci/0.1.0": "bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy", + "skill/valory/task_execution/0.1.0": "bafybeibibozam4q4f2p6oewt4a4dhpewpwahtwebes4x5zu4x3scmysad4", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", - "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta" + "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta", + "contract/valory/hash_checkpoint/0.1.0": "bafybeiap5fvi2w53e4uwxt75gjzie557hwuegf76xupimx3dvpkgfmj4ei" }, "third_party": { "skill/valory/transaction_settlement_abci/0.1.0": "bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q", @@ -37,6 +38,7 @@ "connection/valory/p2p_libp2p_client/0.1.0": "bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq", "contract/valory/gnosis_safe_proxy_factory/0.1.0": "bafybeig6evakqztiuyn67vwv63fzgqqfig4whp4qlef3w6pf7hmngrw3si", "contract/valory/gnosis_safe/0.1.0": "bafybeie7qpo4sue4i54pzsg6nx365q6d3i4sl6ygdilwldqqxwroukbkiu", - "contract/valory/multisend/0.1.0": "bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y" + "contract/valory/multisend/0.1.0": "bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y", + "connection/valory/http_server/0.22.0": "bafybeie6g5hxhvdijyjlz4opquapxbsh6udzdjvlqhguwd6wp5cb5a5wuy" } } \ No newline at end of file diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index 43fc1356..ecfe6472 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -14,7 +14,7 @@ connections: - valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq - valory/websocket_client:0.1.0:bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 - valory/gnosis_safe:0.1.0:bafybeie7qpo4sue4i54pzsg6nx365q6d3i4sl6ygdilwldqqxwroukbkiu - valory/gnosis_safe_proxy_factory:0.1.0:bafybeig6evakqztiuyn67vwv63fzgqqfig4whp4qlef3w6pf7hmngrw3si - valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y @@ -36,11 +36,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeihm6tdacrqw3fg4tpujrsi3p3owx4qxem3ehmzntjvxdjie4twcom -- valory/task_execution:0.1.0:bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue +- valory/mech_abci:0.1.0:bafybeige2sthqncsypcav5mxr2xbbwrkylgnjjzgtaetvmzexucfwqrhye +- valory/task_execution:0.1.0:bafybeibibozam4q4f2p6oewt4a4dhpewpwahtwebes4x5zu4x3scmysad4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra +- valory/task_submission_abci:0.1.0:bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/contracts/agent_mech/contract.yaml b/packages/valory/contracts/agent_mech/contract.yaml index 89f578b6..f0e94c07 100644 --- a/packages/valory/contracts/agent_mech/contract.yaml +++ b/packages/valory/contracts/agent_mech/contract.yaml @@ -8,7 +8,7 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeigpq5lxfj2aza6ok3fjuywtdafelkbvoqwaits7regfbgu4oynmku build/AgentMech.json: bafybeidrlu7vpusp2tzovyf5rbnqy2jicuq3e6czizfkzswjq4rjusu72i - contract.py: bafybeihm4bmidifvp225rpxtg5xu5dyd5k65gm33jkoms2brrshvu5lige + contract.py: bafybeig65qzfwsetro4ncnb4zlmtws3dliun6q57mw3xzy7qh5s2kczj64 fingerprint_ignore_patterns: [] class_name: AgentMechContract contract_interface_paths: diff --git a/packages/valory/contracts/hash_checkpoint/contract.yaml b/packages/valory/contracts/hash_checkpoint/contract.yaml index 50872f62..e5cbf9ad 100644 --- a/packages/valory/contracts/hash_checkpoint/contract.yaml +++ b/packages/valory/contracts/hash_checkpoint/contract.yaml @@ -7,8 +7,8 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeigpq5lxfj2aza6ok3fjuywtdafelkbvoqwaits7regfbgu4oynmku - build/HashCheckpoint.json: bafybeidrlu7vpusp2tzovyf5rbnqy2jicuq3e6czizfkzswjq4rjusu72i - contract.py: bafybeihm4bmidifvp225rpxtg5xu5dyd5k65gm33jkoms2brrshvu5lige + build/HashCheckpoint.json: bafybeicdse6k7xbis3mdurqee7a3ghiba4hzfk4llhc3hk6q4qbfjd5rg4 + contract.py: bafybeiaklk45tud5qogk6zeufwlewlgbaunux5kbahj4auf6xzkikfgwru fingerprint_ignore_patterns: [] class_name: HashCheckpointContract contract_interface_paths: diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index 6df3c1c3..fdc47f8b 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeifw2qj6n7kwpjdhupjkcwdz4ydqur4j7744jb3vtevcucxcylpd2e +agent: valory/mech:0.1.0:bafybeic67wwmmkkygnz5klo5zn4jgixc2mnyugsrcilx3oe4ut4ya4v66u number_of_agents: 4 deployment: agent: diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index ef47697c..2dff839d 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -21,7 +21,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra +- valory/task_submission_abci:0.1.0:bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: @@ -157,8 +157,11 @@ models: agent_id: 3 metadata_hash: '00000000000000000000000000000000000000000000000000' slash_cooldown_hours: 3 + hash_checkpoint_address: '0x0000000000000000000000000000000000000000' slash_threshold_amount: 10000000000000000 light_slash_unit_amount: 5000000000000000 + service_owner_share: 0.1 + profit_split_freq: 100 serious_slash_unit_amount: 8000000000000000 class_name: Params randomness_api: diff --git a/packages/valory/skills/task_execution/behaviours.py b/packages/valory/skills/task_execution/behaviours.py index 3adc51ef..08b01c22 100644 --- a/packages/valory/skills/task_execution/behaviours.py +++ b/packages/valory/skills/task_execution/behaviours.py @@ -337,6 +337,7 @@ def _handle_get_task(self, message: IpfsMessage, dialogue: Dialogue) -> None: self._prepare_task(task_data) elif is_data_valid: tool = task_data["tool"] + self._executing_task["tool"] = tool self.context.logger.warning(f"Tool {tool} is not valid.") self._invalid_request = True else: diff --git a/packages/valory/skills/task_execution/skill.yaml b/packages/valory/skills/task_execution/skill.yaml index b7ba2c09..313f2b92 100644 --- a/packages/valory/skills/task_execution/skill.yaml +++ b/packages/valory/skills/task_execution/skill.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeidqhvvlnthkbnmrdkdeyjyx2f2ab6z4xdgmagh7welqnh2v6wczx4 - behaviours.py: bafybeie4h4m4py7u3ah4mcotiah32umi7lb5xnxmzpvvhikushaedcglkq + behaviours.py: bafybeichcbo5txi3capzii4stvamqutr5w43cguloveeqyacnxklwo3nea dialogues.py: bafybeid4zxalqdlo5mw4yfbuf34hx4jp5ay5z6chm4zviwu4cj7fudtwca handlers.py: bafybeidbt5ezj74cgfogk3w4uw4si2grlnk5g54veyumw7g5yh6gdscywu models.py: bafybeihc2kmymmh5oousjddbc7xujqbk5niermuqak2dhtgryukzq5wxeq @@ -20,7 +20,7 @@ connections: - valory/ipfs:0.1.0:bafybeigfmqvlzbp67fttccpl4hsu3zaztbxv6vd7ikzra2hfppfkalgpji - valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 protocols: - valory/acn_data_share:0.1.0:bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq - valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index 93590dc2..e8cf746a 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -27,6 +27,7 @@ from typing import Any, Dict, Generator, List, Optional, Set, Type, cast, Tuple import openai # noqa +from aea.helpers.cid import to_v1, CID from multibase import multibase from multicodec import multicodec @@ -52,6 +53,7 @@ AbstractRoundBehaviour, BaseBehaviour, ) +from packages.valory.skills.abstract_round_abci.io_.store import SupportedFiletype from packages.valory.skills.task_submission_abci.models import Params from packages.valory.skills.task_submission_abci.payloads import TransactionPayload from packages.valory.skills.task_submission_abci.rounds import ( @@ -71,7 +73,8 @@ DONE_TASKS = "ready_tasks" DONE_TASKS_LOCK = "lock" NO_DATA = b"" - +ZERO_IPFS_HASH = "f017012200000000000000000000000000000000000000000000000000000000000000000" +FILENAME = "usage" class TaskExecutionBaseBehaviour(BaseBehaviour, ABC): """Base behaviour for the task_execution_abci skill.""" @@ -127,7 +130,7 @@ def remove_tasks(self, submitted_tasks: List[Dict[str, Any]]) -> None: @property def mech_addresses(self) -> List[str]: """Get the addresses of the MECHs.""" - return self.context.params.mech_addresses + return self.context.params.agent_mech_contract_addresses @staticmethod def to_multihash(hash_string: str) -> str: @@ -190,7 +193,82 @@ def handle_submitted_tasks(self) -> None: self.remove_tasks(submitted_tasks) -class FundsSplittingBehaviour(TaskExecutionBaseBehaviour, ABC): +class DeliverBehaviour(TaskExecutionBaseBehaviour, ABC): + """Behaviour for tracking task delivery by the agents.""" + + def _get_current_delivery_report( + self + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the current .""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, + contract_address=self.params.hash_checkpoint_address, + contract_id=str(HashCheckpointContract.contract_id), + contract_callable="get_latest_hash", + sender_address=self.synchronized_data.safe_contract_address, + ) + if contract_api_msg.performative != ContractApiMessage.Performative.STATE: + self.context.logger.warning( + f"get_latest_hash unsuccessful!: {contract_api_msg}" + ) + return None + latest_ipfs_hash = cast(str, contract_api_msg.state.body["data"]) + self.context.logger.debug(f"Latest IPFS hash: {latest_ipfs_hash}") + if latest_ipfs_hash == ZERO_IPFS_HASH: + return {} + # format the hash + ipfs_hash = str(CID.from_string(latest_ipfs_hash)) + usage_data = yield from self.get_from_ipfs(ipfs_hash, filetype=SupportedFiletype.JSON) + if usage_data is None: + self.context.logger.warning( + f"Could not get usage data from IPFS: {latest_ipfs_hash}" + ) + return None + return usage_data + + def _update_current_delivery_report( + self, + current_usage: Dict[str, Any], + done_tasks: List[Dict[str, Any]], + ) -> Dict[str, Any]: + """Update the usage of the tool on IPFS.""" + for task in done_tasks: + agent, tool = task["task_executor_address"], task["tool"] + if agent not in current_usage: + current_usage[agent] = {} + if tool not in current_usage[agent]: + current_usage[agent][tool] = 0 + current_usage[agent][tool] += 1 + return current_usage + + def get_delivery_report(self) -> Generator[None, None, Optional[Dict[str, Any]]]: + """ + Get the task delivery report. + + This method returns a dictionary of the form: + { + "agent_address": { + "tool_name": num_delivered_tasks + } + } + + Note that the report contains the tasks that are being delivered on-chain in the current period. + + :return: the delivery report: + :yield: None + """ + current_usage = yield from self._get_current_delivery_report() + if current_usage is None: + # something went wrong + self.context.logger.warning("Could not get current usage.") + return None + + done_tasks = self.synchronized_data.done_tasks + updated_usage = self._update_current_delivery_report(current_usage, done_tasks) + return updated_usage + + +class FundsSplittingBehaviour(DeliverBehaviour, ABC): """FundsSplittingBehaviour""" def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: @@ -205,16 +283,21 @@ def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: total_reqs = sum(reqs_by_agent.values()) return total_reqs - def _get_num_reqs_by_agent(self) -> Generator[None, None, Dict[str, int]]: + def _get_num_reqs_by_agent(self) -> Generator[None, None, Optional[Dict[str, int]]]: """Return the total number of requests delivered.""" - # TODO: implement once the storage is ready - return { - "agent0": 0, - "agent1": 1, - "agent2": 2, - "agent3": 3, - } - yield + delivery_report = yield from self.get_delivery_report() + if delivery_report is None: + self.context.logger.warning( + "Could not get delivery report. Don't split profits." + ) + return None + + # accumulate the number of requests delivered by each agent + reqs_by_agent = {} + for agent, tool_usage in delivery_report.items(): + reqs_by_agent[agent] = sum(tool_usage.values()) + + return reqs_by_agent def _should_split_profits(self) -> Generator[None, None, bool]: """ @@ -438,13 +521,13 @@ def _accumulate_reqs_by_operator( return reqs_by_operator -class TrackingBehaviour(TaskExecutionBaseBehaviour, ABC): +class TrackingBehaviour(DeliverBehaviour, ABC): """Behaviour to track the execution of a task.""" def _get_checkpoint_tx( self, hashcheckpoint_address: str, - ipfs_hash: bytes, + ipfs_hash: str, ) -> Generator[None, None, Optional[Dict[str, Any]]]: """Get the transfer tx.""" contract_api_msg = yield from self.get_contract_api_response( @@ -452,7 +535,7 @@ def _get_checkpoint_tx( contract_address=hashcheckpoint_address, contract_id=str(HashCheckpointContract.contract_id), contract_callable="get_checkpoint_data", - ipfs_hash=ipfs_hash, + data=bytes.fromhex(ipfs_hash), ) if ( contract_api_msg.performative != ContractApiMessage.Performative.STATE @@ -469,64 +552,35 @@ def _get_checkpoint_tx( "data": data, } - def _get_current_usage( - self - ) -> Generator[None, None, Optional[Dict[str, Any]]]: - """Get the current .""" - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, - contract_address=self.params.hash_checkpoint_address, - contract_id=str(HashCheckpointContract.contract_id), - contract_callable="get_latest_hash", - sender_address=self.synchronized_data.safe_contract_address, - ) - if contract_api_msg.performative != ContractApiMessage.Performative.STATE: - self.context.logger.warning( - f"get_latest_hash unsuccessful!: {contract_api_msg}" - ) - return None - latest_ipfs_hash = cast(str, contract_api_msg.state.body["data"]) - usage_data = yield from self.get_from_ipfs(latest_ipfs_hash) - if usage_data is None: - self.context.logger.warning( - f"Could not get usage data from IPFS: {latest_ipfs_hash}" - ) - return None - return usage_data - - def _update_usage( - self, - current_usage: Dict[str, Any], - done_tasks: List[Dict[str, Any]], - ) -> Generator[None, None, Optional[Tuple[str, Dict[str, Any]]]]: - """Update the usage of the tool on IPFS.""" - for task in done_tasks: - agent, tool = task["executor_address"], task["tool"] - if agent not in current_usage: - current_usage[agent] = {} - if tool not in current_usage[agent]: - current_usage[agent][tool] = 0 - current_usage[agent][tool] += 1 - ipfs_hash = yield from self.send_to_ipfs("usage", current_usage) + def _save_usage_to_ipfs(self, current_usage: Dict[str, Any]) -> Generator[None, None, Optional[str]]: + """Save usage to ipfs.""" + ipfs_hash = yield from self.send_to_ipfs(FILENAME, current_usage, filetype=SupportedFiletype.JSON) if ipfs_hash is None: self.context.logger.warning("Could not update usage.") return None - return ipfs_hash, current_usage + return ipfs_hash def get_update_usage_tx(self) -> Generator: """Get a tx to update the usage.""" - current_usage = yield from self._get_current_usage() - if current_usage is None: + updated_usage = yield from self.get_delivery_report() + if updated_usage is None: # something went wrong self.context.logger.warning("Could not get current usage.") return None - updated_usage, ipfs_hash = yield from self._update_usage(current_usage, self.synchronized_data.done_tasks) + ipfs_hash = yield from self._save_usage_to_ipfs(updated_usage) + if ipfs_hash is None: + # something went wrong + self.context.logger.warning("Could not save usage to IPFS.") + return None + + self.context.logger.info(f"Saved updated usage to IPFS: {ipfs_hash}") + ipfs_hash = self.to_multihash(to_v1(ipfs_hash)) tx = yield from self._get_checkpoint_tx(self.params.hash_checkpoint_address, ipfs_hash) return tx -class HashUpdateBehaviour(TaskExecutionBaseBehaviour): +class HashUpdateBehaviour(TaskExecutionBaseBehaviour, ABC): """HashUpdateBehaviour""" def _get_latest_hash(self) -> Generator[None, None, Optional[bytes]]: @@ -596,7 +650,7 @@ def get_mech_update_hash_tx(self) -> Generator: } -class TransactionPreparationBehaviour(FundsSplittingBehaviour, HashUpdateBehaviour): +class TransactionPreparationBehaviour(FundsSplittingBehaviour, HashUpdateBehaviour, TrackingBehaviour): """TransactionPreparationBehaviour""" matching_round: Type[AbstractRound] = TransactionPreparationRound @@ -640,6 +694,13 @@ def get_payload_content(self) -> Generator[None, None, str]: if response_tx is not None: all_txs.append(response_tx) + update_usage_tx = yield from self.get_update_usage_tx() + if update_usage_tx is None: + # something went wrong, respond with ERROR payload for now + # in case we cannot update the usage, we should not proceed with the rest of the txs + return TransactionPreparationRound.ERROR_PAYLOAD + + all_txs.append(update_usage_tx) multisend_tx_str = yield from self._to_multisend(all_txs) if multisend_tx_str is None: # something went wrong, respond with ERROR payload for now diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index 70adc0ca..f2af43c0 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -8,24 +8,27 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiholqak7ltw6bbmn2c5tn3j7xgzkdlfzp3kcskiqsvmxoih6m4muq - behaviours.py: bafybeihcxwfsxa5hxftpqnm5ujtckk5ulsqdbtfavzblt3ae3qcbxg2o5e + behaviours.py: bafybeienfwhleyod5mugzn5q3xpjc5oda7zudxk67fsocavu37awktlpem dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq - models.py: bafybeib6d45xymtpy7qhjzeb37imgtmibqqfpekd5uqqetottw6riddxtu + models.py: bafybeigyrdverkmdxywd7cque7kfqgchi2p7nsdynvetkjqtmtepymfqfm payloads.py: bafybeia2yorri2u5rwh6vukb6iwdrbn53ygsuuhthns2txptvjipyb6f4e rounds.py: bafybeicstmau4vlzpxz3kjgiwwsetwmotdk4un4iucmdddzvot5dgdkg2a tasks.py: bafybeicu5t5cvfhbndgpxbbtmp4vbmtyb6fba6vsnlewftvuderxp5lwcy fingerprint_ignore_patterns: [] connections: [] contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 - valory/agent_registry:0.1.0:bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu - valory/gnosis_safe:0.1.0:bafybeie7qpo4sue4i54pzsg6nx365q6d3i4sl6ygdilwldqqxwroukbkiu - valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y +- valory/service_registry:0.1.0:bafybeib6eed4u2dqggq7jpnb4lury6ylqzdxp6oxxvgrouhcvtmwsbsjbq +- valory/hash_checkpoint:0.1.0:bafybeiap5fvi2w53e4uwxt75gjzie557hwuegf76xupimx3dvpkgfmj4ei protocols: - valory/acn_data_share:0.1.0:bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq - valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q From 114f52650f696a7ace43390f8865a7833920c601 Mon Sep 17 00:00:00 2001 From: Ardian Date: Mon, 27 Nov 2023 11:52:58 +0100 Subject: [PATCH 5/8] fix: `exec` call via mech --- packages/packages.json | 10 ++--- packages/valory/agents/mech/aea-config.yaml | 6 +-- packages/valory/services/mech/service.yaml | 2 +- packages/valory/skills/mech_abci/skill.yaml | 2 +- .../skills/task_execution/behaviours.py | 3 +- .../valory/skills/task_execution/skill.yaml | 2 +- .../skills/task_submission_abci/behaviours.py | 42 ++++++++++++------- .../skills/task_submission_abci/models.py | 4 +- .../skills/task_submission_abci/skill.yaml | 4 +- 9 files changed, 45 insertions(+), 30 deletions(-) diff --git a/packages/packages.json b/packages/packages.json index 4630afc5..07a8e84f 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,13 +2,13 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeic67wwmmkkygnz5klo5zn4jgixc2mnyugsrcilx3oe4ut4ya4v66u", - "skill/valory/mech_abci/0.1.0": "bafybeige2sthqncsypcav5mxr2xbbwrkylgnjjzgtaetvmzexucfwqrhye", + "agent/valory/mech/0.1.0": "bafybeieaxtrvyxksi64znth77cz3xo352ne24svn7zr3b4stxpin2jhzzy", + "skill/valory/mech_abci/0.1.0": "bafybeigjandpn6voupdy65mpnawlo2szqbtptsqn4uirbffrzjehurg3r4", "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", - "service/valory/mech/0.1.0": "bafybeie6ygxmy2fvvitro4f54qaapn2hqdazz6vnku3wfofbpqecjvbnai", + "service/valory/mech/0.1.0": "bafybeibrbx27ldbwnbxjdmgnsfqtcjdbbvlyauawhfhjmmnic3npb2ye5u", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy", - "skill/valory/task_execution/0.1.0": "bafybeibibozam4q4f2p6oewt4a4dhpewpwahtwebes4x5zu4x3scmysad4", + "skill/valory/task_submission_abci/0.1.0": "bafybeid7h3x37jplw4yq5u3jkbeq64dkwtafet7tfez5uol47ywdyqexve", + "skill/valory/task_execution/0.1.0": "bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta", diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index ecfe6472..bfabdc95 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -36,11 +36,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeige2sthqncsypcav5mxr2xbbwrkylgnjjzgtaetvmzexucfwqrhye -- valory/task_execution:0.1.0:bafybeibibozam4q4f2p6oewt4a4dhpewpwahtwebes4x5zu4x3scmysad4 +- valory/mech_abci:0.1.0:bafybeigjandpn6voupdy65mpnawlo2szqbtptsqn4uirbffrzjehurg3r4 +- valory/task_execution:0.1.0:bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy +- valory/task_submission_abci:0.1.0:bafybeid7h3x37jplw4yq5u3jkbeq64dkwtafet7tfez5uol47ywdyqexve - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index fdc47f8b..d94d16d7 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeic67wwmmkkygnz5klo5zn4jgixc2mnyugsrcilx3oe4ut4ya4v66u +agent: valory/mech:0.1.0:bafybeieaxtrvyxksi64znth77cz3xo352ne24svn7zr3b4stxpin2jhzzy number_of_agents: 4 deployment: agent: diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index 2dff839d..3a9d93f4 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -21,7 +21,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeigzbkoy7hhhv5uiv2a7v63dlslpzm75auvk6gt63ohrvoi45cnyqy +- valory/task_submission_abci:0.1.0:bafybeid7h3x37jplw4yq5u3jkbeq64dkwtafet7tfez5uol47ywdyqexve - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: diff --git a/packages/valory/skills/task_execution/behaviours.py b/packages/valory/skills/task_execution/behaviours.py index 08b01c22..be421477 100644 --- a/packages/valory/skills/task_execution/behaviours.py +++ b/packages/valory/skills/task_execution/behaviours.py @@ -337,7 +337,8 @@ def _handle_get_task(self, message: IpfsMessage, dialogue: Dialogue) -> None: self._prepare_task(task_data) elif is_data_valid: tool = task_data["tool"] - self._executing_task["tool"] = tool + executing_task = cast(Dict[str, Any], self._executing_task) + executing_task["tool"] = tool self.context.logger.warning(f"Tool {tool} is not valid.") self._invalid_request = True else: diff --git a/packages/valory/skills/task_execution/skill.yaml b/packages/valory/skills/task_execution/skill.yaml index 313f2b92..cc96dd14 100644 --- a/packages/valory/skills/task_execution/skill.yaml +++ b/packages/valory/skills/task_execution/skill.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeidqhvvlnthkbnmrdkdeyjyx2f2ab6z4xdgmagh7welqnh2v6wczx4 - behaviours.py: bafybeichcbo5txi3capzii4stvamqutr5w43cguloveeqyacnxklwo3nea + behaviours.py: bafybeiahzfpgcjpvbhpfkbifrkzb6qaj2gesnkswdi2lj7yszhe27dvjtm dialogues.py: bafybeid4zxalqdlo5mw4yfbuf34hx4jp5ay5z6chm4zviwu4cj7fudtwca handlers.py: bafybeidbt5ezj74cgfogk3w4uw4si2grlnk5g54veyumw7g5yh6gdscywu models.py: bafybeihc2kmymmh5oousjddbc7xujqbk5niermuqak2dhtgryukzq5wxeq diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index e8cf746a..1777c250 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -18,16 +18,15 @@ # ------------------------------------------------------------------------------ """This package contains round behaviours of TaskExecutionAbciApp.""" -import abc import json import threading import time from abc import ABC from copy import deepcopy -from typing import Any, Dict, Generator, List, Optional, Set, Type, cast, Tuple +from typing import Any, Dict, Generator, List, Optional, Set, Type, cast import openai # noqa -from aea.helpers.cid import to_v1, CID +from aea.helpers.cid import CID, to_v1 from multibase import multibase from multicodec import multicodec @@ -73,9 +72,12 @@ DONE_TASKS = "ready_tasks" DONE_TASKS_LOCK = "lock" NO_DATA = b"" -ZERO_IPFS_HASH = "f017012200000000000000000000000000000000000000000000000000000000000000000" +ZERO_IPFS_HASH = ( + "f017012200000000000000000000000000000000000000000000000000000000000000000" +) FILENAME = "usage" + class TaskExecutionBaseBehaviour(BaseBehaviour, ABC): """Base behaviour for the task_execution_abci skill.""" @@ -197,11 +199,11 @@ class DeliverBehaviour(TaskExecutionBaseBehaviour, ABC): """Behaviour for tracking task delivery by the agents.""" def _get_current_delivery_report( - self + self, ) -> Generator[None, None, Optional[Dict[str, Any]]]: """Get the current .""" contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore contract_address=self.params.hash_checkpoint_address, contract_id=str(HashCheckpointContract.contract_id), contract_callable="get_latest_hash", @@ -218,13 +220,15 @@ def _get_current_delivery_report( return {} # format the hash ipfs_hash = str(CID.from_string(latest_ipfs_hash)) - usage_data = yield from self.get_from_ipfs(ipfs_hash, filetype=SupportedFiletype.JSON) + usage_data = yield from self.get_from_ipfs( + ipfs_hash, filetype=SupportedFiletype.JSON + ) if usage_data is None: self.context.logger.warning( f"Could not get usage data from IPFS: {latest_ipfs_hash}" ) return None - return usage_data + return cast(Dict[str, Any], usage_data) def _update_current_delivery_report( self, @@ -364,7 +368,7 @@ def get_split_profit_txs( def _get_profits(self, address: str) -> Generator[None, None, int]: """Get the profits.""" ledger_api_response = yield from self.get_ledger_api_response( - performative=LedgerApiMessage.Performative.GET_STATE, + performative=LedgerApiMessage.Performative.GET_STATE, # type: ignore ledger_callable="get_balance", account=address, ) @@ -421,7 +425,7 @@ def _get_transfer_tx( value=amount, data=NO_DATA, tx_gas=AUTO_GAS, - operation=MechOperation.CALL, + operation=MechOperation.CALL.value, ) if ( contract_api_msg.performative != ContractApiMessage.Performative.STATE @@ -444,7 +448,7 @@ def _get_service_owner( ) -> Generator[None, None, Optional[str]]: """Get the service owner address.""" contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore contract_address=self.params.service_registry_address, contract_id=str(ServiceRegistryContract.contract_id), contract_callable="get_service_owner", @@ -552,9 +556,13 @@ def _get_checkpoint_tx( "data": data, } - def _save_usage_to_ipfs(self, current_usage: Dict[str, Any]) -> Generator[None, None, Optional[str]]: + def _save_usage_to_ipfs( + self, current_usage: Dict[str, Any] + ) -> Generator[None, None, Optional[str]]: """Save usage to ipfs.""" - ipfs_hash = yield from self.send_to_ipfs(FILENAME, current_usage, filetype=SupportedFiletype.JSON) + ipfs_hash = yield from self.send_to_ipfs( + FILENAME, current_usage, filetype=SupportedFiletype.JSON + ) if ipfs_hash is None: self.context.logger.warning("Could not update usage.") return None @@ -576,7 +584,9 @@ def get_update_usage_tx(self) -> Generator: self.context.logger.info(f"Saved updated usage to IPFS: {ipfs_hash}") ipfs_hash = self.to_multihash(to_v1(ipfs_hash)) - tx = yield from self._get_checkpoint_tx(self.params.hash_checkpoint_address, ipfs_hash) + tx = yield from self._get_checkpoint_tx( + self.params.hash_checkpoint_address, ipfs_hash + ) return tx @@ -650,7 +660,9 @@ def get_mech_update_hash_tx(self) -> Generator: } -class TransactionPreparationBehaviour(FundsSplittingBehaviour, HashUpdateBehaviour, TrackingBehaviour): +class TransactionPreparationBehaviour( + FundsSplittingBehaviour, HashUpdateBehaviour, TrackingBehaviour +): """TransactionPreparationBehaviour""" matching_round: Type[AbstractRound] = TransactionPreparationRound diff --git a/packages/valory/skills/task_submission_abci/models.py b/packages/valory/skills/task_submission_abci/models.py index c5534b1c..7ce93c4a 100644 --- a/packages/valory/skills/task_submission_abci/models.py +++ b/packages/valory/skills/task_submission_abci/models.py @@ -66,7 +66,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.manual_gas_limit = self._ensure("manual_gas_limit", kwargs, int) self.service_owner_share = self._ensure("service_owner_share", kwargs, float) self.profit_split_freq = self._ensure("profit_split_freq", kwargs, int) - self.hash_checkpoint_address = self._ensure("hash_checkpoint_address", kwargs, str) + self.hash_checkpoint_address = self._ensure( + "hash_checkpoint_address", kwargs, str + ) super().__init__(*args, **kwargs) diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index f2af43c0..65be5d01 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -8,11 +8,11 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiholqak7ltw6bbmn2c5tn3j7xgzkdlfzp3kcskiqsvmxoih6m4muq - behaviours.py: bafybeienfwhleyod5mugzn5q3xpjc5oda7zudxk67fsocavu37awktlpem + behaviours.py: bafybeia7arkt3helbxvjjlnmoucqupftzcjg5h35afzqu5wx7yfafljhiy dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq - models.py: bafybeigyrdverkmdxywd7cque7kfqgchi2p7nsdynvetkjqtmtepymfqfm + models.py: bafybeidcd3n33xyjgekbp3mc3a5g3kxtlglqt6awgbovhg7ovasdqvm7wi payloads.py: bafybeia2yorri2u5rwh6vukb6iwdrbn53ygsuuhthns2txptvjipyb6f4e rounds.py: bafybeicstmau4vlzpxz3kjgiwwsetwmotdk4un4iucmdddzvot5dgdkg2a tasks.py: bafybeicu5t5cvfhbndgpxbbtmp4vbmtyb6fba6vsnlewftvuderxp5lwcy From 25501d1437d89f1dc624eceffdd5ef6be7aa24bc Mon Sep 17 00:00:00 2001 From: Ardian Date: Mon, 27 Nov 2023 12:01:39 +0100 Subject: [PATCH 6/8] chore: sync with main --- packages/packages.json | 12 ++++++------ packages/valory/agents/mech/aea-config.yaml | 6 +++--- packages/valory/services/mech/service.yaml | 2 +- packages/valory/skills/mech_abci/skill.yaml | 2 +- .../valory/skills/task_submission_abci/skill.yaml | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/packages.json b/packages/packages.json index ef887a68..1bee5eea 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,13 +2,13 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeifw2qj6n7kwpjdhupjkcwdz4ydqur4j7744jb3vtevcucxcylpd2e", - "skill/valory/mech_abci/0.1.0": "bafybeihm6tdacrqw3fg4tpujrsi3p3owx4qxem3ehmzntjvxdjie4twcom", - "contract/valory/agent_mech/0.1.0": "bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u", - "service/valory/mech/0.1.0": "bafybeigjxfgvkjotfodzell24wvcg74lm2t7rcxdhsdgty2aczhhxcpudy", + "agent/valory/mech/0.1.0": "bafybeidgc46ahsyv2zcvqgosx3zz6nn3m7c52edzu4jur5h7kpjcvxy4yq", + "skill/valory/mech_abci/0.1.0": "bafybeiaqb6zgnzicjemwh4nfjvhowiazdk42t4kqtlr23kxwwf3gnlx64u", + "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", + "service/valory/mech/0.1.0": "bafybeie3sivsfx34giiz7lhe4ix3jlha2kkkjqjgzhstgyefhxedxxgew4", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra", - "skill/valory/task_execution/0.1.0": "bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue", + "skill/valory/task_submission_abci/0.1.0": "bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm", + "skill/valory/task_execution/0.1.0": "bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta", diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index bf9fb3dd..65135864 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -37,11 +37,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeihm6tdacrqw3fg4tpujrsi3p3owx4qxem3ehmzntjvxdjie4twcom -- valory/task_execution:0.1.0:bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue +- valory/mech_abci:0.1.0:bafybeiaqb6zgnzicjemwh4nfjvhowiazdk42t4kqtlr23kxwwf3gnlx64u +- valory/task_execution:0.1.0:bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra +- valory/task_submission_abci:0.1.0:bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index df5710ab..c0cd25f7 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeifw2qj6n7kwpjdhupjkcwdz4ydqur4j7744jb3vtevcucxcylpd2e +agent: valory/mech:0.1.0:bafybeidgc46ahsyv2zcvqgosx3zz6nn3m7c52edzu4jur5h7kpjcvxy4yq number_of_agents: 4 deployment: agent: diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index 0e5a2018..bd92eb8e 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -23,7 +23,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidk7pqb3hr2cokhroi4sfjbbwssidkfx5lhkjuitoeb4fswhdixra +- valory/task_submission_abci:0.1.0:bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index 1dfa1c8c..3acdc337 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -12,7 +12,7 @@ fingerprint: dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq - models.py: bafybeib6d45xymtpy7qhjzeb37imgtmibqqfpekd5uqqetottw6riddxtu + models.py: bafybeihzit6sstyzry2puyusyxx76wlqkd5r7a4nazmeutoodv32o7wv6q payloads.py: bafybeia2yorri2u5rwh6vukb6iwdrbn53ygsuuhthns2txptvjipyb6f4e rounds.py: bafybeicstmau4vlzpxz3kjgiwwsetwmotdk4un4iucmdddzvot5dgdkg2a tasks.py: bafybeicu5t5cvfhbndgpxbbtmp4vbmtyb6fba6vsnlewftvuderxp5lwcy From d39098bd30871c54ec20190e2bf77561d4f0100f Mon Sep 17 00:00:00 2001 From: Ardian Date: Mon, 27 Nov 2023 13:36:18 +0100 Subject: [PATCH 7/8] chore: lint --- packages/packages.json | 8 ++++---- packages/valory/agents/mech/aea-config.yaml | 4 ++-- packages/valory/services/mech/service.yaml | 2 +- packages/valory/skills/mech_abci/skill.yaml | 2 +- packages/valory/skills/task_submission_abci/behaviours.py | 5 ++--- packages/valory/skills/task_submission_abci/skill.yaml | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/packages.json b/packages/packages.json index 1bee5eea..dad2d609 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,12 +2,12 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeidgc46ahsyv2zcvqgosx3zz6nn3m7c52edzu4jur5h7kpjcvxy4yq", - "skill/valory/mech_abci/0.1.0": "bafybeiaqb6zgnzicjemwh4nfjvhowiazdk42t4kqtlr23kxwwf3gnlx64u", + "agent/valory/mech/0.1.0": "bafybeib6pandgld3qtqprrvrjmptpehc65ue6m5ozbavfpjqrrb5ikjbgi", + "skill/valory/mech_abci/0.1.0": "bafybeifqcfbpwipyvlkrpttnkxnd2fv6pov3gapjhz3b3sbfbmykidrrkq", "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", - "service/valory/mech/0.1.0": "bafybeie3sivsfx34giiz7lhe4ix3jlha2kkkjqjgzhstgyefhxedxxgew4", + "service/valory/mech/0.1.0": "bafybeidryu6vwlr5t5wt4ggp34wj6wezjwadetl5rk7r74e24facvcoho4", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm", + "skill/valory/task_submission_abci/0.1.0": "bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi", "skill/valory/task_execution/0.1.0": "bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index 65135864..782f091b 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -37,11 +37,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeiaqb6zgnzicjemwh4nfjvhowiazdk42t4kqtlr23kxwwf3gnlx64u +- valory/mech_abci:0.1.0:bafybeifqcfbpwipyvlkrpttnkxnd2fv6pov3gapjhz3b3sbfbmykidrrkq - valory/task_execution:0.1.0:bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm +- valory/task_submission_abci:0.1.0:bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index c0cd25f7..47355292 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeidgc46ahsyv2zcvqgosx3zz6nn3m7c52edzu4jur5h7kpjcvxy4yq +agent: valory/mech:0.1.0:bafybeib6pandgld3qtqprrvrjmptpehc65ue6m5ozbavfpjqrrb5ikjbgi number_of_agents: 4 deployment: agent: diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index bd92eb8e..c4a5fbff 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -23,7 +23,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeieohw4xxxw6ec27p3oh6n4g7imrmydvjvjfdp47l4p2tjnnts6jwm +- valory/task_submission_abci:0.1.0:bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index 1777c250..0fcf8d7b 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -387,9 +387,8 @@ def _split_funds( :returns: a dictionary mapping operator addresses to the amount of funds they should receive. :yields: None """ - service_owner = yield from self._get_service_owner( - self.params.on_chain_service_id - ) + on_chain_id = cast(int, self.params.on_chain_service_id) + service_owner = yield from self._get_service_owner(on_chain_id) if service_owner is None: self.context.logger.warning( "Could not get service owner. Don't split profits." diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index 3acdc337..ed371237 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -8,7 +8,7 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiholqak7ltw6bbmn2c5tn3j7xgzkdlfzp3kcskiqsvmxoih6m4muq - behaviours.py: bafybeia7arkt3helbxvjjlnmoucqupftzcjg5h35afzqu5wx7yfafljhiy + behaviours.py: bafybeihpzxlxflvzfafffxdokxvx5qjr7bnkcqwaqmq76p67b7dsryypcu dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq From c7a9a68330bd3fa5af5493a0638d3de190617eef Mon Sep 17 00:00:00 2001 From: Ardian Date: Mon, 27 Nov 2023 14:35:27 +0100 Subject: [PATCH 8/8] fix: add missing params --- packages/packages.json | 8 ++++---- packages/valory/agents/mech/aea-config.yaml | 4 ++-- packages/valory/services/mech/service.yaml | 10 +++++++++- packages/valory/skills/mech_abci/skill.yaml | 2 +- packages/valory/skills/task_submission_abci/models.py | 3 +++ packages/valory/skills/task_submission_abci/skill.yaml | 4 +++- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/packages.json b/packages/packages.json index dad2d609..da2f28e4 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,12 +2,12 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeib6pandgld3qtqprrvrjmptpehc65ue6m5ozbavfpjqrrb5ikjbgi", - "skill/valory/mech_abci/0.1.0": "bafybeifqcfbpwipyvlkrpttnkxnd2fv6pov3gapjhz3b3sbfbmykidrrkq", + "agent/valory/mech/0.1.0": "bafybeih5idugp2jm7hxzj63tvvfep3tradk2hhnxipro2egaxnvmdaqjka", + "skill/valory/mech_abci/0.1.0": "bafybeigrndr6sd3nayqa3wbffl263f6guxcbnk67m6x2vzhpvpkmtdn6xu", "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", - "service/valory/mech/0.1.0": "bafybeidryu6vwlr5t5wt4ggp34wj6wezjwadetl5rk7r74e24facvcoho4", + "service/valory/mech/0.1.0": "bafybeiewvz4sdoarlrgrjwnlnzgpxz6t7xafsbhifbuhoimq333bev7hwy", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi", + "skill/valory/task_submission_abci/0.1.0": "bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i", "skill/valory/task_execution/0.1.0": "bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index 782f091b..51f58f7e 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -37,11 +37,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeifqcfbpwipyvlkrpttnkxnd2fv6pov3gapjhz3b3sbfbmykidrrkq +- valory/mech_abci:0.1.0:bafybeigrndr6sd3nayqa3wbffl263f6guxcbnk67m6x2vzhpvpkmtdn6xu - valory/task_execution:0.1.0:bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi +- valory/task_submission_abci:0.1.0:bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index 47355292..03e6eb03 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeib6pandgld3qtqprrvrjmptpehc65ue6m5ozbavfpjqrrb5ikjbgi +agent: valory/mech:0.1.0:bafybeih5idugp2jm7hxzj63tvvfep3tradk2hhnxipro2egaxnvmdaqjka number_of_agents: 4 deployment: agent: @@ -55,6 +55,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} 1: models: params: @@ -83,6 +85,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} service_endpoint_base: ${SERVICE_ENDPOINT_BASE:str:https://dummy_service.autonolas.tech/} 2: models: @@ -113,6 +117,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} 3: models: params: @@ -141,6 +147,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} service_endpoint_base: ${SERVICE_ENDPOINT_BASE:str:https://dummy_service.autonolas.tech/} --- public_id: valory/task_execution:0.1.0 diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index c4a5fbff..2260e426 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -23,7 +23,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeidz6os4qfq657vzne2inn76vuteohs2rfldthys37atsgcvznitvi +- valory/task_submission_abci:0.1.0:bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: diff --git a/packages/valory/skills/task_submission_abci/models.py b/packages/valory/skills/task_submission_abci/models.py index 81743dd6..6942b2c5 100644 --- a/packages/valory/skills/task_submission_abci/models.py +++ b/packages/valory/skills/task_submission_abci/models.py @@ -67,6 +67,9 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.manual_gas_limit = self._ensure("manual_gas_limit", kwargs, int) self.service_owner_share = self._ensure("service_owner_share", kwargs, float) self.profit_split_freq = self._ensure("profit_split_freq", kwargs, int) + self.agent_mech_contract_addresses = self._ensure( + "agent_mech_contract_addresses", kwargs, list + ) self.hash_checkpoint_address = self._ensure( "hash_checkpoint_address", kwargs, str ) diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index ed371237..7a2e75e6 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -12,7 +12,7 @@ fingerprint: dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq - models.py: bafybeihzit6sstyzry2puyusyxx76wlqkd5r7a4nazmeutoodv32o7wv6q + models.py: bafybeibil7zmdpa3daz4wdhx2ekvspawtqswt56elj4hrvtiwykc6td6de payloads.py: bafybeia2yorri2u5rwh6vukb6iwdrbn53ygsuuhthns2txptvjipyb6f4e rounds.py: bafybeicstmau4vlzpxz3kjgiwwsetwmotdk4un4iucmdddzvot5dgdkg2a tasks.py: bafybeicu5t5cvfhbndgpxbbtmp4vbmtyb6fba6vsnlewftvuderxp5lwcy @@ -83,6 +83,8 @@ models: class_name: LedgerApiDialogues params: args: + agent_mech_contract_addresses: + - '0xFf82123dFB52ab75C417195c5fDB87630145ae81' cleanup_history_depth_current: null drand_public_key: 868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31 finalize_timeout: 60.0