diff --git a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py index 5ad86dec..7e17bb43 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/decision_receive.py @@ -27,9 +27,11 @@ from typing import Any, Dict, Generator, List, Optional, Tuple, Union from packages.valory.skills.decision_maker_abci.behaviours.base import ( - DecisionMakerBaseBehaviour, remove_fraction_wei, ) +from packages.valory.skills.decision_maker_abci.behaviours.storage_manager import ( + StorageManagerBehaviour, +) from packages.valory.skills.decision_maker_abci.io_.loader import ComponentPackageLoader from packages.valory.skills.decision_maker_abci.models import ( BenchmarkingMockData, @@ -59,7 +61,7 @@ TOKEN_PRECISION = 10**18 -class DecisionReceiveBehaviour(DecisionMakerBaseBehaviour): +class DecisionReceiveBehaviour(StorageManagerBehaviour): """A behaviour in which the agents receive the mech response.""" matching_round = DecisionReceiveRound @@ -93,6 +95,17 @@ def mech_response(self) -> MechInteractionResponse: return MechInteractionResponse(error=error) return self._mech_response + @property + def is_invalid_response(self) -> bool: + """Check if the response is invalid.""" + if self.mech_response.result is None: + self.context.logger.warning( + "Trying to check whether the mech's response is invalid but no response has been detected! " + "Assuming invalid response." + ) + return True + return self.mech_response.result == self.params.mech_invalid_response + def _next_dataset_row(self) -> Optional[Dict[str, str]]: """Read the next row from the input dataset which is used during the benchmarking mode. @@ -527,12 +540,17 @@ def async_act(self) -> Generator: """Do the action.""" with self.context.benchmark_tool.measure(self.behaviour_id).local(): + success = yield from self._setup_policy_and_tools() + if not success: + return None + prediction_response = self._get_decision() is_profitable = None bet_amount = None next_mock_data_row = None bets_hash = None decision_received_timestamp = None + policy = None if prediction_response is not None and prediction_response.vote is not None: is_profitable, bet_amount = yield from self._is_profitable( prediction_response @@ -552,6 +570,14 @@ def async_act(self) -> Generator: bet_amount, ) + if prediction_response is not None: + self.policy.tool_responded( + self.synchronized_data.mech_tool, + self.synced_timestamp, + self.is_invalid_response, + ) + policy = self.policy.serialize() + # always remove the processed trade from the benchmarking input file # now there is one reader pointer per market if self.benchmarking_mode.enabled: @@ -572,7 +598,9 @@ def async_act(self) -> Generator: prediction_response.confidence if prediction_response else None, bet_amount, next_mock_data_row, + policy, decision_received_timestamp, ) + self._store_all() yield from self.finish_behaviour(payload) diff --git a/packages/valory/skills/decision_maker_abci/payloads.py b/packages/valory/skills/decision_maker_abci/payloads.py index 33ec183b..b15c02b0 100644 --- a/packages/valory/skills/decision_maker_abci/payloads.py +++ b/packages/valory/skills/decision_maker_abci/payloads.py @@ -35,6 +35,7 @@ class DecisionReceivePayload(UpdateBetsPayload): confidence: Optional[float] bet_amount: Optional[int] next_mock_data_row: Optional[int] + policy: Optional[str] decision_received_timestamp: Optional[int] @@ -119,3 +120,10 @@ class BetPlacementPayload(MultisigTxPayload): """Represents a transaction payload for placing a bet.""" wallet_balance: Optional[int] = None + + +@dataclass(frozen=True) +class HandleFailedTxPayload(VotingPayload): + """Represents a transaction payload for placing a bet.""" + + tx_submitter: str diff --git a/packages/valory/skills/decision_maker_abci/states/decision_receive.py b/packages/valory/skills/decision_maker_abci/states/decision_receive.py index 678b6b2d..282e48c0 100644 --- a/packages/valory/skills/decision_maker_abci/states/decision_receive.py +++ b/packages/valory/skills/decision_maker_abci/states/decision_receive.py @@ -49,6 +49,7 @@ class DecisionReceiveRound(CollectSameUntilThresholdRound): get_name(SynchronizedData.confidence), get_name(SynchronizedData.bet_amount), get_name(SynchronizedData.next_mock_data_row), + get_name(SynchronizedData.policy), ) collection_key = get_name(SynchronizedData.participant_to_decision) diff --git a/packages/valory/skills/decision_maker_abci/tests/states/test_decision_receive.py b/packages/valory/skills/decision_maker_abci/tests/states/test_decision_receive.py index 064c891a..bcf00f1b 100644 --- a/packages/valory/skills/decision_maker_abci/tests/states/test_decision_receive.py +++ b/packages/valory/skills/decision_maker_abci/tests/states/test_decision_receive.py @@ -63,6 +63,7 @@ def get_payloads( next_mock_data_row: Optional[int], is_profitable: Optional[bool], bets_hash: str, + policy: str, ) -> Mapping[str, UpdateBetsPayload]: """Get payloads.""" return { @@ -73,7 +74,8 @@ def get_payloads( bet_amount=bet_amount, next_mock_data_row=next_mock_data_row, is_profitable=is_profitable, - bets_hash=bets_hash, # Added bets_hash parameter + bets_hash=bets_hash, + policy=policy, decision_received_timestamp=int(datetime.datetime.utcnow().timestamp()), ) for participant in get_participants() @@ -110,6 +112,7 @@ class TestDecisionReceiveRound(BaseCollectSameUntilThresholdRoundTest): bet_amount=100, next_mock_data_row=1, is_profitable=True, + policy="", bets_hash=DUMMY_BETS_HASH, # Added bets_hash ), final_data={ @@ -131,6 +134,7 @@ class TestDecisionReceiveRound(BaseCollectSameUntilThresholdRoundTest): bet_amount=50, next_mock_data_row=2, is_profitable=False, + policy="", bets_hash=DUMMY_BETS_HASH, # Added bets_hash ), final_data={ @@ -152,6 +156,7 @@ class TestDecisionReceiveRound(BaseCollectSameUntilThresholdRoundTest): bet_amount=None, next_mock_data_row=None, is_profitable=True, + policy="", bets_hash=DUMMY_BETS_HASH, # Added bets_hash ), final_data={}, @@ -168,6 +173,7 @@ class TestDecisionReceiveRound(BaseCollectSameUntilThresholdRoundTest): bet_amount=None, next_mock_data_row=None, is_profitable=True, + policy="", bets_hash=DUMMY_BETS_HASH, # Added bets_hash ), final_data={}, @@ -184,6 +190,7 @@ class TestDecisionReceiveRound(BaseCollectSameUntilThresholdRoundTest): bet_amount=None, next_mock_data_row=None, is_profitable=True, + policy="", bets_hash=DUMMY_BETS_HASH, # Added bets_hash ), final_data={}, diff --git a/packages/valory/skills/decision_maker_abci/tests/test_payloads.py b/packages/valory/skills/decision_maker_abci/tests/test_payloads.py index a8197400..f406adc7 100644 --- a/packages/valory/skills/decision_maker_abci/tests/test_payloads.py +++ b/packages/valory/skills/decision_maker_abci/tests/test_payloads.py @@ -50,6 +50,7 @@ "confidence": 0.90, "bet_amount": 1, "next_mock_data_row": 1, + "policy": "dummy policy", "decision_received_timestamp": int(datetime.utcnow().timestamp()), }, ),