diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 06d521f9f1..1c5929a3bc 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -32,10 +32,12 @@ jobs:
run: |
tox -e py3.8 -- --aea-loop sync -m 'not integration and not unstable'
- sync_aea_loop_integrational_tests:
+ all_integrational_tests:
continue-on-error: True
runs-on: ubuntu-latest
+
timeout-minutes: 40
+
steps:
- uses: actions/checkout@master
- uses: actions/setup-python@master
@@ -52,10 +54,12 @@ jobs:
pip install pipenv
pip install tox
sudo apt-get install -y protobuf-compiler
- - name: Integrational tests and coverage
+ - name: Sync AEA loop integrational tests and coverage
run: |
tox -e py3.8 -- --aea-loop sync -m 'integration and not unstable and not ledger'
-
+ - name: Async Integration tests
+ run: tox -e py3.8 -- -m 'integration and not unstable and not ledger'
+
common_checks:
runs-on: ubuntu-latest
continue-on-error: True
@@ -82,6 +86,8 @@ jobs:
tar xvfz go-ipfs.tar.gz
sudo mv go-ipfs/ipfs /usr/local/bin/ipfs
ipfs init
+ - name: Pipenv lock
+ run: pipenv lock
- name: Security Check
run: tox -e bandit
- name: Safety Check
@@ -111,27 +117,6 @@ jobs:
- name: Generate Documentation
run: tox -e docs
- integration_checks:
- continue-on-error: True
- runs-on: ubuntu-latest
-
- timeout-minutes: 40
-
- steps:
- - uses: actions/checkout@master
- - uses: actions/setup-python@master
- with:
- python-version: 3.7
- - name: Install dependencies (ubuntu-latest)
- run: |
- sudo apt-get update --fix-missing
- sudo apt-get autoremove
- sudo apt-get autoclean
- pip install pipenv
- pip install tox
- - name: Integration tests
- run: tox -e py3.7 -- -m 'integration and not unstable and not ledger'
-
integration_checks_ledger:
continue-on-error: True
runs-on: ubuntu-latest
diff --git a/HISTORY.md b/HISTORY.md
index 596f9b2171..39ffdbca8d 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,27 @@
# Release History
+## 0.5.3 (2020-08-05)
+
+- Adds support for re-starting agent after stopping it
+- Adds full test coverage for protocols generator
+- Adds support for dynamically adding handlers
+- Improves p2p connection startup reliability
+- Addresses p2p connection race condition with long running processes
+- Adds connection states in connections
+- Applies consistent logger usage throughout
+- Adds key rotation and randomised locations for integration tests
+- Adds request delays in SOEF connection to avoid request limits
+- Exposes runtime states on agent and removes agent liveness object
+- Adds readme files in protocols and connections
+- Improves edge case handling in dialogue models
+- Adds support for cosmwasm message signing
+- Adds test coverage for test tools
+- Adds dialogues models in all connections where required
+- Transitions erc1155 skills and simple search to SOEF and p2p
+- Adds full test coverage for skills modules
+- Multiple docs updates
+- Multiple additional tests and test stability fixes
+
## 0.5.2 (2020-07-21)
- Transitions demos to agent-land test network, P2P and SOEF connections
diff --git a/MANIFEST.in b/MANIFEST.in
index 5eb868e9f3..2b10871f8e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,6 @@
include README.md LICENSE HISTORY.md AUTHORS.md SECURITY.md CODE_OF_CONDUCT.md Pipfile mkdocs.yml tox.ini pytest.ini strategy.ini
-recursive-include aea *.json *.yaml *.proto *.ico *png *.html *.js *.css
+recursive-include aea *.json *.yaml *.proto *.ico *png *.html *.js *.css *.md
recursive-include docs *
recursive-include examples *
recursive-include packages *
diff --git a/Makefile b/Makefile
index 222d6572bc..905922a689 100644
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,7 @@ lint:
.PHONY: pylint
pylint:
- pylint aea benchmark examples packages scripts
+ pylint aea benchmark packages scripts examples/*
.PHONY: security
security:
diff --git a/Pipfile b/Pipfile
index baa3f28804..ee8e85647e 100644
--- a/Pipfile
+++ b/Pipfile
@@ -39,7 +39,6 @@ openapi-spec-validator = "==0.2.8"
pexpect = "==4.8.0"
psutil = "==5.7.0"
pydocstyle = "==3.0.0"
-pydoc-markdown = "==3.3.0"
pygments = "==2.5.2"
pylint = "==2.5.2"
pymdown-extensions = "==6.3"
diff --git a/README.md b/README.md
index 7b2fcbb1d8..e1323ae025 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,51 @@
-# AEA Framework
+
+ AEA Framework
+
-[![PyPI](https://img.shields.io/pypi/v/aea)](https://pypi.org/project/aea/)
-![PyPI - Python Version](https://img.shields.io/pypi/pyversions/aea)
-![PyPI - Wheel](https://img.shields.io/pypi/wheel/aea)
-[![](https://img.shields.io/pypi/l/aea)](https://github.com/fetchai/agents-aea/blob/master/LICENSE)
-![PyPI - Downloads](https://img.shields.io/pypi/dm/aea)
-[![](https://img.shields.io/badge/slack-fetchai-black.svg)](https://fetch-ai.slack.com/join/shared_invite/enQtNDI2MDYwMjE3OTQwLWY0ZjAyYjM0NGQzNWRhNDMxMzdjYmVhYTE3NDNhNTAyMTE0YWRkY2VmOWRmMGQ3ODM1N2NjOWUwNDExM2U3YjY)
-
-![AEA framework sanity checks and tests](https://github.com/fetchai/agents-aea/workflows/AEA%20framework%20sanity%20checks%20and%20tests/badge.svg?branch=master)
-![Codecov](https://img.shields.io/codecov/c/github/fetchai/agents-aea)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
A framework for autonomous economic agent (AEA) development
+
diff --git a/aea/__version__.py b/aea/__version__.py
index 884d0cd850..9c4e84a1b2 100644
--- a/aea/__version__.py
+++ b/aea/__version__.py
@@ -22,7 +22,7 @@
__title__ = "aea"
__description__ = "Autonomous Economic Agent framework"
__url__ = "https://github.com/fetchai/agents-aea.git"
-__version__ = "0.5.2"
+__version__ = "0.5.3"
__author__ = "Fetch.AI Limited"
__license__ = "Apache-2.0"
__copyright__ = "2019 Fetch.AI Limited"
diff --git a/aea/aea.py b/aea/aea.py
index ed396d4c26..fdb96bcd82 100644
--- a/aea/aea.py
+++ b/aea/aea.py
@@ -34,7 +34,7 @@
from aea.exceptions import AEAException
from aea.helpers.exception_policy import ExceptionPolicyEnum
from aea.helpers.exec_timeout import ExecTimeoutThreadGuard, TimeoutException
-from aea.helpers.logging import AgentLoggerAdapter
+from aea.helpers.logging import AgentLoggerAdapter, WithLogger
from aea.identity.base import Identity
from aea.mail.base import Envelope
from aea.protocols.base import Message
@@ -45,10 +45,8 @@
from aea.skills.error.handlers import ErrorHandler
from aea.skills.tasks import TaskManager
-logger = logging.getLogger(__name__)
-
-class AEA(Agent):
+class AEA(Agent, WithLogger):
"""This class implements an autonomous economic agent."""
RUN_LOOPS: Dict[str, Type[BaseAgentLoop]] = {
@@ -108,6 +106,10 @@ def __init__(
loop_mode=loop_mode,
runtime_mode=runtime_mode,
)
+ aea_logger = AgentLoggerAdapter(
+ logger=logging.getLogger(__name__), agent_name=identity.name
+ )
+ WithLogger.__init__(self, logger=cast(logging.Logger, aea_logger))
self.max_reactions = max_reactions
self._task_manager = TaskManager()
@@ -256,14 +258,14 @@ def _handle(self, envelope: Envelope) -> None:
:param envelope: the envelope to handle.
:return: None
"""
- logger.debug("Handling envelope: {}".format(envelope))
+ self.logger.debug("Handling envelope: {}".format(envelope))
protocol = self.resources.get_protocol(envelope.protocol_id)
# TODO specify error handler in config and make this work for different skill/protocol versions.
error_handler = self._get_error_handler()
if error_handler is None:
- logger.warning("ErrorHandler not initialized. Stopping AEA!")
+ self.logger.warning("ErrorHandler not initialized. Stopping AEA!")
self.stop()
return
error_handler = cast(ErrorHandler, error_handler)
@@ -278,9 +280,11 @@ def _handle(self, envelope: Envelope) -> None:
else:
msg = protocol.serializer.decode(envelope.message)
msg.counterparty = envelope.sender
+ msg.sender = envelope.sender
+ # msg.to = envelope.to
msg.is_incoming = True
except Exception as e: # pylint: disable=broad-except # thats ok, because we send the decoding error back
- logger.warning("Decoding error. Exception: {}".format(str(e)))
+ self.logger.warning("Decoding error. Exception: {}".format(str(e)))
error_handler.send_decoding_error(envelope)
return
@@ -334,13 +338,13 @@ def _execution_control(
"""
# docstyle: ignore
def log_exception(e, fn, component):
- logger.exception(f"<{e}> raised during `{fn}` call of `{component}`")
+ self.logger.exception(f"<{e}> raised during `{fn}` call of `{component}`")
try:
with ExecTimeoutThreadGuard(self._execution_timeout):
return fn(*(args or []), **(kwargs or {}))
except TimeoutException:
- logger.warning(
+ self.logger.warning(
"`{}` of `{}` was terminated as its execution exceeded the timeout of {} seconds. Please refactor your code!".format(
fn, component, self._execution_timeout
)
@@ -383,8 +387,7 @@ def teardown(self) -> None:
:return: None
"""
- logger.debug("[{}]: Calling teardown method...".format(self.name))
- self.liveness.stop()
+ self.logger.debug("[{}]: Calling teardown method...".format(self.name))
self.decision_maker.stop()
self.task_manager.stop()
self.resources.teardown()
diff --git a/aea/aea_builder.py b/aea/aea_builder.py
index e404bdbd65..d1c5f71b36 100644
--- a/aea/aea_builder.py
+++ b/aea/aea_builder.py
@@ -71,12 +71,7 @@
)
from aea.configurations.loader import ConfigLoader
from aea.contracts import contract_registry
-from aea.crypto.helpers import (
- IDENTIFIER_TO_KEY_FILES,
- create_private_key,
- try_validate_private_key_path,
-)
-from aea.crypto.registries import crypto_registry
+from aea.crypto.helpers import verify_or_create_private_keys
from aea.crypto.wallet import Wallet
from aea.decision_maker.base import DecisionMakerHandler
from aea.decision_maker.default import (
@@ -1301,7 +1296,9 @@ def from_aea_project(
"""
aea_project_path = Path(aea_project_path)
cls._try_to_load_agent_configuration_file(aea_project_path)
- _verify_or_create_private_keys(aea_project_path)
+ verify_or_create_private_keys(
+ aea_project_path=aea_project_path, exit_on_error=False
+ )
builder = AEABuilder(with_default_packages=False)
# TODO isolate environment
@@ -1343,11 +1340,17 @@ def _load_and_add_components(
if configuration in self._component_instances[component_type].keys():
component = self._component_instances[component_type][configuration]
+ if configuration.component_type != ComponentType.SKILL:
+ component.logger = cast(
+ logging.Logger, make_logger(configuration, agent_name)
+ )
else:
configuration = deepcopy(configuration)
- component = load_component_from_config(configuration, **kwargs)
+ _logger = make_logger(configuration, agent_name)
+ component = load_component_from_config(
+ configuration, logger=_logger, **kwargs
+ )
- _set_logger_to_component(component, configuration, agent_name)
resources.add_component(component)
def _populate_contract_registry(self):
@@ -1394,58 +1397,19 @@ def _check_we_can_build(self):
)
-def _set_logger_to_component(
- component: Component, configuration: ComponentConfiguration, agent_name: str,
-) -> None:
+def make_logger(
+ configuration: ComponentConfiguration, agent_name: str,
+) -> Optional[logging.Logger]:
"""
- Set the logger to the component.
+ Make the logger for a component.
- :param component: the component instance.
:param configuration: the component configuration
:param agent_name: the agent name
- :return: None
+ :return: the logger.
"""
if configuration.component_type == ComponentType.SKILL:
# skip because skill object already have their own logger from the skill context.
- return
+ return None
logger_name = f"aea.packages.{configuration.author}.{configuration.component_type.to_plural()}.{configuration.name}"
- logger = AgentLoggerAdapter(logging.getLogger(logger_name), agent_name)
- component.logger = logger
-
-
-# TODO this function is repeated in 'aea.cli.utils.package_utils.py'
-def _verify_or_create_private_keys(aea_project_path: Path) -> None:
- """Verify or create private keys."""
- path_to_configuration = aea_project_path / DEFAULT_AEA_CONFIG_FILE
- agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig)
- fp_read = path_to_configuration.open(mode="r", encoding="utf-8")
- agent_configuration = agent_loader.load(fp_read)
-
- for identifier, _value in agent_configuration.private_key_paths.read_all():
- if identifier not in crypto_registry.supported_ids:
- raise ValueError(f"Item not registered with id '{identifier}'.")
-
- for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items():
- config_private_key_path = agent_configuration.private_key_paths.read(identifier)
- if config_private_key_path is None:
- create_private_key(
- identifier, private_key_file=str(aea_project_path / private_key_path)
- )
- agent_configuration.private_key_paths.update(identifier, private_key_path)
- else:
- try:
- try_validate_private_key_path(
- identifier,
- str(aea_project_path / private_key_path),
- exit_on_error=False,
- )
- except FileNotFoundError: # pragma: no cover
- logger.error(
- "File {} for private key {} not found.".format(
- repr(private_key_path), identifier,
- )
- )
- raise
-
- fp_write = path_to_configuration.open(mode="w", encoding="utf-8")
- agent_loader.dump(agent_configuration, fp_write)
+ _logger = AgentLoggerAdapter(logging.getLogger(logger_name), agent_name)
+ return cast(logging.Logger, _logger)
diff --git a/aea/agent.py b/aea/agent.py
index a5a139334b..19c2622321 100644
--- a/aea/agent.py
+++ b/aea/agent.py
@@ -21,55 +21,18 @@
import logging
from abc import ABC, abstractmethod
from asyncio import AbstractEventLoop
-from enum import Enum
from typing import Dict, List, Optional, Type
from aea.agent_loop import BaseAgentLoop, SyncAgentLoop
from aea.connections.base import Connection
from aea.identity.base import Identity
from aea.multiplexer import InBox, Multiplexer, OutBox
-from aea.runtime import AsyncRuntime, BaseRuntime, ThreadedRuntime
+from aea.runtime import AsyncRuntime, BaseRuntime, RuntimeStates, ThreadedRuntime
logger = logging.getLogger(__name__)
-class AgentState(Enum):
- """Enumeration for an agent state.
-
- In particular, it can be one of the following states:
-
- - AgentState.INITIATED: when the Agent object has been created.
- - AgentState.CONNECTED: when the agent is connected.
- - AgentState.RUNNING: when the agent is running.
- """
-
- INITIATED = "initiated"
- CONNECTED = "connected"
- RUNNING = "running"
-
-
-class Liveness:
- """Determines the liveness of the agent."""
-
- def __init__(self):
- """Instantiate the liveness."""
- self._is_stopped = True
-
- @property
- def is_stopped(self) -> bool:
- """Check whether the liveness is stopped."""
- return self._is_stopped
-
- def start(self) -> None:
- """Start the liveness."""
- self._is_stopped = False
-
- def stop(self) -> None:
- """Stop the liveness."""
- self._is_stopped = True
-
-
class Agent(ABC):
"""This class provides an abstract base class for a generic agent."""
@@ -111,7 +74,6 @@ def __init__(
self._multiplexer = Multiplexer(self._connections, loop=loop)
self._inbox = InBox(self._multiplexer)
self._outbox = OutBox(self._multiplexer, identity.address)
- self._liveness = Liveness()
self._timeout = timeout
self._tick = 0
@@ -185,11 +147,6 @@ def name(self) -> str:
"""Get the agent name."""
return self.identity.name
- @property
- def liveness(self) -> Liveness:
- """Get the liveness."""
- return self._liveness
-
@property
def tick(self) -> int:
"""
@@ -204,26 +161,6 @@ def timeout(self) -> float:
"""Get the time in (fractions of) seconds to time out an agent between act and react."""
return self._timeout
- @property
- def agent_state(self) -> AgentState:
- """
- Get the state of the agent.
-
- :raises ValueError: if the state does not satisfy any of the foreseen conditions.
- :return: None
- """
- if (
- self.multiplexer is not None
- and not self.multiplexer.connection_status.is_connected
- ):
- return AgentState.INITIATED
- elif self.multiplexer.connection_status.is_connected and not self.is_running:
- return AgentState.CONNECTED
- elif self.multiplexer.connection_status.is_connected and self.is_running:
- return AgentState.RUNNING
- else:
- raise ValueError("Agent state not recognized.") # pragma: no cover
-
@property
def loop_mode(self) -> str:
"""Get the agent loop mode."""
@@ -240,7 +177,7 @@ def runtime(self) -> BaseRuntime:
return self._runtime
def setup_multiplexer(self) -> None:
- """Set up the multiplexer"""
+ """Set up the multiplexer."""
pass
def start(self) -> None:
@@ -278,7 +215,6 @@ def start_setup(self) -> None:
"""
logger.debug("[{}]: Calling setup method...".format(self.name))
self.setup()
- self.liveness.start()
def stop(self) -> None:
"""
@@ -333,3 +269,12 @@ def teardown(self) -> None:
:return: None
"""
+
+ @property
+ def state(self) -> RuntimeStates:
+ """
+ Get state of the agent's runtime.
+
+ :return: RuntimeStates
+ """
+ return self._runtime.state
diff --git a/aea/agent_loop.py b/aea/agent_loop.py
index 1266a3e852..29d319e746 100644
--- a/aea/agent_loop.py
+++ b/aea/agent_loop.py
@@ -252,7 +252,7 @@ def _create_tasks(self) -> List[Task]:
tasks = [
self._task_process_inbox(),
self._task_process_internal_messages(),
- self._task_process_new_behaviours(),
+ self._task_process_new_skill_components(),
self._task_wait_for_error(),
]
return list(map(self._loop.create_task, tasks)) # type: ignore # some issue with map and create_task
@@ -275,11 +275,12 @@ async def _task_process_internal_messages(self) -> None:
msg
)
- async def _task_process_new_behaviours(self) -> None:
+ async def _task_process_new_skill_components(self) -> None:
"""Process new behaviours added to skills in runtime."""
while self.is_running:
# TODO: better handling internal messages for skills internal updates
self._agent.filter._handle_new_behaviours() # pylint: disable=protected-access # TODO: refactoring!
+ self._agent.filter._handle_new_handlers() # pylint: disable=protected-access # TODO: refactoring!
self._register_all_behaviours() # re register, cause new may appear
await asyncio.sleep(self.NEW_BEHAVIOURS_PROCESS_SLEEP)
diff --git a/aea/cli/generate_key.py b/aea/cli/generate_key.py
index faece7ca93..1781c0fd5b 100644
--- a/aea/cli/generate_key.py
+++ b/aea/cli/generate_key.py
@@ -20,6 +20,7 @@
"""Implementation of the 'aea generate_key' subcommand."""
from pathlib import Path
+from typing import Optional
import click
@@ -34,24 +35,36 @@
type=click.Choice([*list(crypto_registry.supported_ids), "all"]),
required=True,
)
-def generate_key(type_):
+@click.argument(
+ "file",
+ metavar="FILE",
+ type=click.Path(exists=False, file_okay=True, dir_okay=False, readable=True),
+ required=False,
+)
+def generate_key(type_, file):
"""Generate private keys."""
- _generate_private_key(type_)
+ _generate_private_key(type_, file)
-def _generate_private_key(type_: str) -> None:
+def _generate_private_key(type_: str, file: Optional[str] = None) -> None:
"""
Generate private key.
:param type_: type.
+ :param file: path to file.
:return: None
"""
- types = list(IDENTIFIER_TO_KEY_FILES.keys()) if type_ == "all" else [type_]
+ if type_ == "all" and file is not None:
+ raise click.ClickException("Type all cannot be used in combination with file.")
+ elif type_ == "all":
+ types = list(IDENTIFIER_TO_KEY_FILES.keys())
+ else:
+ types = [type_]
for type_ in types:
- private_key_file = IDENTIFIER_TO_KEY_FILES[type_]
+ private_key_file = IDENTIFIER_TO_KEY_FILES[type_] if file is None else file
if _can_write(private_key_file):
- create_private_key(type_)
+ create_private_key(type_, private_key_file)
def _can_write(path) -> bool:
diff --git a/aea/cli/generate_wealth.py b/aea/cli/generate_wealth.py
index 9485936a85..fc96215077 100644
--- a/aea/cli/generate_wealth.py
+++ b/aea/cli/generate_wealth.py
@@ -20,29 +20,30 @@
"""Implementation of the 'aea generate_wealth' subcommand."""
import time
-from typing import cast
+from typing import Dict, Optional, cast
import click
from aea.cli.utils.context import Context
from aea.cli.utils.decorators import check_aea_project
-from aea.cli.utils.package_utils import try_get_balance, verify_or_create_private_keys
-from aea.crypto.helpers import (
- IDENTIFIER_TO_FAUCET_APIS,
- TESTNETS,
- try_generate_testnet_wealth,
+from aea.cli.utils.package_utils import (
+ try_get_balance,
+ verify_or_create_private_keys_ctx,
)
+from aea.configurations.base import AgentConfig
+from aea.crypto.helpers import try_generate_testnet_wealth
+from aea.crypto.registries import faucet_apis_registry, make_faucet_api_cls
from aea.crypto.wallet import Wallet
-FUNDS_RELEASE_TIMEOUT = 10
+FUNDS_RELEASE_TIMEOUT = 30
@click.command()
@click.argument(
"type_",
metavar="TYPE",
- type=click.Choice(list(IDENTIFIER_TO_FAUCET_APIS.keys())),
+ type=click.Choice(list(faucet_apis_registry.supported_ids)),
required=True,
)
@click.option(
@@ -55,18 +56,29 @@ def generate_wealth(click_context, sync, type_):
_try_generate_wealth(click_context, type_, sync)
-def _try_generate_wealth(click_context, type_, sync):
+def _try_generate_wealth(
+ click_context: click.core.Context, type_: str, sync: bool
+) -> None:
+ """
+ Try generate wealth for the provided network identifier.
+
+ :param click_context: the click context
+ :param type_: the network type
+ :param sync: whether to sync or not
+ :return: None
+ """
ctx = cast(Context, click_context.obj)
- verify_or_create_private_keys(ctx)
+ verify_or_create_private_keys_ctx(ctx=ctx)
private_key_paths = {
config_pair[0]: config_pair[1]
for config_pair in ctx.agent_config.private_key_paths.read_all()
- }
+ } # type: Dict[str, Optional[str]]
wallet = Wallet(private_key_paths)
try:
address = wallet.addresses[type_]
- testnet = TESTNETS[type_]
+ faucet_api_cls = make_faucet_api_cls(type_)
+ testnet = faucet_api_cls.network_name
click.echo(
"Requesting funds for address {} on test network '{}'".format(
address, testnet
@@ -80,10 +92,22 @@ def _try_generate_wealth(click_context, type_, sync):
raise click.ClickException(str(e))
-def _wait_funds_release(agent_config, wallet, type_):
+def _wait_funds_release(agent_config: AgentConfig, wallet: Wallet, type_: str) -> None:
+ """
+ Wait for the funds to be released.
+
+ :param agent_config: the agent config
+ :param wallet: the wallet
+ :param type_: the network type
+ """
start_balance = try_get_balance(agent_config, wallet, type_)
end_time = time.time() + FUNDS_RELEASE_TIMEOUT
+ has_hit_timeout = True
while time.time() < end_time:
- if start_balance != try_get_balance(agent_config, wallet, type_):
+ current_balance = try_get_balance(agent_config, wallet, type_)
+ if start_balance != current_balance:
+ has_hit_timeout = False
break # pragma: no cover
time.sleep(1)
+ if has_hit_timeout:
+ raise ValueError("Timeout hit. Syncing did not finish.")
diff --git a/aea/cli/get_address.py b/aea/cli/get_address.py
index 2cf3f570c4..632353e26a 100644
--- a/aea/cli/get_address.py
+++ b/aea/cli/get_address.py
@@ -25,7 +25,7 @@
from aea.cli.utils.context import Context
from aea.cli.utils.decorators import check_aea_project
-from aea.cli.utils.package_utils import verify_or_create_private_keys
+from aea.cli.utils.package_utils import verify_or_create_private_keys_ctx
from aea.crypto.registries import crypto_registry
from aea.crypto.wallet import Wallet
@@ -55,7 +55,7 @@ def _try_get_address(click_context, type_):
:return: address.
"""
ctx = cast(Context, click_context.obj)
- verify_or_create_private_keys(ctx)
+ verify_or_create_private_keys_ctx(ctx=ctx)
private_key_paths = {
config_pair[0]: config_pair[1]
diff --git a/aea/cli/get_wealth.py b/aea/cli/get_wealth.py
index 0a828db4f2..021c48faa1 100644
--- a/aea/cli/get_wealth.py
+++ b/aea/cli/get_wealth.py
@@ -19,20 +19,26 @@
"""Implementation of the 'aea get_wealth' subcommand."""
-from typing import cast
+from typing import Dict, Optional, cast
import click
from aea.cli.utils.context import Context
from aea.cli.utils.decorators import check_aea_project
-from aea.cli.utils.package_utils import try_get_balance, verify_or_create_private_keys
-from aea.crypto.ledger_apis import SUPPORTED_LEDGER_APIS
+from aea.cli.utils.package_utils import (
+ try_get_balance,
+ verify_or_create_private_keys_ctx,
+)
+from aea.crypto.registries import ledger_apis_registry
from aea.crypto.wallet import Wallet
@click.command()
@click.argument(
- "type_", metavar="TYPE", type=click.Choice(SUPPORTED_LEDGER_APIS), required=True,
+ "type_",
+ metavar="TYPE",
+ type=click.Choice(ledger_apis_registry.supported_ids),
+ required=True,
)
@click.pass_context
@check_aea_project
@@ -42,12 +48,12 @@ def get_wealth(click_context, type_):
click.echo(wealth)
-def _try_get_wealth(click_context, type_):
+def _try_get_wealth(click_context: click.core.Context, type_: str):
ctx = cast(Context, click_context.obj)
- verify_or_create_private_keys(ctx)
+ verify_or_create_private_keys_ctx(ctx=ctx)
private_key_paths = {
config_pair[0]: config_pair[1]
for config_pair in ctx.agent_config.private_key_paths.read_all()
- }
+ } # type: Dict[str, Optional[str]]
wallet = Wallet(private_key_paths)
return try_get_balance(ctx.agent_config, wallet, type_)
diff --git a/aea/cli/interact.py b/aea/cli/interact.py
index c7eaf03a65..0761b1a26e 100644
--- a/aea/cli/interact.py
+++ b/aea/cli/interact.py
@@ -134,7 +134,7 @@ def _try_construct_envelope(agent_name: str, sender: str) -> Optional[Envelope]:
performative_str = "bytes"
performative = DefaultMessage.Performative(performative_str)
click.echo(
- "Provide message of protocol fetchai/default:0.3.0 for performative {}:".format(
+ "Provide message of protocol fetchai/default:0.4.0 for performative {}:".format(
performative_str
)
)
@@ -150,10 +150,12 @@ def _try_construct_envelope(agent_name: str, sender: str) -> Optional[Envelope]:
else:
message = message_escaped # pragma: no cover
msg = DefaultMessage(performative=performative, content=message)
+ msg.counterparty = agent_name
+ msg.sender = sender
envelope = Envelope(
- to=agent_name,
- sender=sender,
- protocol_id=DefaultMessage.protocol_id, # PublicId.from_str(protocol_id),
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
except InterruptInputException:
diff --git a/aea/cli/utils/package_utils.py b/aea/cli/utils/package_utils.py
index 84e8ce44c9..e199097ca9 100644
--- a/aea/cli/utils/package_utils.py
+++ b/aea/cli/utils/package_utils.py
@@ -42,51 +42,27 @@
_get_default_configuration_file_name_from_type,
)
from aea.configurations.loader import ConfigLoader
-from aea.crypto.helpers import (
- IDENTIFIER_TO_KEY_FILES,
- create_private_key,
- try_validate_private_key_path,
-)
+from aea.crypto.helpers import verify_or_create_private_keys
from aea.crypto.ledger_apis import DEFAULT_LEDGER_CONFIGS, LedgerApis
-from aea.crypto.registries import crypto_registry
from aea.crypto.wallet import Wallet
+ROOT = Path(".")
+
-def verify_or_create_private_keys(ctx: Context) -> None:
+def verify_or_create_private_keys_ctx(
+ ctx: Context, aea_project_path: Path = ROOT, exit_on_error: bool = True,
+) -> None:
"""
- Verify or create private keys.
+ Verify or create private keys with ctx provided.
:param ctx: Context
"""
- path = Path(DEFAULT_AEA_CONFIG_FILE)
- agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig)
- fp = path.open(mode="r", encoding="utf-8")
- aea_conf = agent_loader.load(fp)
-
- for identifier, _value in aea_conf.private_key_paths.read_all():
- if identifier not in crypto_registry.supported_ids:
- ValueError("Unsupported identifier in private key paths.")
-
- for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items():
- config_private_key_path = aea_conf.private_key_paths.read(identifier)
- if config_private_key_path is None:
- create_private_key(identifier)
- aea_conf.private_key_paths.update(identifier, private_key_path)
- else:
- try:
- try_validate_private_key_path(identifier, private_key_path)
- except FileNotFoundError: # pragma: no cover
- raise click.ClickException(
- "File {} for private key {} not found.".format(
- repr(private_key_path), identifier,
- )
- )
-
- # update aea config
- path = Path(DEFAULT_AEA_CONFIG_FILE)
- fp = path.open(mode="w", encoding="utf-8")
- agent_loader.dump(aea_conf, fp)
- ctx.agent_config = aea_conf
+ try:
+ agent_config = verify_or_create_private_keys(aea_project_path, exit_on_error)
+ if ctx is not None:
+ ctx.agent_config = agent_config
+ except ValueError as e: # pragma: nocover
+ click.ClickException(str(e))
def validate_package_name(package_name: str):
@@ -430,9 +406,8 @@ def try_get_balance(agent_config: AgentConfig, wallet: Wallet, type_: str) -> in
try:
if type_ not in DEFAULT_LEDGER_CONFIGS: # pragma: no cover
raise ValueError("No ledger api config for {} available.".format(type_))
- ledger_apis = LedgerApis(DEFAULT_LEDGER_CONFIGS, agent_config.default_ledger)
address = wallet.addresses[type_]
- balance = ledger_apis.get_balance(type_, address)
+ balance = LedgerApis.get_balance(type_, address)
if balance is None: # pragma: no cover
raise ValueError("No balance returned!")
return balance
diff --git a/aea/components/base.py b/aea/components/base.py
index 166defa01d..0455e736f2 100644
--- a/aea/components/base.py
+++ b/aea/components/base.py
@@ -42,6 +42,7 @@ def __init__(
self,
configuration: Optional[ComponentConfiguration] = None,
is_vendor: bool = False,
+ **kwargs
):
"""
Initialize a package.
@@ -49,7 +50,7 @@ def __init__(
:param configuration: the package configuration.
:param is_vendor: whether the package is vendorized.
"""
- WithLogger.__init__(self)
+ WithLogger.__init__(self, **kwargs)
self._configuration = configuration
self._directory = None # type: Optional[Path]
self._is_vendor = is_vendor
diff --git a/aea/configurations/constants.py b/aea/configurations/constants.py
index 89b557e3f1..2ac9890c4a 100644
--- a/aea/configurations/constants.py
+++ b/aea/configurations/constants.py
@@ -25,13 +25,13 @@
from aea.crypto.cosmos import CosmosCrypto
from aea.crypto.helpers import COSMOS_PRIVATE_KEY_FILE
-DEFAULT_CONNECTION = PublicId.from_str("fetchai/stub:0.6.0")
-DEFAULT_PROTOCOL = PublicId.from_str("fetchai/default:0.3.0")
-DEFAULT_SKILL = PublicId.from_str("fetchai/error:0.3.0")
+DEFAULT_CONNECTION = PublicId.from_str("fetchai/stub:0.7.0")
+DEFAULT_PROTOCOL = PublicId.from_str("fetchai/default:0.4.0")
+DEFAULT_SKILL = PublicId.from_str("fetchai/error:0.4.0")
DEFAULT_LEDGER = CosmosCrypto.identifier
DEFAULT_PRIVATE_KEY_FILE = COSMOS_PRIVATE_KEY_FILE
DEFAULT_REGISTRY_PATH = DRP
DEFAULT_LICENSE = DL
-SIGNING_PROTOCOL = PublicId.from_str("fetchai/signing:0.1.0")
-STATE_UPDATE_PROTOCOL = PublicId.from_str("fetchai/state_update:0.1.0")
+SIGNING_PROTOCOL = PublicId.from_str("fetchai/signing:0.2.0")
+STATE_UPDATE_PROTOCOL = PublicId.from_str("fetchai/state_update:0.2.0")
LOCAL_PROTOCOLS = [DEFAULT_PROTOCOL, SIGNING_PROTOCOL, STATE_UPDATE_PROTOCOL]
diff --git a/aea/connections/base.py b/aea/connections/base.py
index eb7888333b..f04dd49021 100644
--- a/aea/connections/base.py
+++ b/aea/connections/base.py
@@ -16,13 +16,13 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""The base connection package."""
import inspect
import logging
import re
from abc import ABC, abstractmethod
from asyncio import AbstractEventLoop
+from enum import Enum
from pathlib import Path
from typing import Optional, Set, TYPE_CHECKING, cast
@@ -34,6 +34,7 @@
PublicId,
)
from aea.crypto.wallet import CryptoStore
+from aea.helpers.async_utils import AsyncState
from aea.helpers.base import load_aea_package, load_module
from aea.identity.base import Identity
@@ -45,15 +46,13 @@
logger = logging.getLogger(__name__)
-# TODO refactoring: this should be an enum
-# but beware of backward-compatibility.
-class ConnectionStatus:
- """The connection status class."""
+class ConnectionStates(Enum):
+ """Connection states enum."""
- def __init__(self):
- """Initialize the connection status."""
- self.is_connected = False # type: bool
- self.is_connecting = False # type: bool
+ connected = "connected"
+ connecting = "connecting"
+ disconnecting = "disconnecting"
+ disconnected = "disconnected"
class Connection(Component, ABC):
@@ -68,6 +67,7 @@ def __init__(
crypto_store: Optional[CryptoStore] = None,
restricted_to_protocols: Optional[Set[PublicId]] = None,
excluded_protocols: Optional[Set[PublicId]] = None,
+ **kwargs
):
"""
Initialize the connection.
@@ -82,12 +82,12 @@ def __init__(
:param excluded_protocols: the set of protocols ids that we want to exclude for this connection.
"""
assert configuration is not None, "The configuration must be provided."
- super().__init__(configuration)
+ super().__init__(configuration, **kwargs)
assert (
super().public_id == self.connection_id
), "Connection ids in configuration and class not matching."
self._loop: Optional[AbstractEventLoop] = None
- self._connection_status = ConnectionStatus()
+ self._state = AsyncState(ConnectionStates.disconnected)
self._identity = identity
self._crypto_store = crypto_store
@@ -164,9 +164,9 @@ def excluded_protocols(self) -> Set[PublicId]: # pragma: nocover
return self.configuration.excluded_protocols
@property
- def connection_status(self) -> ConnectionStatus:
+ def state(self) -> ConnectionStates:
"""Get the connection status."""
- return self._connection_status
+ return self._state.get()
@abstractmethod
async def connect(self):
@@ -195,7 +195,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
@classmethod
def from_dir(
- cls, directory: str, identity: Identity, crypto_store: CryptoStore
+ cls, directory: str, identity: Identity, crypto_store: CryptoStore, **kwargs
) -> "Connection":
"""
Load the connection from a directory.
@@ -210,7 +210,7 @@ def from_dir(
ComponentConfiguration.load(ComponentType.CONNECTION, Path(directory)),
)
configuration.directory = Path(directory)
- return Connection.from_config(configuration, identity, crypto_store)
+ return Connection.from_config(configuration, identity, crypto_store, **kwargs)
@classmethod
def from_config(
@@ -218,6 +218,7 @@ def from_config(
configuration: ConnectionConfig,
identity: Identity,
crypto_store: CryptoStore,
+ **kwargs
) -> "Connection":
"""
Load a connection from a configuration.
@@ -249,5 +250,18 @@ def from_config(
connection_class_name
)
return connection_class(
- configuration=configuration, identity=identity, crypto_store=crypto_store
+ configuration=configuration,
+ identity=identity,
+ crypto_store=crypto_store,
+ **kwargs
)
+
+ @property
+ def is_connected(self) -> bool:
+ """Return is connected state."""
+ return self.state == ConnectionStates.connected
+
+ @property
+ def is_disconnected(self) -> bool:
+ """Return is disconnected state."""
+ return self.state == ConnectionStates.disconnected
diff --git a/aea/connections/scaffold/connection.yaml b/aea/connections/scaffold/connection.yaml
index 21393b32e4..c1e655bae3 100644
--- a/aea/connections/scaffold/connection.yaml
+++ b/aea/connections/scaffold/connection.yaml
@@ -8,6 +8,7 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmZvYZ5ECcWwqiNGh8qNTg735wu51HqaLxTSifUxkQ4KGj
connection.py: QmT7MNg8gkmWMzthN3k77i6UVhwXBeC2bGiNrUmXQcjWit
+ readme.md: Qmdt71SaCCwAG1c24VktXDm4pxgUBiPMg4bWfUTiqorypf
fingerprint_ignore_patterns: []
protocols: []
class_name: MyScaffoldConnection
diff --git a/aea/connections/scaffold/readme.md b/aea/connections/scaffold/readme.md
new file mode 100644
index 0000000000..6359d72d7b
--- /dev/null
+++ b/aea/connections/scaffold/readme.md
@@ -0,0 +1,5 @@
+# Scaffold connection
+The scaffold connection acts as a boilerplate for a newly created connection.
+
+## Usage
+Create a scaffold connection with the `aea scaffold connection {NAME}` command and implement your own connection.
diff --git a/aea/connections/stub/connection.py b/aea/connections/stub/connection.py
index 71fdef4769..4aa3fe28b4 100644
--- a/aea/connections/stub/connection.py
+++ b/aea/connections/stub/connection.py
@@ -30,7 +30,7 @@
from typing import AsyncIterable, IO, List, Optional
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.helpers import file_lock
from aea.helpers.base import exception_log_and_reraise
from aea.mail.base import Envelope
@@ -44,7 +44,7 @@
DEFAULT_OUTPUT_FILE_NAME = "./output_file"
SEPARATOR = b","
-PUBLIC_ID = PublicId.from_str("fetchai/stub:0.6.0")
+PUBLIC_ID = PublicId.from_str("fetchai/stub:0.7.0")
def _encode(e: Envelope, separator: bytes = SEPARATOR):
@@ -251,19 +251,19 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
async def connect(self) -> None:
"""Set up the connection."""
- if self.connection_status.is_connected:
+ if self.is_connected:
return
- self._loop = asyncio.get_event_loop()
+
+ self._state.set(ConnectionStates.connecting)
+
try:
- # initialize the queue here because the queue
- # must be initialized with the right event loop
- # which is known only at connection time.
+ self._loop = asyncio.get_event_loop()
self.in_queue = asyncio.Queue()
self._read_envelopes_task = self._loop.create_task(self.read_envelopes())
- finally:
- self.connection_status.is_connected = False
-
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
+ except Exception: # pragma: no cover
+ self._state.set(ConnectionStates.disconnected)
+ raise
async def _stop_read_envelopes(self) -> None:
"""
@@ -292,14 +292,16 @@ async def disconnect(self) -> None:
In this type of connection there's no channel to disconnect.
"""
- if not self.connection_status.is_connected:
+ if self.is_disconnected:
return
assert self.in_queue is not None, "Input queue not initialized."
+
+ self._state.set(ConnectionStates.disconnecting)
await self._stop_read_envelopes()
self._write_pool.shutdown(wait=False)
self.in_queue.put_nowait(None)
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: Envelope) -> None:
"""
diff --git a/aea/connections/stub/connection.yaml b/aea/connections/stub/connection.yaml
index b066d6281c..6a9045d90e 100644
--- a/aea/connections/stub/connection.yaml
+++ b/aea/connections/stub/connection.yaml
@@ -1,13 +1,14 @@
name: stub
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The stub connection implements a connection stub which reads/writes messages
from/to file.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmWwepN9Fy9gHAp39vUGFSLdnB9JZjdyE3STnbowSUhJkC
- connection.py: QmSTtyR9GAeTRpby8dWNXwLQ2XHQdVhxKpLesruUJKsw9v
+ connection.py: QmVkdNVgxBLMcTbPqUF1aTz1hcjF5bW8HXkXrcc8MyfRFz
+ readme.md: Qmdh2bmWqSCTZPGoLomuG4Gfbfcktz3bR7hVTLJTpVH9Xn
fingerprint_ignore_patterns: []
protocols: []
class_name: StubConnection
diff --git a/aea/connections/stub/readme.md b/aea/connections/stub/readme.md
new file mode 100644
index 0000000000..a534a8e5b9
--- /dev/null
+++ b/aea/connections/stub/readme.md
@@ -0,0 +1,7 @@
+# stub connection
+A simple connection for communication with an AEA, using the file system as a point of data exchange.
+
+## Usage
+First, add the connection to your AEA project: `aea add connection fetchai/stub:0.7.0`. (If you have created your AEA project with `aea create` then the connection will already be available by default.)
+
+Optionally, in the `connection.yaml` file under `config` set the `input_file` and `output_file` to the desired file path. The `stub` connection reads encoded envelopes from the `input_file` and writes encoded envelopes to the `output_file`.
diff --git a/aea/context/base.py b/aea/context/base.py
index 778ee507d8..f789a9d6c3 100644
--- a/aea/context/base.py
+++ b/aea/context/base.py
@@ -24,10 +24,9 @@
from typing import Any, Dict, Optional
from aea.configurations.base import PublicId
-from aea.connections.base import ConnectionStatus
from aea.identity.base import Identity
from aea.mail.base import Address
-from aea.multiplexer import OutBox
+from aea.multiplexer import ConnectionStatus, OutBox
from aea.skills.tasks import TaskManager
diff --git a/aea/contracts/base.py b/aea/contracts/base.py
index 9f53aa0e61..275944b9ad 100644
--- a/aea/contracts/base.py
+++ b/aea/contracts/base.py
@@ -43,13 +43,13 @@ class Contract(Component, ABC):
contract_interface: Any = None
- def __init__(self, contract_config: ContractConfig):
+ def __init__(self, contract_config: ContractConfig, **kwargs):
"""
Initialize the contract.
:param contract_config: the contract configurations.
"""
- super().__init__(contract_config)
+ super().__init__(contract_config, **kwargs)
@property
def id(self) -> ContractId:
@@ -76,7 +76,7 @@ def get_instance(
"""
@classmethod
- def from_dir(cls, directory: str) -> "Contract":
+ def from_dir(cls, directory: str, **kwargs) -> "Contract":
"""
Load the protocol from a directory.
@@ -88,10 +88,10 @@ def from_dir(cls, directory: str) -> "Contract":
ComponentConfiguration.load(ComponentType.CONTRACT, Path(directory)),
)
configuration.directory = Path(directory)
- return Contract.from_config(configuration)
+ return Contract.from_config(configuration, **kwargs)
@classmethod
- def from_config(cls, configuration: ContractConfig) -> "Contract":
+ def from_config(cls, configuration: ContractConfig, **kwargs) -> "Contract":
"""
Load contract from configuration.
@@ -120,4 +120,64 @@ def from_config(cls, configuration: ContractConfig) -> "Contract":
# with open(path, "r") as interface_file:
# contract_interface = json.load(interface_file)
- return contract_class(configuration)
+ return contract_class(configuration, **kwargs)
+
+ @classmethod
+ def get_deploy_transaction(cls, ledger_api: LedgerApi, **kwargs) -> bytes:
+ """
+ Handler method for the 'GET_DEPLOY_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 kwargs: keyword arguments.
+ :return: the bytes representing the state.
+ """
+ raise NotImplementedError
+
+ @classmethod
+ def get_raw_transaction(
+ cls, ledger_api: LedgerApi, contract_address: str, **kwargs
+ ) -> bytes:
+ """
+ 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.
+ :return: the bytes representing the state.
+ """
+ raise NotImplementedError
+
+ @classmethod
+ def get_raw_message(
+ cls, ledger_api: LedgerApi, contract_address: str, **kwargs
+ ) -> 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.
+ :return: the bytes representing the state.
+ """
+ raise NotImplementedError
+
+ @classmethod
+ def get_state(cls, ledger_api: LedgerApi, contract_address: str, **kwargs) -> bytes:
+ """
+ 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.
+ :return: the bytes representing the state.
+ """
+ raise NotImplementedError
diff --git a/aea/crypto/__init__.py b/aea/crypto/__init__.py
index e493ef4f70..0a07586c50 100644
--- a/aea/crypto/__init__.py
+++ b/aea/crypto/__init__.py
@@ -22,7 +22,11 @@
from aea.crypto.cosmos import CosmosCrypto
from aea.crypto.ethereum import EthereumCrypto
from aea.crypto.fetchai import FetchAICrypto
-from aea.crypto.registries import register_crypto, register_ledger_api # noqa
+from aea.crypto.registries import (
+ register_crypto,
+ register_faucet_api,
+ register_ledger_api,
+) # noqa
register_crypto(
id_=FetchAICrypto.identifier, entry_point="aea.crypto.fetchai:FetchAICrypto"
@@ -34,6 +38,16 @@
id_=CosmosCrypto.identifier, entry_point="aea.crypto.cosmos:CosmosCrypto"
)
+register_faucet_api(
+ id_=FetchAICrypto.identifier, entry_point="aea.crypto.fetchai:FetchAIFaucetApi"
+)
+register_faucet_api(
+ id_=EthereumCrypto.identifier, entry_point="aea.crypto.ethereum:EthereumFaucetApi"
+)
+register_faucet_api(
+ id_=CosmosCrypto.identifier, entry_point="aea.crypto.cosmos:CosmosFaucetApi"
+)
+
register_ledger_api(
id_=FetchAICrypto.identifier, entry_point="aea.crypto.fetchai:FetchAIApi",
)
diff --git a/aea/crypto/base.py b/aea/crypto/base.py
index 90a0e0eab9..b404e2f6a7 100644
--- a/aea/crypto/base.py
+++ b/aea/crypto/base.py
@@ -202,6 +202,16 @@ def recover_message(
:return: the recovered addresses
"""
+ @staticmethod
+ @abstractmethod
+ def get_hash(message: bytes) -> str:
+ """
+ Get the hash of a message.
+
+ :param message: the message to be hashed.
+ :return: the hash of the message.
+ """
+
class LedgerApi(Helper, ABC):
"""Interface for ledger APIs."""
@@ -283,6 +293,7 @@ class FaucetApi(ABC):
"""Interface for testnet faucet APIs."""
identifier = "base" # type: str
+ network_name = "testnet" # type: str
@abstractmethod
def get_wealth(self, address: Address) -> None:
diff --git a/aea/crypto/cosmos.py b/aea/crypto/cosmos.py
index 96e6de1452..c76956cb01 100644
--- a/aea/crypto/cosmos.py
+++ b/aea/crypto/cosmos.py
@@ -42,6 +42,7 @@
_COSMOS = "cosmos"
COSMOS_TESTNET_FAUCET_URL = "https://faucet-agent-land.prod.fetch-ai.com:443/claim"
+TESTNET_NAME = "testnet"
DEFAULT_ADDRESS = "https://rest-agent-land.prod.fetch-ai.com:443"
DEFAULT_CURRENCY_DENOM = "atestfet"
DEFAULT_CHAIN_ID = "agent-land"
@@ -117,17 +118,19 @@ def sign_message(self, message: bytes, is_deprecated_mode: bool = False) -> str:
signature_base64_str = base64.b64encode(signature_compact).decode("utf-8")
return signature_base64_str
- def sign_transaction(self, transaction: Any) -> Any:
+ @staticmethod
+ def format_default_transaction(
+ transaction: Any, signature: str, base64_pbk: str
+ ) -> Any:
"""
- Sign a transaction in bytes string form.
+ Format default CosmosSDK transaction and add signature
- :param transaction: the transaction to be signed
- :return: signed transaction
+ :param transaction: the transaction to be formatted
+ :param signature: the transaction signature
+ :param base64_pbk: the base64 formatted public key
+
+ :return: formatted transaction with signature
"""
- transaction_str = json.dumps(transaction, separators=(",", ":"), sort_keys=True)
- transaction_bytes = transaction_str.encode("utf-8")
- signed_transaction = self.sign_message(transaction_bytes)
- base64_pbk = base64.b64encode(bytes.fromhex(self.public_key)).decode("utf-8")
pushable_tx = {
"tx": {
"msg": transaction["msgs"],
@@ -135,7 +138,7 @@ def sign_transaction(self, transaction: Any) -> Any:
"memo": transaction["memo"],
"signatures": [
{
- "signature": signed_transaction,
+ "signature": signature,
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": base64_pbk,
@@ -149,6 +152,66 @@ def sign_transaction(self, transaction: Any) -> Any:
}
return pushable_tx
+ @staticmethod
+ def format_wasm_transaction(
+ transaction: Any, signature: str, base64_pbk: str
+ ) -> Any:
+ """
+ Format CosmWasm transaction and add signature
+
+ :param transaction: the transaction to be formatted
+ :param signature: the transaction signature
+ :param base64_pbk: the base64 formatted public key
+
+ :return: formatted transaction with signature
+ """
+
+ pushable_tx = {
+ "type": "cosmos-sdk/StdTx",
+ "value": {
+ "msg": transaction["msgs"],
+ "fee": transaction["fee"],
+ "signatures": [
+ {
+ "pub_key": {
+ "type": "tendermint/PubKeySecp256k1",
+ "value": base64_pbk,
+ },
+ "signature": signature,
+ }
+ ],
+ "memo": transaction["memo"],
+ },
+ }
+ return pushable_tx
+
+ def sign_transaction(self, transaction: Any) -> Any:
+ """
+ Sign a transaction in bytes string form.
+
+ :param transaction: the transaction to be signed
+ :return: signed transaction
+ """
+
+ transaction_str = json.dumps(transaction, separators=(",", ":"), sort_keys=True)
+ transaction_bytes = transaction_str.encode("utf-8")
+ signed_transaction = self.sign_message(transaction_bytes)
+ base64_pbk = base64.b64encode(bytes.fromhex(self.public_key)).decode("utf-8")
+
+ if (
+ "msgs" in transaction
+ and len(transaction["msgs"]) == 1
+ and "type" in transaction["msgs"][0]
+ and "wasm" in transaction["msgs"][0]["type"]
+ ):
+ return self.format_wasm_transaction(
+ transaction, signed_transaction, base64_pbk
+ )
+ else:
+ return self.format_default_transaction(
+ transaction, signed_transaction, base64_pbk
+ )
+
@classmethod
def generate_private_key(cls) -> SigningKey:
"""Generate a key pair for cosmos network."""
@@ -268,6 +331,17 @@ def recover_message(
]
return tuple(addresses)
+ @staticmethod
+ def get_hash(message: bytes) -> str:
+ """
+ Get the hash of a message.
+
+ :param message: the message to be hashed.
+ :return: the hash of the message.
+ """
+ digest = hashlib.sha256(message).hexdigest()
+ return digest
+
class CosmosApi(LedgerApi, CosmosHelper):
"""Class to interact with the Cosmos SDK via a HTTP APIs."""
@@ -456,6 +530,7 @@ class CosmosFaucetApi(FaucetApi):
"""Cosmos testnet faucet API."""
identifier = _COSMOS
+ testnet_name = TESTNET_NAME
def get_wealth(self, address: Address) -> None:
"""
diff --git a/aea/crypto/ethereum.py b/aea/crypto/ethereum.py
index 51937bfd1d..cca52d9442 100644
--- a/aea/crypto/ethereum.py
+++ b/aea/crypto/ethereum.py
@@ -44,6 +44,7 @@
_ETHEREUM = "ethereum"
GAS_ID = "gwei"
ETHEREUM_TESTNET_FAUCET_URL = "https://faucet.ropsten.be/donate/"
+TESTNET_NAME = "ropsten"
DEFAULT_ADDRESS = "https://ropsten.infura.io/v3/f00f7b3ba0e848ddbdc8941c527447fe"
DEFAULT_CHAIN_ID = 3
DEFAULT_GAS_PRICE = "50"
@@ -244,6 +245,17 @@ def recover_message(
)
return (address,)
+ @staticmethod
+ def get_hash(message: bytes) -> str:
+ """
+ Get the hash of a message.
+
+ :param message: the message to be hashed.
+ :return: the hash of the message.
+ """
+ digest = Web3.keccak(message).hex()
+ return digest
+
class EthereumApi(LedgerApi, EthereumHelper):
"""Class to interact with the Ethereum Web3 APIs."""
@@ -419,6 +431,7 @@ class EthereumFaucetApi(FaucetApi):
"""Ethereum testnet faucet API."""
identifier = _ETHEREUM
+ testnet_name = TESTNET_NAME
def get_wealth(self, address: Address) -> None:
"""
diff --git a/aea/crypto/fetchai.py b/aea/crypto/fetchai.py
index 9e091f2997..1c35352faf 100644
--- a/aea/crypto/fetchai.py
+++ b/aea/crypto/fetchai.py
@@ -48,6 +48,7 @@
DEFAULT_NETWORK = "testnet"
SUCCESSFUL_TERMINAL_STATES = ("Executed", "Submitted")
FETCHAI_TESTNET_FAUCET_URL = "https://explore-testnet.fetch.ai/api/v1/send_tokens/"
+TESTNET_NAME = "testnet"
class FetchAICrypto(Crypto[Entity]):
@@ -241,6 +242,17 @@ def recover_message(
]
return tuple(addresses)
+ @staticmethod
+ def get_hash(message: bytes) -> str:
+ """
+ Get the hash of a message.
+
+ :param message: the message to be hashed.
+ :return: the hash of the message.
+ """
+ digest = sha256_hash(message)
+ return digest.hex()
+
class FetchAIApi(LedgerApi, FetchAIHelper):
"""Class to interact with the Fetch ledger APIs."""
@@ -366,6 +378,7 @@ class FetchAIFaucetApi(FaucetApi):
"""Fetchai testnet faucet API."""
identifier = _FETCHAI
+ testnet_name = TESTNET_NAME
def get_wealth(self, address: Address) -> None:
"""
diff --git a/aea/crypto/helpers.py b/aea/crypto/helpers.py
index feb326b2bb..ad6e1bf970 100644
--- a/aea/crypto/helpers.py
+++ b/aea/crypto/helpers.py
@@ -21,35 +21,73 @@
import logging
import sys
-from typing import Optional
+from pathlib import Path
-from aea.crypto.cosmos import CosmosCrypto, CosmosFaucetApi
-from aea.crypto.ethereum import EthereumCrypto, EthereumFaucetApi
-from aea.crypto.fetchai import FetchAICrypto, FetchAIFaucetApi
-from aea.crypto.registries import make_crypto
+from aea.configurations.base import AgentConfig, DEFAULT_AEA_CONFIG_FILE
+from aea.configurations.loader import ConfigLoader
+from aea.crypto.cosmos import CosmosCrypto
+from aea.crypto.ethereum import EthereumCrypto
+from aea.crypto.fetchai import FetchAICrypto
+from aea.crypto.registries import crypto_registry, make_crypto, make_faucet_api
COSMOS_PRIVATE_KEY_FILE = "cosmos_private_key.txt"
FETCHAI_PRIVATE_KEY_FILE = "fet_private_key.txt"
ETHEREUM_PRIVATE_KEY_FILE = "eth_private_key.txt"
-TESTNETS = {
- FetchAICrypto.identifier: "testnet",
- EthereumCrypto.identifier: "ropsten",
- CosmosCrypto.identifier: "testnet",
-}
IDENTIFIER_TO_KEY_FILES = {
CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE,
EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_FILE,
FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE,
}
-IDENTIFIER_TO_FAUCET_APIS = {
- CosmosCrypto.identifier: CosmosFaucetApi(),
- EthereumCrypto.identifier: EthereumFaucetApi(),
- FetchAICrypto.identifier: FetchAIFaucetApi(),
-}
logger = logging.getLogger(__name__)
+def verify_or_create_private_keys(
+ aea_project_path: Path, exit_on_error: bool = True,
+) -> AgentConfig:
+ """
+ Verify or create private keys.
+
+ :param ctx: Context
+ """
+ path_to_aea_config = aea_project_path / DEFAULT_AEA_CONFIG_FILE
+ agent_loader = ConfigLoader("aea-config_schema.json", AgentConfig)
+ fp = path_to_aea_config.open(mode="r", encoding="utf-8")
+ aea_conf = agent_loader.load(fp)
+
+ for identifier, _value in aea_conf.private_key_paths.read_all():
+ if identifier not in crypto_registry.supported_ids: # pragma: nocover
+ ValueError("Unsupported identifier in private key paths.")
+
+ for identifier, private_key_path in IDENTIFIER_TO_KEY_FILES.items():
+ config_private_key_path = aea_conf.private_key_paths.read(identifier)
+ if config_private_key_path is None:
+ if identifier == aea_conf.default_ledger: # pragma: nocover
+ create_private_key(
+ identifier,
+ private_key_file=str(aea_project_path / private_key_path),
+ )
+ aea_conf.private_key_paths.update(identifier, private_key_path)
+ else:
+ try:
+ try_validate_private_key_path(
+ identifier,
+ str(aea_project_path / private_key_path),
+ exit_on_error=exit_on_error,
+ )
+ except FileNotFoundError: # pragma: no cover
+ raise ValueError(
+ "File {} for private key {} not found.".format(
+ repr(private_key_path), identifier,
+ )
+ )
+
+ # update aea config
+ fp = path_to_aea_config.open(mode="w", encoding="utf-8")
+ agent_loader.dump(aea_conf, fp)
+ return aea_conf
+
+
def try_validate_private_key_path(
ledger_id: str, private_key_path: str, exit_on_error: bool = True
) -> None:
@@ -77,16 +115,15 @@ def try_validate_private_key_path(
raise
-def create_private_key(ledger_id: str, private_key_file: Optional[str] = None) -> None:
+def create_private_key(ledger_id: str, private_key_file: str) -> None:
"""
Create a private key for the specified ledger identifier.
:param ledger_id: the ledger identifier.
+ :param private_key_file: the private key file.
:return: None
:raises: ValueError if the identifier is invalid.
"""
- if private_key_file is None:
- private_key_file = IDENTIFIER_TO_KEY_FILES[ledger_id]
crypto = make_crypto(ledger_id)
crypto.dump(open(private_key_file, "wb"))
@@ -99,6 +136,6 @@ def try_generate_testnet_wealth(identifier: str, address: str) -> None:
:param address: the address to check for
:return: None
"""
- faucet_api = IDENTIFIER_TO_FAUCET_APIS.get(identifier, None)
+ faucet_api = make_faucet_api(identifier)
if faucet_api is not None:
faucet_api.get_wealth(address)
diff --git a/aea/crypto/ledger_apis.py b/aea/crypto/ledger_apis.py
index a411553bf8..29aa10cf2f 100644
--- a/aea/crypto/ledger_apis.py
+++ b/aea/crypto/ledger_apis.py
@@ -19,22 +19,22 @@
"""Module wrapping all the public and private keys cryptography."""
import logging
-from typing import Any, Dict, Optional, Type, Union
+from typing import Any, Dict, Optional, Tuple, Union
+from aea.configurations.constants import DEFAULT_LEDGER
from aea.crypto.base import LedgerApi
from aea.crypto.cosmos import CosmosApi
from aea.crypto.cosmos import DEFAULT_ADDRESS as COSMOS_DEFAULT_ADDRESS
from aea.crypto.ethereum import DEFAULT_ADDRESS as ETHEREUM_DEFAULT_ADDRESS
from aea.crypto.ethereum import DEFAULT_CHAIN_ID, EthereumApi
from aea.crypto.fetchai import DEFAULT_NETWORK, FetchAIApi
-from aea.crypto.registries import make_ledger_api
+from aea.crypto.registries import (
+ ledger_apis_registry,
+ make_ledger_api,
+ make_ledger_api_cls,
+)
from aea.mail.base import Address
-SUPPORTED_LEDGER_APIS = {
- CosmosApi.identifier: CosmosApi,
- EthereumApi.identifier: EthereumApi,
- FetchAIApi.identifier: FetchAIApi,
-} # type: Dict[str, Type[LedgerApi]]
DEFAULT_LEDGER_CONFIGS = {
CosmosApi.identifier: {"address": COSMOS_DEFAULT_ADDRESS},
EthereumApi.identifier: {
@@ -50,55 +50,24 @@
class LedgerApis:
"""Store all the ledger apis we initialise."""
- def __init__(
- self,
- ledger_api_configs: Dict[str, Dict[str, Union[str, int]]],
- default_ledger_id: str,
- ):
- """
- Instantiate a wallet object.
-
- :param ledger_api_configs: the ledger api configs.
- :param default_ledger_id: the default ledger id.
- """
- apis = {} # type: Dict[str, LedgerApi]
- for identifier, config in ledger_api_configs.items():
- api = make_ledger_api(identifier, **config)
- apis[identifier] = api
- self._apis = apis
- self._configs = ledger_api_configs
- self._default_ledger_id = default_ledger_id
-
- @property
- def configs(self) -> Dict[str, Dict[str, Union[str, int]]]:
- """Get the configs."""
- return self._configs
-
- @property
- def apis(self) -> Dict[str, LedgerApi]:
- """Get the apis."""
- return self._apis
+ ledger_api_configs: Dict[str, Dict[str, Union[str, int]]] = DEFAULT_LEDGER_CONFIGS
- def has_ledger(self, identifier: str) -> bool:
- """Check if it has a ."""
- return identifier in self.apis
+ @staticmethod
+ def has_ledger(identifier: str) -> bool:
+ """Check if it has the api."""
+ return identifier in ledger_apis_registry.supported_ids
- def get_api(self, identifier: str) -> LedgerApi:
+ @classmethod
+ def get_api(cls, identifier: str) -> LedgerApi:
"""Get the ledger API."""
- assert self.has_ledger(identifier), "Ledger API not instantiated!"
- return self.apis[identifier]
-
- @property
- def has_default_ledger(self) -> bool:
- """Check if it has the default ledger API."""
- return self.default_ledger_id in self.apis.keys()
-
- @property
- def default_ledger_id(self) -> str:
- """Get the default ledger id."""
- return self._default_ledger_id
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
+ return api
- def get_balance(self, identifier: str, address: str) -> Optional[int]:
+ @classmethod
+ def get_balance(cls, identifier: str, address: str) -> Optional[int]:
"""
Get the token balance.
@@ -106,13 +75,16 @@ def get_balance(self, identifier: str, address: str) -> Optional[int]:
:param address: the address to check for
:return: the token balance
"""
- assert identifier in self.apis.keys(), "Not a registered ledger api identifier."
- api = self.apis[identifier]
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
balance = api.get_balance(address)
return balance
+ @classmethod
def get_transfer_transaction(
- self,
+ cls,
identifier: str,
sender_address: str,
destination_address: str,
@@ -133,14 +105,17 @@ def get_transfer_transaction(
:return: tx
"""
- assert identifier in self.apis.keys(), "Not a registered ledger api identifier."
- api = self.apis[identifier]
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
tx = api.get_transfer_transaction(
sender_address, destination_address, amount, tx_fee, tx_nonce, **kwargs,
)
return tx
- def send_signed_transaction(self, identifier: str, tx_signed: Any) -> Optional[str]:
+ @classmethod
+ def send_signed_transaction(cls, identifier: str, tx_signed: Any) -> Optional[str]:
"""
Send a signed transaction and wait for confirmation.
@@ -148,12 +123,15 @@ def send_signed_transaction(self, identifier: str, tx_signed: Any) -> Optional[s
:param tx_signed: the signed transaction
:return: the tx_digest, if present
"""
- assert identifier in self.apis.keys(), "Not a registered ledger api identifier."
- api = self.apis[identifier]
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
tx_digest = api.send_signed_transaction(tx_signed)
return tx_digest
- def get_transaction_receipt(self, identifier: str, tx_digest: str) -> Optional[Any]:
+ @classmethod
+ def get_transaction_receipt(cls, identifier: str, tx_digest: str) -> Optional[Any]:
"""
Get the transaction receipt for a transaction digest.
@@ -161,12 +139,15 @@ def get_transaction_receipt(self, identifier: str, tx_digest: str) -> Optional[A
:param tx_digest: the digest associated to the transaction.
:return: the tx receipt, if present
"""
- assert identifier in self.apis.keys(), "Not a registered ledger api identifier."
- api = self.apis[identifier]
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
tx_receipt = api.get_transaction_receipt(tx_digest)
return tx_receipt
- def get_transaction(self, identifier: str, tx_digest: str) -> Optional[Any]:
+ @classmethod
+ def get_transaction(cls, identifier: str, tx_digest: str) -> Optional[Any]:
"""
Get the transaction for a transaction digest.
@@ -174,8 +155,10 @@ def get_transaction(self, identifier: str, tx_digest: str) -> Optional[Any]:
:param tx_digest: the digest associated to the transaction.
:return: the tx, if present
"""
- assert identifier in self.apis.keys(), "Not a registered ledger api identifier."
- api = self.apis[identifier]
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api = make_ledger_api(identifier, **cls.ledger_api_configs[identifier])
tx = api.get_transaction(tx_digest)
return tx
@@ -189,9 +172,9 @@ def is_transaction_settled(identifier: str, tx_receipt: Any) -> bool:
:return: True if correctly settled, False otherwise
"""
assert (
- identifier in SUPPORTED_LEDGER_APIS.keys()
+ identifier in ledger_apis_registry.supported_ids
), "Not a registered ledger api identifier."
- api_class = SUPPORTED_LEDGER_APIS[identifier]
+ api_class = make_ledger_api_cls(identifier)
is_settled = api_class.is_transaction_settled(tx_receipt)
return is_settled
@@ -216,9 +199,9 @@ def is_transaction_valid(
:return: True if is valid , False otherwise
"""
assert (
- identifier in SUPPORTED_LEDGER_APIS.keys()
+ identifier in ledger_apis_registry.supported_ids
), "Not a registered ledger api identifier."
- api_class = SUPPORTED_LEDGER_APIS[identifier]
+ api_class = make_ledger_api_cls(identifier)
is_valid = api_class.is_transaction_valid(tx, seller, client, tx_nonce, amount)
return is_valid
@@ -233,8 +216,51 @@ def generate_tx_nonce(identifier: str, seller: Address, client: Address) -> str:
:return: return the hash in hex.
"""
assert (
- identifier in SUPPORTED_LEDGER_APIS.keys()
+ identifier in ledger_apis_registry.supported_ids
), "Not a registered ledger api identifier."
- api_class = SUPPORTED_LEDGER_APIS[identifier]
+ api_class = make_ledger_api_cls(identifier)
tx_nonce = api_class.generate_tx_nonce(seller=seller, client=client)
return tx_nonce
+
+ @staticmethod
+ def recover_message(
+ identifier: str,
+ message: bytes,
+ signature: str,
+ is_deprecated_mode: bool = False,
+ ) -> Tuple[Address, ...]:
+ """
+ Recover the addresses from the hash.
+
+ :param identifier: ledger identifier.
+ :param message: the message we expect
+ :param signature: the transaction signature
+ :param is_deprecated_mode: if the deprecated signing was used
+ :return: the recovered addresses
+ """
+ assert (
+ identifier in ledger_apis_registry.supported_ids
+ ), "Not a registered ledger api identifier."
+ api_class = make_ledger_api_cls(identifier)
+ addresses = api_class.recover_message(
+ message=message, signature=signature, is_deprecated_mode=is_deprecated_mode
+ )
+ return addresses
+
+ @staticmethod
+ def get_hash(identifier: str, message: bytes) -> str:
+ """
+ Get the hash of a message.
+
+ :param identifier: ledger identifier.
+ :param message: the message to be hashed.
+ :return: the hash of the message.
+ """
+ identifier = (
+ identifier
+ if identifier in ledger_apis_registry.supported_ids
+ else DEFAULT_LEDGER
+ )
+ api_class = make_ledger_api_cls(identifier)
+ digest = api_class.get_hash(message=message)
+ return digest
diff --git a/aea/crypto/registries/__init__.py b/aea/crypto/registries/__init__.py
index f5d755e8f1..21c94d61cc 100644
--- a/aea/crypto/registries/__init__.py
+++ b/aea/crypto/registries/__init__.py
@@ -18,9 +18,9 @@
# ------------------------------------------------------------------------------
"""This module contains the crypto and the ledger APIs registries."""
-from typing import Callable
+from typing import Callable, Type
-from aea.crypto.base import Crypto, LedgerApi
+from aea.crypto.base import Crypto, FaucetApi, LedgerApi
from aea.crypto.registries.base import Registry
crypto_registry: Registry[Crypto] = Registry[Crypto]()
@@ -30,3 +30,9 @@
ledger_apis_registry: Registry[LedgerApi] = Registry[LedgerApi]()
register_ledger_api = ledger_apis_registry.register
make_ledger_api: Callable[..., LedgerApi] = ledger_apis_registry.make
+make_ledger_api_cls: Callable[..., Type[LedgerApi]] = ledger_apis_registry.make_cls
+
+faucet_apis_registry: Registry[FaucetApi] = Registry[FaucetApi]()
+register_faucet_api = faucet_apis_registry.register
+make_faucet_api: Callable[..., FaucetApi] = faucet_apis_registry.make
+make_faucet_api_cls: Callable[..., Type[FaucetApi]] = faucet_apis_registry.make_cls
diff --git a/aea/crypto/registries/base.py b/aea/crypto/registries/base.py
index 7b9c172dc1..f1bab9d9f6 100644
--- a/aea/crypto/registries/base.py
+++ b/aea/crypto/registries/base.py
@@ -134,11 +134,20 @@ def make(self, **kwargs) -> ItemType:
"""
_kwargs = self._kwargs.copy()
_kwargs.update(kwargs)
+ cls = self.get_class()
+ item = cls(**_kwargs) # type: ignore
+ return item
+
+ def get_class(self) -> Type[ItemType]:
+ """
+ Get the class of the item with class variables instantiated.
+
+ :return: an item class
+ """
cls = self.entry_point.load()
for key, value in self._class_kwargs.items():
setattr(cls, key, value)
- item = cls(**_kwargs) # type: ignore
- return item
+ return cls
class Registry(Generic[ItemType]):
@@ -201,6 +210,29 @@ def make(
item = spec.make(**kwargs)
return item
+ def make_cls(
+ self, id_: Union[ItemId, str], module: Optional[str] = None
+ ) -> Type[ItemType]:
+ """
+ Load a class of the associated type item id.
+
+ :param id_: the id of the item class. Make sure it has been registered earlier
+ before calling this function.
+ :param module: dotted path to a module.
+ whether a module should be loaded before creating the object.
+ this argument is useful when the item might not be registered
+ beforehand, and loading the specified module will make the registration.
+ E.g. suppose the call to 'register' for a custom object
+ is located in some_package/__init__.py. By providing module="some_package",
+ the call to 'register' in such module gets triggered and
+ the make can then find the identifier.
+ :return: the new item class.
+ """
+ item_id = ItemId(id_)
+ spec = self._get_spec(item_id, module=module)
+ cls = spec.get_class()
+ return cls
+
def has_spec(self, item_id: ItemId) -> bool:
"""
Check whether there exist a spec associated with an item id.
diff --git a/aea/crypto/wallet.py b/aea/crypto/wallet.py
index d1028d3aa7..c4971d0e59 100644
--- a/aea/crypto/wallet.py
+++ b/aea/crypto/wallet.py
@@ -45,16 +45,19 @@ def __init__(
crypto_objects = {} # type: Dict[str, Crypto]
public_keys = {} # type: Dict[str, str]
addresses = {} # type: Dict[str, str]
+ private_keys = {} # type: Dict[str, str]
for identifier, path in crypto_id_to_path.items():
crypto = make_crypto(identifier, private_key_path=path)
crypto_objects[identifier] = crypto
public_keys[identifier] = cast(str, crypto.public_key)
addresses[identifier] = cast(str, crypto.address)
+ private_keys[identifier] = cast(str, crypto.private_key)
self._crypto_objects = crypto_objects
self._public_keys = public_keys
self._addresses = addresses
+ self._private_keys = private_keys
@property
def public_keys(self) -> Dict[str, str]:
@@ -71,6 +74,11 @@ def addresses(self) -> Dict[str, str]:
"""Get the crypto addresses."""
return self._addresses
+ @property
+ def private_keys(self) -> Dict[str, str]:
+ """Get the crypto addresses."""
+ return self._private_keys
+
class Wallet:
"""
@@ -114,6 +122,11 @@ def addresses(self) -> Dict[str, str]:
"""Get the crypto addresses."""
return self._main_cryptos.addresses
+ @property
+ def private_keys(self) -> Dict[str, str]:
+ """Get the crypto addresses."""
+ return self._main_cryptos.private_keys
+
@property
def main_cryptos(self) -> CryptoStore:
"""Get the main crypto store."""
diff --git a/aea/decision_maker/base.py b/aea/decision_maker/base.py
index 51d5429cae..3cc826502f 100644
--- a/aea/decision_maker/base.py
+++ b/aea/decision_maker/base.py
@@ -17,10 +17,11 @@
#
# ------------------------------------------------------------------------------
"""This module contains the decision maker class."""
+
+import copy
import hashlib
import logging
import threading
-import uuid
from abc import ABC, abstractmethod
from queue import Queue
from threading import Thread
@@ -296,7 +297,7 @@ def __init__(
:param decision_maker_handler: the decision maker handler
"""
self._agent_name = decision_maker_handler.identity.name
- self._queue_access_code = uuid.uuid4().hex
+ self._queue_access_code = uuid4().hex
self._message_in_queue = ProtectedQueue(
self._queue_access_code
) # type: ProtectedQueue
@@ -376,6 +377,10 @@ def handle(self, message: Message) -> None:
:param message: the internal message
:return: None
"""
- message.counterparty = uuid4().hex # TODO: temporary fix only
- message.is_incoming = True
- self.decision_maker_handler.handle(message)
+ # TODO: remove next three lines
+ copy_message = copy.copy(message)
+ copy_message.counterparty = message.sender
+ copy_message.sender = message.sender
+ # copy_message.to = message.to
+ copy_message.is_incoming = True
+ self.decision_maker_handler.handle(copy_message)
diff --git a/aea/helpers/async_utils.py b/aea/helpers/async_utils.py
index 3eec78fad0..4f17212912 100644
--- a/aea/helpers/async_utils.py
+++ b/aea/helpers/async_utils.py
@@ -31,6 +31,7 @@
Any,
Awaitable,
Callable,
+ Container,
List,
Optional,
Sequence,
@@ -63,37 +64,54 @@ def ensure_list(value: Any) -> List:
class AsyncState:
"""Awaitable state."""
- def __init__(self, initial_state: Any = None):
+ def __init__(
+ self, initial_state: Any = None, states_enum: Optional[Container[Any]] = None
+ ):
"""Init async state.
:param initial_state: state to set on start.
+ :param states_enum: container of valid states if not provided state not checked on set.
"""
self._state = initial_state
self._watchers: Set[Future] = set()
-
- @property
- def state(self) -> Any:
- """Return current state."""
- return self.get()
-
- @state.setter
- def state(self, state: Any) -> None:
- """Set state."""
- self.set(state)
+ self._callbacks: List[Callable[[Any], None]] = []
+ self._states_enum = states_enum
def set(self, state: Any) -> None:
"""Set state."""
+ if self._states_enum is not None and state not in self._states_enum:
+ raise ValueError(
+ f"Unsupported state: {state}. Valid states are {self._states_enum}"
+ )
+
if self._state == state: # pragma: no cover
return
+
self._state_changed(state)
self._state = state
+ def add_callback(self, callback_fn: Callable[[Any], None]) -> None:
+ """
+ Add callback to track state changes.
+
+ :param callback_fn: callable object to be called on state changed.
+
+ :return: None
+ """
+ self._callbacks.append(callback_fn)
+
def get(self) -> Any:
"""Get state."""
return self._state
def _state_changed(self, state: Any) -> None:
"""Fulfill watchers for state."""
+ for callback_fn in self._callbacks:
+ try:
+ callback_fn(state)
+ except Exception: # pylint: disable=broad-except
+ logger.exception(f"Exception on calling {callback_fn}")
+
for watcher in list(self._watchers):
if state not in watcher._states: # type: ignore # pylint: disable=protected-access # pragma: nocover
continue
diff --git a/aea/helpers/dialogue/base.py b/aea/helpers/dialogue/base.py
index 5c12d7444a..556cdf095e 100644
--- a/aea/helpers/dialogue/base.py
+++ b/aea/helpers/dialogue/base.py
@@ -28,7 +28,7 @@
import itertools
from abc import ABC, abstractmethod
from enum import Enum
-from typing import Callable, Dict, FrozenSet, List, Optional, Tuple, Type, cast
+from typing import Callable, Dict, FrozenSet, List, Optional, Set, Tuple, Type, cast
from aea.mail.base import Address
from aea.protocols.base import Message
@@ -124,6 +124,15 @@ def from_json(cls, obj: Dict[str, str]) -> "DialogueLabel":
)
return dialogue_label
+ def get_incomplete_version(self) -> "DialogueLabel":
+ """Get the incomplete version of the label."""
+ dialogue_label = DialogueLabel(
+ (self.dialogue_starter_reference, Dialogue.OPPONENT_STARTER_REFERENCE),
+ self.dialogue_opponent_addr,
+ self.dialogue_starter_addr,
+ )
+ return dialogue_label
+
def __str__(self):
"""Get the string representation."""
return "{}_{}_{}_{}".format(
@@ -133,6 +142,22 @@ def __str__(self):
self.dialogue_starter_addr,
)
+ @classmethod
+ def from_str(cls, obj: str) -> "DialogueLabel":
+ """Get the dialogue label from string representation."""
+ (
+ dialogue_starter_reference,
+ dialogue_responder_reference,
+ dialogue_opponent_addr,
+ dialogue_starter_addr,
+ ) = obj.split("_")
+ dialogue_label = DialogueLabel(
+ (dialogue_starter_reference, dialogue_responder_reference),
+ dialogue_opponent_addr,
+ dialogue_starter_addr,
+ )
+ return dialogue_label
+
class Dialogue(ABC):
"""The dialogue class maintains state of a dialogue and manages it."""
@@ -239,6 +264,7 @@ def __init__(
:return: None
"""
self._agent_address = agent_address
+ self._incomplete_dialogue_label = dialogue_label.get_incomplete_version()
self._dialogue_label = dialogue_label
self._role = role
@@ -264,6 +290,24 @@ def dialogue_label(self) -> DialogueLabel:
"""
return self._dialogue_label
+ @property
+ def incomplete_dialogue_label(self) -> DialogueLabel:
+ """
+ Get the dialogue label.
+
+ :return: The incomplete dialogue label
+ """
+ return self._incomplete_dialogue_label
+
+ @property
+ def dialogue_labels(self) -> Set[DialogueLabel]:
+ """
+ Get the dialogue labels (incomplete and complete, if it exists)
+
+ :return: the dialogue labels
+ """
+ return {self._dialogue_label, self._incomplete_dialogue_label}
+
@property
def agent_address(self) -> Address:
"""
@@ -392,24 +436,39 @@ def is_empty(self) -> bool:
def update(self, message: Message) -> bool:
"""
- Extend the list of incoming/outgoing messages with 'message', if 'message' is valid.
+ Extend the list of incoming/outgoing messages with 'message', if 'message' belongs to dialogue and is valid.
:param message: a message to be added
:return: True if message successfully added, false otherwise
"""
- if (
- message.is_incoming
- and self.last_message is not None
- and self.last_message.message_id == self.STARTING_MESSAGE_ID
- and self.dialogue_label.dialogue_reference[1]
- == self.OPPONENT_STARTER_REFERENCE
- ):
- self._update_self_initiated_dialogue_label_on_second_message(message)
+ if not message.is_incoming:
+ message.sender = self.agent_address
+ self.ensure_counterparty(message)
+
+ if not self.is_belonging_to_dialogue(message):
+ return False
+
+ is_extendable = self.is_valid_next_message(message)
+ if is_extendable:
+ if message.is_incoming:
+ self._incoming_messages.extend([message])
+ else:
+ self._outgoing_messages.extend([message])
+ return is_extendable
+
+ def ensure_counterparty(self, message: Message) -> None:
+ """
+ Ensure the counterparty is set (set if not) correctly.
+
+ :param message: a message
+ :return: None
+ """
counterparty = None # type: Optional[str]
try:
counterparty = message.counterparty
except AssertionError:
+ # assume message belongs to dialogue
message.counterparty = self.dialogue_label.dialogue_opponent_addr
if counterparty is not None:
@@ -417,13 +476,26 @@ def update(self, message: Message) -> bool:
message.counterparty == self.dialogue_label.dialogue_opponent_addr
), "The counterparty specified in the message is different from the opponent in this dialogue."
- is_extendable = self.is_valid_next_message(message)
- if is_extendable:
- if message.is_incoming:
- self._incoming_messages.extend([message])
- else:
- self._outgoing_messages.extend([message])
- return is_extendable
+ def is_belonging_to_dialogue(self, message: Message) -> bool:
+ """
+ Check if the message is belonging to the dialogue.
+
+ :param message: the message
+ :return: Ture if message is part of the dialogue, False otherwise
+ """
+ if self.is_self_initiated:
+ self_initiated_dialogue_label = DialogueLabel(
+ (message.dialogue_reference[0], Dialogue.OPPONENT_STARTER_REFERENCE),
+ message.counterparty,
+ self.agent_address,
+ )
+ result = self_initiated_dialogue_label in self.dialogue_labels
+ else:
+ other_initiated_dialogue_label = DialogueLabel(
+ message.dialogue_reference, message.counterparty, message.counterparty
+ )
+ result = other_initiated_dialogue_label in self.dialogue_labels
+ return result
def reply(self, target_message: Message, performative, **kwargs) -> Message:
"""
@@ -455,49 +527,6 @@ def reply(self, target_message: Message, performative, **kwargs) -> Message:
else:
raise Exception("Invalid message from performative and contents.")
- def _update_self_initiated_dialogue_label_on_second_message(
- self, second_message: Message
- ) -> None:
- """
- Update this (self initiated) dialogue's dialogue_label with a complete dialogue reference from counterparty's first message.
-
- :param second_message: The second message in the dialogue (the first by the counterparty)
- :return: None
- """
- dialogue_reference = second_message.dialogue_reference
-
- self_initiated_dialogue_reference = (
- dialogue_reference[0],
- self.OPPONENT_STARTER_REFERENCE,
- )
- self_initiated_dialogue_label = DialogueLabel(
- self_initiated_dialogue_reference,
- second_message.counterparty,
- self.agent_address,
- )
-
- if self.last_message is not None:
- if (
- self.dialogue_label == self_initiated_dialogue_label
- and self.last_message.message_id == 1
- and second_message.message_id == 2
- and second_message.is_incoming
- ):
- updated_dialogue_label = DialogueLabel(
- dialogue_reference,
- self_initiated_dialogue_label.dialogue_opponent_addr,
- self_initiated_dialogue_label.dialogue_starter_addr,
- )
- self.update_dialogue_label(updated_dialogue_label)
- else:
- raise Exception(
- "Invalid call to update dialogue's reference. This call must be made only after receiving dialogue's second message by the counterparty."
- )
- else:
- raise Exception(
- "Cannot update dialogue's reference after the first message."
- )
-
def is_valid_next_message(self, message: Message) -> bool:
"""
Check whether 'message' is a valid next message in this dialogue.
@@ -699,7 +728,10 @@ def __init__(
:param end_states: the list of dialogue endstates
:return: None
"""
- self._dialogues = {} # type: Dict[DialogueLabel, Dialogue]
+ self._dialogues_by_dialogue_label = {} # type: Dict[DialogueLabel, Dialogue]
+ self._incomplete_to_complete_dialogue_labels = (
+ {}
+ ) # type: Dict[DialogueLabel, DialogueLabel]
self._agent_address = agent_address
self._dialogue_nonce = 0
self._dialogue_stats = DialogueStats(end_states)
@@ -722,7 +754,7 @@ def __init__(
@property
def dialogues(self) -> Dict[DialogueLabel, Dialogue]:
"""Get dictionary of dialogues in which the agent engages."""
- return self._dialogues
+ return self._dialogues_by_dialogue_label
@property
def agent_address(self) -> Address:
@@ -745,7 +777,7 @@ def new_self_initiated_dialogue_reference(self) -> Tuple[str, str]:
:return: the next nonce
"""
- return str(self._dialogue_nonce + 1), Dialogue.OPPONENT_STARTER_REFERENCE
+ return str(self._next_dialogue_nonce()), Dialogue.OPPONENT_STARTER_REFERENCE
def create(
self, counterparty: Address, performative: Message.Performative, **kwargs,
@@ -774,13 +806,14 @@ def create(
dialogue = self._create_self_initiated(
dialogue_opponent_addr=counterparty,
+ dialogue_reference=initial_message.dialogue_reference,
role=self._role_from_first_message(initial_message),
)
successfully_updated = dialogue.update(initial_message)
if not successfully_updated:
- self._dialogues.pop(dialogue.dialogue_label)
+ self._dialogues_by_dialogue_label.pop(dialogue.dialogue_label)
self._dialogue_nonce -= 1
raise Exception(
"Cannot create the a dialogue with the specified performative and contents."
@@ -801,58 +834,81 @@ def update(self, message: Message) -> Optional[Dialogue]:
"""
dialogue_reference = message.dialogue_reference
- if ( # new dialogue by other
+ if not message.has_counterparty:
+ raise ValueError(
+ "The message counterparty field is not set {}".format(message)
+ )
+ if message.is_incoming and not message.has_sender:
+ raise ValueError("The message sender field is not set {}".format(message))
+
+ is_invalid_label = (
+ dialogue_reference[0] == Dialogue.OPPONENT_STARTER_REFERENCE
+ and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
+ )
+ is_new_dialogue = (
dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
- and message.is_incoming
- ):
+ and message.message_id == 1
+ and message.target == 0
+ )
+ is_incomplete_label_and_non_initial_msg = (
+ dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
+ and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
+ and message.message_id > 1
+ )
+ if is_invalid_label:
+ dialogue = None # type: Optional[Dialogue]
+ elif is_new_dialogue and message.is_incoming: # new dialogue by other
dialogue = self._create_opponent_initiated(
dialogue_opponent_addr=message.counterparty,
dialogue_reference=dialogue_reference,
role=self._role_from_first_message(message),
- ) # type: Optional[Dialogue]
- elif ( # new dialogue by self
- dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
- and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
- and not message.is_incoming
- ):
- assert (
- message.counterparty is not None
- ), "The message counter-party field is not set {}".format(message)
+ )
+ elif is_new_dialogue and not message.is_incoming: # new dialogue by self
dialogue = self._create_self_initiated(
dialogue_opponent_addr=message.counterparty,
+ dialogue_reference=dialogue_reference,
role=self._role_from_first_message(message),
)
- else: # existing dialogue
- self._update_self_initiated_dialogue_label_on_second_message(message)
+ elif ( # non-initial message with incomplete label
+ is_incomplete_label_and_non_initial_msg
+ ):
+ # we can allow a dialogue to have incomplete reference
+ # as multiple messages can be sent before one is received with complete reference
+ dialogue = self.get_dialogue(message)
+ else:
+ self._update_self_initiated_dialogue_label_on_message_with_complete_reference(
+ message
+ )
dialogue = self.get_dialogue(message)
- if dialogue is not None:
- dialogue.update(message)
+ if dialogue is not None and dialogue.update(message):
result = dialogue # type: Optional[Dialogue]
- else: # couldn't find the dialogue
+ else: # couldn't find the dialogue or invalid message
result = None
return result
- def _update_self_initiated_dialogue_label_on_second_message(
- self, second_message: Message
+ def _update_self_initiated_dialogue_label_on_message_with_complete_reference(
+ self, message: Message
) -> None:
"""
Update a self initiated dialogue label with a complete dialogue reference from counterparty's first message.
- :param second_message: The second message in the dialogue (the first by the counterparty in a self initiated dialogue)
+ :param message: A message in the dialogue (the first by the counterparty with a complete reference)
:return: None
"""
- dialogue_reference = second_message.dialogue_reference
+ dialogue_reference = message.dialogue_reference
+ assert (
+ dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
+ and dialogue_reference[1] != Dialogue.OPPONENT_STARTER_REFERENCE
+ ), "Only complete dialogue references allowed."
self_initiated_dialogue_reference = (
dialogue_reference[0],
Dialogue.OPPONENT_STARTER_REFERENCE,
)
self_initiated_dialogue_label = DialogueLabel(
- self_initiated_dialogue_reference,
- second_message.counterparty,
- self.agent_address,
+ self_initiated_dialogue_reference, message.counterparty, self.agent_address,
)
if self_initiated_dialogue_label in self.dialogues:
@@ -865,10 +921,15 @@ def _update_self_initiated_dialogue_label_on_second_message(
self_initiated_dialogue.update_dialogue_label(final_dialogue_label)
assert (
self_initiated_dialogue.dialogue_label not in self.dialogues
- ), "DialogueLabel already present."
+ and self_initiated_dialogue_label
+ not in self._incomplete_to_complete_dialogue_labels
+ ), "DialogueLabel already present in dialogues."
self.dialogues.update(
{self_initiated_dialogue.dialogue_label: self_initiated_dialogue}
)
+ self._incomplete_to_complete_dialogue_labels[
+ self_initiated_dialogue_label
+ ] = final_dialogue_label
def get_dialogue(self, message: Message) -> Optional[Dialogue]:
"""
@@ -887,15 +948,33 @@ def get_dialogue(self, message: Message) -> Optional[Dialogue]:
dialogue_reference, counterparty, counterparty
)
- if other_initiated_dialogue_label in self.dialogues:
- result = self.dialogues[
- other_initiated_dialogue_label
- ] # type: Optional[Dialogue]
- elif self_initiated_dialogue_label in self.dialogues:
- result = self.dialogues[self_initiated_dialogue_label]
- else:
- result = None
+ self_initiated_dialogue_label = self.get_latest_label(
+ self_initiated_dialogue_label
+ )
+ other_initiated_dialogue_label = self.get_latest_label(
+ other_initiated_dialogue_label
+ )
+ self_initiated_dialogue = self.get_dialogue_from_label(
+ self_initiated_dialogue_label
+ )
+ other_initiated_dialogue = self.get_dialogue_from_label(
+ other_initiated_dialogue_label
+ )
+
+ result = self_initiated_dialogue or other_initiated_dialogue
+ return result
+
+ def get_latest_label(self, dialogue_label: DialogueLabel) -> DialogueLabel:
+ """
+ Retrieve the latest dialogue label if present otherwise return same label.
+
+ :param dialogue_label: the dialogue label
+ :return dialogue_label: the dialogue label
+ """
+ result = self._incomplete_to_complete_dialogue_labels.get(
+ dialogue_label, dialogue_label
+ )
return result
def get_dialogue_from_label(
@@ -911,7 +990,10 @@ def get_dialogue_from_label(
return result
def _create_self_initiated(
- self, dialogue_opponent_addr: Address, role: Dialogue.Role,
+ self,
+ dialogue_opponent_addr: Address,
+ dialogue_reference: Tuple[str, str],
+ role: Dialogue.Role,
) -> Dialogue:
"""
Create a self initiated dialogue.
@@ -921,25 +1003,14 @@ def _create_self_initiated(
:return: the created dialogue.
"""
- dialogue_reference = (
- str(self._next_dialogue_nonce()),
- Dialogue.OPPONENT_STARTER_REFERENCE,
- )
- dialogue_label = DialogueLabel(
+ assert (
+ dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
+ and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
+ ), "Cannot initiate dialogue with preassigned dialogue_responder_reference!"
+ incomplete_dialogue_label = DialogueLabel(
dialogue_reference, dialogue_opponent_addr, self.agent_address
)
- if self._message_class is not None and self._dialogue_class is not None:
- dialogue = self._dialogue_class(
- dialogue_label=dialogue_label,
- message_class=self._message_class,
- agent_address=self.agent_address,
- role=role,
- )
- else:
- dialogue = self.create_dialogue(
- dialogue_label=dialogue_label, role=role,
- ) # pragma: no cover
- self.dialogues.update({dialogue_label: dialogue})
+ dialogue = self._create(incomplete_dialogue_label, role)
return dialogue
def _create_opponent_initiated(
@@ -961,15 +1032,50 @@ def _create_opponent_initiated(
dialogue_reference[0] != Dialogue.OPPONENT_STARTER_REFERENCE
and dialogue_reference[1] == Dialogue.OPPONENT_STARTER_REFERENCE
), "Cannot initiate dialogue with preassigned dialogue_responder_reference!"
+ incomplete_dialogue_label = DialogueLabel(
+ dialogue_reference, dialogue_opponent_addr, dialogue_opponent_addr
+ )
new_dialogue_reference = (
dialogue_reference[0],
str(self._next_dialogue_nonce()),
)
- dialogue_label = DialogueLabel(
+ complete_dialogue_label = DialogueLabel(
new_dialogue_reference, dialogue_opponent_addr, dialogue_opponent_addr
)
+ dialogue = self._create(
+ incomplete_dialogue_label, role, complete_dialogue_label
+ )
+ return dialogue
+
+ def _create(
+ self,
+ incomplete_dialogue_label: DialogueLabel,
+ role: Dialogue.Role,
+ complete_dialogue_label: Optional[DialogueLabel] = None,
+ ) -> Dialogue:
+ """
+ Create a dialogue from label and role.
+
+ :param incomplete_dialogue_label: the dialogue label (incomplete)
+ :param role: the agent's role
+ :param complete_dialogue_label: the dialogue label (complete)
- assert dialogue_label not in self.dialogues
+ :return: the created dialogue
+ """
+ assert (
+ incomplete_dialogue_label
+ not in self._incomplete_to_complete_dialogue_labels
+ ), "Incomplete dialogue label already present."
+ if complete_dialogue_label is None:
+ dialogue_label = incomplete_dialogue_label
+ else:
+ self._incomplete_to_complete_dialogue_labels[
+ incomplete_dialogue_label
+ ] = complete_dialogue_label
+ dialogue_label = complete_dialogue_label
+ assert (
+ dialogue_label not in self.dialogues
+ ), "Dialogue label already present in dialogues."
if self._message_class is not None and self._dialogue_class is not None:
dialogue = self._dialogue_class(
dialogue_label=dialogue_label,
@@ -978,11 +1084,11 @@ def _create_opponent_initiated(
role=role,
)
else:
+ # TODO: remove this approach
dialogue = self.create_dialogue(
dialogue_label=dialogue_label, role=role,
) # pragma: no cover
self.dialogues.update({dialogue_label: dialogue})
-
return dialogue
@abstractmethod
diff --git a/aea/helpers/exec_timeout.py b/aea/helpers/exec_timeout.py
index 371a5aa70e..c70d172e86 100644
--- a/aea/helpers/exec_timeout.py
+++ b/aea/helpers/exec_timeout.py
@@ -203,7 +203,9 @@ def start(cls) -> None:
cls._loop = asyncio.new_event_loop()
cls._stopped_future = Future(loop=cls._loop)
- cls._supervisor_thread = threading.Thread(target=cls._supervisor_event_loop)
+ cls._supervisor_thread = threading.Thread(
+ target=cls._supervisor_event_loop, daemon=True
+ )
cls._supervisor_thread.start()
@classmethod
@@ -227,6 +229,7 @@ def stop(cls, force: bool = False) -> None:
if cls._supervisor_thread and cls._supervisor_thread.is_alive():
cls._supervisor_thread.join()
cls._supervisor_thread = None
+ cls._start_count = 0
@classmethod
def _supervisor_event_loop(cls) -> None:
diff --git a/aea/helpers/logging.py b/aea/helpers/logging.py
index 6cc46866ba..8a085528a5 100644
--- a/aea/helpers/logging.py
+++ b/aea/helpers/logging.py
@@ -19,7 +19,7 @@
"""Logging helpers."""
import logging
from logging import Logger, LoggerAdapter
-from typing import Any, MutableMapping, Optional, Tuple, Union
+from typing import Any, MutableMapping, Optional, Tuple, cast
class AgentLoggerAdapter(LoggerAdapter):
@@ -44,9 +44,7 @@ class WithLogger:
"""Interface to endow subclasses with a logger."""
def __init__(
- self,
- logger: Optional[Union[Logger, LoggerAdapter]] = None,
- default_logger_name: str = "aea",
+ self, logger: Optional[Logger] = None, default_logger_name: str = "aea",
):
"""
Initialize the logger.
@@ -54,19 +52,19 @@ def __init__(
:param logger: the logger object.
:param default_logger_name: the default logger name, if a logger is not provided.
"""
- self._logger = logger
+ self._logger: Optional[Logger] = logger
self._default_logger_name = default_logger_name
@property
- def logger(self) -> Union[Logger, LoggerAdapter]:
+ def logger(self) -> Logger:
"""Get the component logger."""
if self._logger is None:
# if not set (e.g. programmatic instantiation)
# return a default one with the default logger name.
return logging.getLogger(self._default_logger_name)
- return self._logger
+ return cast(Logger, self._logger)
@logger.setter
- def logger(self, logger: Union[Logger, LoggerAdapter]):
+ def logger(self, logger: Optional[Logger]):
"""Set the logger."""
self._logger = logger
diff --git a/aea/helpers/transaction/base.py b/aea/helpers/transaction/base.py
index f96abe34ff..f31533db05 100644
--- a/aea/helpers/transaction/base.py
+++ b/aea/helpers/transaction/base.py
@@ -19,8 +19,12 @@
"""This module contains terms related classes."""
+import collections
+import copy
import pickle # nosec
-from typing import Any, Dict, Optional
+from typing import Any, Dict, List, Optional, Tuple
+
+from aea.crypto.ledger_apis import LedgerApis
Address = str
@@ -398,13 +402,14 @@ def __init__(
counterparty_address: Address,
amount_by_currency_id: Dict[str, int],
quantities_by_good_id: Dict[str, int],
- is_sender_payable_tx_fee: bool,
nonce: str,
+ is_sender_payable_tx_fee: bool = True,
fee_by_currency_id: Optional[Dict[str, int]] = None,
+ is_strict: bool = False,
**kwargs,
):
"""
- Instantiate terms.
+ Instantiate terms of a transaction.
:param ledger_id: the ledger on which the terms are to be settled.
:param sender_address: the sender address of the transaction.
@@ -414,6 +419,7 @@ def __init__(
:param is_sender_payable_tx_fee: whether the sender or counterparty pays the tx fee.
:param nonce: nonce to be included in transaction to discriminate otherwise identical transactions.
:param fee_by_currency_id: the fee associated with the transaction.
+ :param is_strict: whether or not terms must have quantities and amounts of opposite signs.
"""
self._ledger_id = ledger_id
self._sender_address = sender_address
@@ -422,9 +428,42 @@ def __init__(
self._quantities_by_good_id = quantities_by_good_id
self._is_sender_payable_tx_fee = is_sender_payable_tx_fee
self._nonce = nonce
- self._fee_by_currency_id = fee_by_currency_id
+ self._fee_by_currency_id = (
+ fee_by_currency_id if fee_by_currency_id is not None else {}
+ )
+ self._is_strict = is_strict
self._kwargs = kwargs if kwargs is not None else {}
self._check_consistency()
+ (
+ good_ids,
+ sender_supplied_quantities,
+ counterparty_supplied_quantities,
+ ) = self._get_lists()
+ self._good_ids = good_ids
+ self._sender_supplied_quantities = sender_supplied_quantities
+ self._counterparty_supplied_quantities = counterparty_supplied_quantities
+ self._sender_hash = self.get_hash(
+ self.ledger_id,
+ sender_address=self.sender_address,
+ counterparty_address=self.counterparty_address,
+ good_ids=self.good_ids,
+ sender_supplied_quantities=self.sender_supplied_quantities,
+ counterparty_supplied_quantities=self.counterparty_supplied_quantities,
+ sender_payable_amount=self.sender_payable_amount,
+ counterparty_payable_amount=self.counterparty_payable_amount,
+ nonce=self.nonce,
+ )
+ self._counterparty_hash = self.get_hash(
+ self.ledger_id,
+ sender_address=self.counterparty_address,
+ counterparty_address=self.sender_address,
+ good_ids=self.good_ids,
+ sender_supplied_quantities=self.counterparty_supplied_quantities,
+ counterparty_supplied_quantities=self.sender_supplied_quantities,
+ sender_payable_amount=self.counterparty_payable_amount,
+ counterparty_payable_amount=self.sender_payable_amount,
+ nonce=self.nonce,
+ )
def _check_consistency(self) -> None:
"""Check consistency of the object."""
@@ -445,21 +484,6 @@ def _check_consistency(self) -> None:
for key, value in self._quantities_by_good_id.items()
]
), "quantities_by_good_id must be a dictionary with str keys and int values."
- pos_amounts = all(
- [amount >= 0 for amount in self._amount_by_currency_id.values()]
- )
- neg_amounts = all(
- [amount <= 0 for amount in self._amount_by_currency_id.values()]
- )
- pos_quantities = all(
- [quantity >= 0 for quantity in self._quantities_by_good_id.values()]
- )
- neg_quantities = all(
- [quantity <= 0 for quantity in self._quantities_by_good_id.values()]
- )
- assert (pos_amounts and neg_quantities) or (
- neg_amounts and pos_quantities
- ), "quantities and amounts do not constitute valid terms."
assert isinstance(
self._is_sender_payable_tx_fee, bool
), "is_sender_payable_tx_fee must be bool"
@@ -468,11 +492,48 @@ def _check_consistency(self) -> None:
isinstance(self._fee_by_currency_id, dict)
and all(
[
- isinstance(key, str) and isinstance(value, int)
+ isinstance(key, str) and isinstance(value, int) and value >= 0
for key, value in self._fee_by_currency_id.items()
]
)
- ), "fee must be None or Dict[str, int]"
+ ), "fee must be None or Dict[str, int] with positive fees only."
+ assert all(
+ [
+ key in self._amount_by_currency_id
+ for key in self._fee_by_currency_id.keys()
+ ]
+ ), "Fee dictionary has keys which are not present in amount dictionary."
+ if self._is_strict:
+ is_pos_amounts = all(
+ [amount >= 0 for amount in self._amount_by_currency_id.values()]
+ )
+ is_neg_amounts = all(
+ [amount <= 0 for amount in self._amount_by_currency_id.values()]
+ )
+ is_pos_quantities = all(
+ [quantity >= 0 for quantity in self._quantities_by_good_id.values()]
+ )
+ is_neg_quantities = all(
+ [quantity <= 0 for quantity in self._quantities_by_good_id.values()]
+ )
+ assert (is_pos_amounts and is_neg_quantities) or (
+ is_neg_amounts and is_pos_quantities
+ ), "quantities and amounts do not constitute valid terms. All quantities must be of same sign. All amounts must be of same sign. Quantities and amounts must be of different sign."
+
+ @property
+ def id(self) -> str:
+ """Get hash of the terms."""
+ return self.sender_hash
+
+ @property
+ def sender_hash(self) -> str:
+ """Get the sender hash."""
+ return self._sender_hash
+
+ @property
+ def counterparty_hash(self) -> str:
+ """Get the sender hash."""
+ return self._counterparty_hash
@property
def ledger_id(self) -> str:
@@ -498,33 +559,101 @@ def counterparty_address(self, counterparty_address: Address) -> None:
@property
def amount_by_currency_id(self) -> Dict[str, int]:
"""Get the amount by currency id."""
- return self._amount_by_currency_id
+ return copy.copy(self._amount_by_currency_id)
+
+ @property
+ def is_sender_payable_tx_fee(self) -> bool:
+ """Bool indicating whether the tx fee is paid by sender or counterparty."""
+ return self._is_sender_payable_tx_fee
+
+ @property
+ def is_single_currency(self) -> bool:
+ """Check whether a single currency is used for payment."""
+ return (
+ len(self._amount_by_currency_id) == 1 and len(self._fee_by_currency_id) <= 1
+ )
+
+ @property
+ def is_empty_currency(self) -> bool:
+ """Check whether a single currency is used for payment."""
+ return len(self._amount_by_currency_id) == 0
+
+ @property
+ def currency_id(self) -> str:
+ """Get the amount the sender must pay."""
+ assert self.is_single_currency, "More than one currency id, cannot get id."
+ value = next(iter(self._amount_by_currency_id.keys()))
+ return value
@property
def sender_payable_amount(self) -> int:
"""Get the amount the sender must pay."""
assert (
- len(self._amount_by_currency_id) == 1
+ self.is_single_currency or self.is_empty_currency
), "More than one currency id, cannot get amount."
- return -next(iter(self._amount_by_currency_id.values()))
+ value = (
+ next(iter(self._amount_by_currency_id.values()))
+ if not self.is_empty_currency
+ else 0
+ )
+ payable = -value if value <= 0 else 0
+ return payable
+
+ @property
+ def sender_payable_amount_incl_fee(self) -> int:
+ """Get the amount the sender must pay inclusive fee."""
+ assert (
+ self.is_single_currency or self.is_empty_currency
+ ), "More than one currency id, cannot get amount."
+ payable = self.sender_payable_amount
+ if self.is_sender_payable_tx_fee and len(self._fee_by_currency_id) == 1:
+ payable += next(iter(self._fee_by_currency_id.values()))
+ return payable
@property
def counterparty_payable_amount(self) -> int:
"""Get the amount the counterparty must pay."""
assert (
- len(self._amount_by_currency_id) == 1
+ self.is_single_currency or self.is_empty_currency
), "More than one currency id, cannot get amount."
- return next(iter(self._amount_by_currency_id.values()))
+ value = (
+ next(iter(self._amount_by_currency_id.values()))
+ if not self.is_empty_currency
+ else 0
+ )
+ payable = value if value >= 0 else 0
+ return payable
+
+ @property
+ def counterparty_payable_amount_incl_fee(self) -> int:
+ """Get the amount the counterparty must pay."""
+ assert (
+ self.is_single_currency or self.is_empty_currency
+ ), "More than one currency id, cannot get amount."
+ payable = self.counterparty_payable_amount
+ if not self.is_sender_payable_tx_fee and len(self._fee_by_currency_id) == 1:
+ payable += next(iter(self._fee_by_currency_id.values()))
+ return payable
@property
def quantities_by_good_id(self) -> Dict[str, int]:
"""Get the quantities by good id."""
- return self._quantities_by_good_id
+ return copy.copy(self._quantities_by_good_id)
@property
- def is_sender_payable_tx_fee(self) -> bool:
- """Bool indicating whether the tx fee is paid by sender or counterparty."""
- return self._is_sender_payable_tx_fee
+ def good_ids(self) -> List[str]:
+ """Get the (ordered) good ids."""
+ return self._good_ids
+
+ @property
+ def sender_supplied_quantities(self) -> List[int]:
+ """Get the (ordered) quantities supplied by the sender."""
+ return self._sender_supplied_quantities
+
+ @property
+ def counterparty_supplied_quantities(self) -> List[int]:
+ """Get the (ordered) quantities supplied by the counterparty."""
+ return self._counterparty_supplied_quantities
@property
def nonce(self) -> str:
@@ -534,28 +663,117 @@ def nonce(self) -> str:
@property
def has_fee(self) -> bool:
"""Check if fee is set."""
- return self._fee_by_currency_id is not None
+ return self.fee_by_currency_id != {}
@property
def fee(self) -> int:
"""Get the fee."""
- assert self._fee_by_currency_id is not None, "fee_by_currency_id not set."
+ assert self.has_fee, "fee_by_currency_id not set."
assert (
- len(self._fee_by_currency_id) == 1
+ len(self.fee_by_currency_id) == 1
), "More than one currency id, cannot get fee."
return next(iter(self._fee_by_currency_id.values()))
+ @property
+ def sender_fee(self) -> int:
+ """Get the sender fee."""
+ value = self.fee if self.is_sender_payable_tx_fee else 0
+ return value
+
+ @property
+ def counterparty_fee(self) -> int:
+ """Get the counterparty fee."""
+ value = 0 if self.is_sender_payable_tx_fee else self.fee
+ return value
+
@property
def fee_by_currency_id(self) -> Dict[str, int]:
"""Get fee by currency."""
- assert self._fee_by_currency_id is not None, "fee_by_currency_id not set."
- return self._fee_by_currency_id
+ return copy.copy(self._fee_by_currency_id)
@property
def kwargs(self) -> Dict[str, Any]:
"""Get the kwargs."""
return self._kwargs
+ def _get_lists(self) -> Tuple[List[str], List[int], List[int]]:
+ ordered = collections.OrderedDict(sorted(self.quantities_by_good_id.items()))
+ good_ids = [] # type: List[str]
+ sender_supplied_quantities = [] # type: List[int]
+ counterparty_supplied_quantities = [] # type: List[int]
+ for good_id, quantity in ordered.items():
+ good_ids.append(good_id)
+ if quantity >= 0:
+ sender_supplied_quantities.append(quantity)
+ counterparty_supplied_quantities.append(0)
+ else:
+ sender_supplied_quantities.append(0)
+ counterparty_supplied_quantities.append(-quantity)
+ return good_ids, sender_supplied_quantities, counterparty_supplied_quantities
+
+ @staticmethod
+ def get_hash(
+ ledger_id: str,
+ sender_address: str,
+ counterparty_address: str,
+ good_ids: List[str],
+ sender_supplied_quantities: List[int],
+ counterparty_supplied_quantities: List[int],
+ sender_payable_amount: int,
+ counterparty_payable_amount: int,
+ nonce: str,
+ ) -> str:
+ """
+ Generate a hash from transaction information.
+
+ :param sender_addr: the sender address
+ :param counterparty_addr: the counterparty address
+ :param good_ids: the list of good ids
+ :param sender_supplied_quantities: the quantities supplied by the sender (must all be positive)
+ :param counterparty_supplied_quantities: the quantities supplied by the counterparty (must all be positive)
+ :param sender_payable_amount: the amount payable by the sender
+ :param counterparty_payable_amount: the amount payable by the counterparty
+ :param tx_nonce: the nonce of the transaction
+ :return: the hash
+ """
+ if len(good_ids) == 0:
+ aggregate_hash = LedgerApis.get_hash(ledger_id, b"")
+ else:
+ aggregate_hash = LedgerApis.get_hash(
+ ledger_id,
+ b"".join(
+ [
+ good_ids[0].encode("utf-8"),
+ sender_supplied_quantities[0].to_bytes(32, "big"),
+ counterparty_supplied_quantities[0].to_bytes(32, "big"),
+ ]
+ ),
+ )
+ for idx, good_id in enumerate(good_ids):
+ if idx == 0:
+ continue
+ aggregate_hash = LedgerApis.get_hash(
+ ledger_id,
+ b"".join(
+ [
+ aggregate_hash.encode("utf-8"),
+ good_id.encode("utf-8"),
+ sender_supplied_quantities[idx].to_bytes(32, "big"),
+ counterparty_supplied_quantities[idx].to_bytes(32, "big"),
+ ]
+ ),
+ )
+
+ m_list = [] # type: List[bytes]
+ m_list.append(sender_address.encode("utf-8"))
+ m_list.append(counterparty_address.encode("utf-8"))
+ m_list.append(aggregate_hash.encode("utf-8"))
+ m_list.append(sender_payable_amount.to_bytes(32, "big"))
+ m_list.append(counterparty_payable_amount.to_bytes(32, "big"))
+ m_list.append(nonce.encode("utf-8"))
+ digest = LedgerApis.get_hash(ledger_id, b"".join(m_list))
+ return digest
+
@staticmethod
def encode(terms_protobuf_object, terms_object: "Terms") -> None:
"""
diff --git a/aea/launcher.py b/aea/launcher.py
index dc36c86897..0f7901fdde 100644
--- a/aea/launcher.py
+++ b/aea/launcher.py
@@ -105,7 +105,7 @@ def stop_event_thread():
agent.start()
except KeyboardInterrupt: # pragma: nocover
logger.debug("_run_agent: keyboard interrupt")
- except BaseException as e:
+ except BaseException as e: # pragma: nocover
logger.exception("exception in _run_agent")
exc = AEAException(f"Raised {type(e)}({e})")
exc.__traceback__ = e.__traceback__
diff --git a/aea/multiplexer.py b/aea/multiplexer.py
index 071cf4a109..e305929c77 100644
--- a/aea/multiplexer.py
+++ b/aea/multiplexer.py
@@ -25,7 +25,7 @@
from typing import Collection, Dict, List, Optional, Sequence, Tuple, cast
from aea.configurations.base import PublicId
-from aea.connections.base import Connection, ConnectionStatus
+from aea.connections.base import Connection, ConnectionStates
from aea.helpers.async_friendly_queue import AsyncFriendlyQueue
from aea.helpers.async_utils import ThreadedAsyncRunner, cancel_and_wait
from aea.helpers.logging import WithLogger
@@ -40,6 +40,19 @@
from aea.protocols.base import Message
+# TODO refactoring: this should be an enum
+# but beware of backward-compatibility.
+
+
+class ConnectionStatus:
+ """The connection status class."""
+
+ def __init__(self):
+ """Initialize the connection status."""
+ self.is_connected = False # type: bool
+ self.is_connecting = False # type: bool
+
+
class AsyncMultiplexer(WithLogger):
"""This class can handle multiple connections at once."""
@@ -158,7 +171,7 @@ def connections(self) -> Tuple[Connection, ...]:
@property
def is_connected(self) -> bool:
"""Check whether the multiplexer is processing envelopes."""
- return all(c.connection_status.is_connected for c in self._connections)
+ return all(c.is_connected for c in self._connections)
@property
def default_routing(self) -> Dict[PublicId, PublicId]:
@@ -235,7 +248,7 @@ async def _stop(self) -> None:
for connection in [
c
for c in self.connections
- if c.connection_status.is_connected or c.connection_status.is_connecting
+ if c.state in (ConnectionStates.connecting, ConnectionStates.connected)
]:
await connection.disconnect()
self.logger.debug("Multiplexer stopped.")
@@ -268,7 +281,7 @@ async def _connect_one(self, connection_id: PublicId) -> None:
"""
connection = self._id_to_connection[connection_id]
self.logger.debug("Processing connection {}".format(connection.connection_id))
- if connection.connection_status.is_connected:
+ if connection.is_connected:
self.logger.debug(
"Connection {} already established.".format(connection.connection_id)
)
@@ -303,7 +316,7 @@ async def _disconnect_one(self, connection_id: PublicId) -> None:
"""
connection = self._id_to_connection[connection_id]
self.logger.debug("Processing connection {}".format(connection.connection_id))
- if not connection.connection_status.is_connected:
+ if not connection.is_connected:
self.logger.debug(
"Connection {} already disconnected.".format(connection.connection_id)
)
@@ -365,7 +378,7 @@ async def _receiving_loop(self) -> None:
# reinstantiate receiving task, but only if the connection is still up.
connection = task_to_connection.pop(task)
- if connection.connection_status.is_connected:
+ if connection.is_connected:
new_task = asyncio.ensure_future(connection.receive())
task_to_connection[new_task] = connection
@@ -711,34 +724,43 @@ def put(self, envelope: Envelope) -> None:
envelope.context,
)
)
- assert isinstance(
- envelope.message, Message
- ), "Only Message type allowed in envelope message field when putting into outbox."
+ if not isinstance(envelope.message, Message):
+ raise ValueError(
+ "Only Message type allowed in envelope message field when putting into outbox."
+ )
+ message = cast(Message, envelope.message)
+ if not message.has_counterparty:
+ raise ValueError("Provided message has message.counterparty not set.")
+ if not message.has_sender:
+ raise ValueError("Provided message has message.sender not set.")
self._multiplexer.put(envelope)
def put_message(
self,
message: Message,
- sender: Optional[Address] = None,
context: Optional[EnvelopeContext] = None,
+ sender: Optional[str] = None,
) -> None:
"""
Put a message in the outbox.
This constructs an envelope with the input arguments.
- :param sender: the sender of the envelope (optional field only necessary when the non-default address is used for sending).
- :param message: the message.
+ "sender" is a deprecated kwarg and will be removed in the next version
+
+ :param message: the message
:param context: the envelope context
:return: None
"""
- assert isinstance(message, Message), "Provided message not of type Message."
- assert (
- message.counterparty
- ), "Provided message has message.counterparty not set."
+ if not isinstance(message, Message):
+ raise ValueError("Provided message not of type Message.")
+ if not message.has_counterparty:
+ raise ValueError("Provided message has message.counterparty not set.")
+ if not message.has_sender and sender is None:
+ raise ValueError("Provided message has message.sender not set.")
envelope = Envelope(
to=message.counterparty,
- sender=sender or self._default_address,
+ sender=sender or message.sender, # TODO: remove "sender"
protocol_id=message.protocol_id,
message=message,
context=context,
diff --git a/aea/protocols/base.py b/aea/protocols/base.py
index 52c42b6596..dcd602293a 100644
--- a/aea/protocols/base.py
+++ b/aea/protocols/base.py
@@ -65,6 +65,8 @@ def __init__(self, body: Optional[Dict] = None, **kwargs):
:param body: the dictionary of values to hold.
:param kwargs: any additional value to add to the body. It will overwrite the body values.
"""
+ self._to = None # type: Optional[Address]
+ self._sender = None # type: Optional[Address]
self._counterparty = None # type: Optional[Address]
self._body = copy(body) if body else {} # type: Dict[str, Any]
self._body.update(kwargs)
@@ -74,6 +76,49 @@ def __init__(self, body: Optional[Dict] = None, **kwargs):
except Exception as e: # pylint: disable=broad-except
logger.error(e)
+ @property
+ def has_sender(self) -> bool:
+ """Check if it has a sender."""
+ return self._sender is not None
+
+ @property
+ def sender(self) -> Address:
+ """
+ Get the sender of the message in Address form.
+
+ :return the address
+ """
+ assert self._sender is not None, "Sender must not be None."
+ return self._sender
+
+ @sender.setter
+ def sender(self, sender: Address) -> None:
+ """Set the sender of the message."""
+ # assert self._sender is None, "Sender already set."
+ self._sender = sender
+
+ @property
+ def has_to(self) -> bool:
+ """Check if it has a sender."""
+ return self._to is not None
+
+ @property
+ def to(self) -> Address:
+ """Get address of receiver."""
+ assert self._to is not None, "To must not be None."
+ return self._to
+
+ @to.setter
+ def to(self, to: Address) -> None:
+ """Set address of receiver."""
+ assert self._to is None, "To already set."
+ self._to = to
+
+ @property
+ def has_counterparty(self) -> bool:
+ """Check if the counterparty is set."""
+ return self._counterparty is not None
+
@property
def counterparty(self) -> Address:
"""
@@ -293,14 +338,16 @@ class Protocol(Component):
It includes a serializer to encode/decode a message.
"""
- def __init__(self, configuration: ProtocolConfig, message_class: Type[Message]):
+ def __init__(
+ self, configuration: ProtocolConfig, message_class: Type[Message], **kwargs
+ ):
"""
Initialize the protocol manager.
:param configuration: the protocol configurations.
- :param serializer: the serializer.
+ :param message_class: the message class.
"""
- super().__init__(configuration)
+ super().__init__(configuration, **kwargs)
self._message_class = message_class
@@ -310,7 +357,7 @@ def serializer(self) -> Type[Serializer]:
return self._message_class.serializer
@classmethod
- def from_dir(cls, directory: str) -> "Protocol":
+ def from_dir(cls, directory: str, **kwargs) -> "Protocol":
"""
Load the protocol from a directory.
@@ -322,10 +369,10 @@ def from_dir(cls, directory: str) -> "Protocol":
ComponentConfiguration.load(ComponentType.PROTOCOL, Path(directory)),
)
configuration.directory = Path(directory)
- return Protocol.from_config(configuration)
+ return Protocol.from_config(configuration, **kwargs)
@classmethod
- def from_config(cls, configuration: ProtocolConfig) -> "Protocol":
+ def from_config(cls, configuration: ProtocolConfig, **kwargs) -> "Protocol":
"""
Load the protocol from configuration.
@@ -366,4 +413,4 @@ def from_config(cls, configuration: ProtocolConfig) -> "Protocol":
serialize_class = serializer_classes[0][1]
message_class.serializer = serialize_class
- return Protocol(configuration, message_class)
+ return Protocol(configuration, message_class, **kwargs)
diff --git a/examples/protocol_specification_ex/default.yaml b/aea/protocols/default/README.md
similarity index 68%
rename from examples/protocol_specification_ex/default.yaml
rename to aea/protocols/default/README.md
index 72347ae5a4..1a4e445a58 100644
--- a/examples/protocol_specification_ex/default.yaml
+++ b/aea/protocols/default/README.md
@@ -1,7 +1,26 @@
+# Default Protocol
+
+**Name:** default
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: A protocol for exchanging any bytes message.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for two agents exchanging any bytes messages.
+
+## Specification
+
+```yaml
---
name: default
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for exchanging any bytes message.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -33,3 +52,6 @@ termination: [bytes, error]
roles: {agent}
end_states: [successful, failed]
...
+```
+
+## Links
diff --git a/aea/protocols/default/dialogues.py b/aea/protocols/default/dialogues.py
index e833fdd5e3..402304c5f3 100644
--- a/aea/protocols/default/dialogues.py
+++ b/aea/protocols/default/dialogues.py
@@ -126,7 +126,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> DefaultDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of default dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/aea/protocols/default/message.py b/aea/protocols/default/message.py
index 5f4fd1b0d7..4bba6f7706 100644
--- a/aea/protocols/default/message.py
+++ b/aea/protocols/default/message.py
@@ -35,7 +35,7 @@
class DefaultMessage(Message):
"""A protocol for exchanging any bytes message."""
- protocol_id = ProtocolId("fetchai", "default", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/default:0.4.0")
ErrorCode = CustomErrorCode
diff --git a/aea/protocols/default/protocol.yaml b/aea/protocols/default/protocol.yaml
index 15c9d68f6b..fcfa1bd6b4 100644
--- a/aea/protocols/default/protocol.yaml
+++ b/aea/protocols/default/protocol.yaml
@@ -1,16 +1,17 @@
name: default
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for exchanging any bytes message.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmfMJ6iNNLWJLqHwjvypw5pyjWXwjDH9rnrrhQizLxDYKZ
__init__.py: QmPMtKUrzVJp594VqNuapJzCesWLQ6Awjqv2ufG3wKNRmH
custom_types.py: QmRcgwDdTxkSHyfF9eoMtsb5P5GJDm4oyLq5W6ZBko1MFU
default.proto: QmNzMUvXkBm5bbitR5Yi49ADiwNn1FhCvXqSKKoqAPZyXv
default_pb2.py: QmSRFi1s3jcqnPuk4yopJeNuC6o58RL7dvEdt85uns3B3N
- dialogues.py: QmP2K2GZedU4o9khkdeB3LCGxxZek7TiT8jJnmcvWAh11j
- message.py: QmapJFvDxeyrM7c5yGwxH1caREkJwaJ6MGmD71FrjUfLZR
+ dialogues.py: QmS3gaDAaoTD9s3YLGvXVxv9RV864TNN8Q87xQ5CALkMBm
+ message.py: QmbC95LcUY1pwbWtgx9no88Tuh8j2TfNQfvU9x4DjACmBR
serialization.py: QmRnajc9BNCftjGkYTKCP9LnD3rq197jM3Re1GDVJTHh2y
fingerprint_ignore_patterns: []
dependencies:
diff --git a/aea/protocols/generator/base.py b/aea/protocols/generator/base.py
index e3e784d40b..3e87db8eb8 100644
--- a/aea/protocols/generator/base.py
+++ b/aea/protocols/generator/base.py
@@ -95,14 +95,14 @@ def __init__(
self,
path_to_protocol_specification: str,
output_path: str = ".",
- path_to_protocol_package: Optional[str] = None,
+ dotted_path_to_protocol_package: Optional[str] = None,
) -> None:
"""
Instantiate a protocol generator.
:param path_to_protocol_specification: path to protocol specification file
:param output_path: the path to the location in which the protocol module is to be generated.
- :param path_to_protocol_package: the path to the protocol package
+ :param dotted_path_to_protocol_package: the path to the protocol package
:return: None
"""
@@ -128,9 +128,9 @@ def __init__(
self.path_to_generated_protocol_package = os.path.join(
output_path, self.protocol_specification.name
)
- self.path_to_protocol_package = (
- path_to_protocol_package + self.protocol_specification.name
- if path_to_protocol_package is not None
+ self.dotted_path_to_protocol_package = (
+ dotted_path_to_protocol_package + self.protocol_specification.name
+ if dotted_path_to_protocol_package is not None
else "{}.{}.protocols.{}".format(
PATH_TO_PACKAGES,
self.protocol_specification.author,
@@ -211,7 +211,7 @@ def _import_from_custom_types_module(self) -> str:
else:
for custom_class in self.spec.all_custom_types:
import_str += "from {}.custom_types import {} as Custom{}\n".format(
- self.path_to_protocol_package, custom_class, custom_class,
+ self.dotted_path_to_protocol_package, custom_class, custom_class,
)
import_str = import_str[:-1]
return import_str
@@ -628,10 +628,13 @@ def _message_class_str(self) -> str:
)
# Class attributes
- cls_str += self.indent + 'protocol_id = ProtocolId("{}", "{}", "{}")\n'.format(
- self.protocol_specification.author,
- self.protocol_specification.name,
- self.protocol_specification.version,
+ cls_str += (
+ self.indent
+ + 'protocol_id = ProtocolId.from_str("{}/{}:{}")\n'.format(
+ self.protocol_specification.author,
+ self.protocol_specification.name,
+ self.protocol_specification.version,
+ )
)
for custom_type in self.spec.all_custom_types:
cls_str += "\n"
@@ -989,7 +992,8 @@ def _dialogue_class_str(self) -> str:
cls_str += self.indent + "from aea.mail.base import Address\n"
cls_str += self.indent + "from aea.protocols.base import Message\n\n"
cls_str += self.indent + "from {}.message import {}Message\n".format(
- self.path_to_protocol_package, self.protocol_specification_in_camel_case,
+ self.dotted_path_to_protocol_package,
+ self.protocol_specification_in_camel_case,
)
# Class Header
@@ -1163,7 +1167,9 @@ def _dialogue_class_str(self) -> str:
)
self._change_indent(1)
cls_str += self.indent + '"""\n'
- cls_str += self.indent + "Create an instance of {} dialogue.\n\n"
+ cls_str += self.indent + "Create an instance of {} dialogue.\n\n".format(
+ self.protocol_specification.name
+ )
cls_str += (
self.indent + ":param dialogue_label: the identifier of the dialogue\n"
)
@@ -1203,9 +1209,6 @@ def _custom_types_module_str(self) -> str:
# Module docstring
cls_str += '"""This module contains class representations corresponding to every custom type in the protocol specification."""\n'
- if len(self.spec.all_custom_types) == 0:
- return cls_str
-
# class code per custom type
for custom_type in self.spec.all_custom_types:
cls_str += self.indent + "\n\nclass {}:\n".format(custom_type)
@@ -1240,7 +1243,7 @@ def _custom_types_module_str(self) -> str:
)
cls_str += (
self.indent
- + "The protocol buffer object in the {}_protobuf_object argument must be matched with the instance of this class in the '{}_object' argument.\n\n".format(
+ + "The protocol buffer object in the {}_protobuf_object argument is matched with the instance of this class in the '{}_object' argument.\n\n".format(
_camel_case_to_snake_case(custom_type),
_camel_case_to_snake_case(custom_type),
)
@@ -1277,7 +1280,7 @@ def _custom_types_module_str(self) -> str:
)
cls_str += (
self.indent
- + "A new instance of this class must be created that matches the protocol buffer object in the '{}_protobuf_object' argument.\n\n".format(
+ + "A new instance of this class is created that matches the protocol buffer object in the '{}_protobuf_object' argument.\n\n".format(
_camel_case_to_snake_case(custom_type)
)
)
@@ -1529,17 +1532,18 @@ def _serialization_class_str(self) -> str:
cls_str += MESSAGE_IMPORT + "\n"
cls_str += SERIALIZER_IMPORT + "\n\n"
cls_str += self.indent + "from {} import (\n {}_pb2,\n)\n".format(
- self.path_to_protocol_package, self.protocol_specification.name,
+ self.dotted_path_to_protocol_package, self.protocol_specification.name,
)
for custom_type in self.spec.all_custom_types:
cls_str += (
self.indent
+ "from {}.custom_types import (\n {},\n)\n".format(
- self.path_to_protocol_package, custom_type,
+ self.dotted_path_to_protocol_package, custom_type,
)
)
cls_str += self.indent + "from {}.message import (\n {}Message,\n)\n".format(
- self.path_to_protocol_package, self.protocol_specification_in_camel_case,
+ self.dotted_path_to_protocol_package,
+ self.protocol_specification_in_camel_case,
)
# Class Header
@@ -1921,14 +1925,12 @@ def _init_str(self) -> str:
init_str += '"""This module contains the support resources for the {} protocol."""\n\n'.format(
self.protocol_specification.name
)
- init_str += "from packages.{}.protocols.{}.message import {}Message\n".format(
- self.protocol_specification.author,
- self.protocol_specification.name,
+ init_str += "from {}.message import {}Message\n".format(
+ self.dotted_path_to_protocol_package,
self.protocol_specification_in_camel_case,
)
- init_str += "from packages.{}.protocols.{}.serialization import {}Serializer\n\n".format(
- self.protocol_specification.author,
- self.protocol_specification.name,
+ init_str += "from {}.serialization import {}Serializer\n".format(
+ self.dotted_path_to_protocol_package,
self.protocol_specification_in_camel_case,
)
init_str += "{}Message.serializer = {}Serializer\n".format(
diff --git a/aea/protocols/generator/common.py b/aea/protocols/generator/common.py
index 4fb683b28b..ba03d82894 100644
--- a/aea/protocols/generator/common.py
+++ b/aea/protocols/generator/common.py
@@ -36,6 +36,13 @@
"pt:union",
"pt:optional",
]
+PYTHON_COMPOSITIONAL_TYPES = [
+ "FrozenSet",
+ "Tuple",
+ "Dict",
+ "Union",
+ "Optional",
+]
MESSAGE_IMPORT = "from aea.protocols.base import Message"
SERIALIZER_IMPORT = "from aea.protocols.base import Serializer"
@@ -77,6 +84,55 @@ def _camel_case_to_snake_case(text: str) -> str:
return re.sub(r"(? int:
+ """
+ Give the index of the matching close bracket for the opening bracket at 'index_of_open_bracket' in the input 'text'.
+
+ :param text: the text containing the brackets.
+ :param index_of_open_bracket: the index of the opening bracket.
+
+ :return: the index of the matching closing bracket (if any).
+ :raises SyntaxError if there are no matching closing bracket.
+ """
+ if text[index_of_open_bracket] != "[":
+ raise SyntaxError(
+ "Index {} in 'text' is not an open bracket '['. It is {}".format(
+ index_of_open_bracket, text[index_of_open_bracket],
+ )
+ )
+
+ open_bracket_stack = []
+ for index in range(index_of_open_bracket, len(text)):
+ if text[index] == "[":
+ open_bracket_stack.append(text[index])
+ elif text[index] == "]":
+ open_bracket_stack.pop()
+ if not open_bracket_stack:
+ return index
+ raise SyntaxError(
+ "No matching closing bracket ']' for the opening bracket '[' at {} "
+ + str(index_of_open_bracket)
+ )
+
+
+def _has_matched_brackets(text: str) -> bool:
+ """
+ Evaluate whether every opening bracket '[' in the 'text' has a matching closing bracket ']'.
+
+ :param text: the text.
+ :return: Boolean result, and associated message.
+ """
+ open_bracket_stack = []
+ for index, _ in enumerate(text):
+ if text[index] == "[":
+ open_bracket_stack.append(index)
+ elif text[index] == "]":
+ if len(open_bracket_stack) == 0:
+ return False
+ open_bracket_stack.pop()
+ return len(open_bracket_stack) == 0
+
+
def _get_sub_types_of_compositional_types(compositional_type: str) -> Tuple[str, ...]:
"""
Extract the sub-types of compositional types.
@@ -87,82 +143,66 @@ def _get_sub_types_of_compositional_types(compositional_type: str) -> Tuple[str,
:return: tuple containing all extracted sub-types.
"""
sub_types_list = list()
- if compositional_type.startswith("Optional") or compositional_type.startswith(
- "pt:optional"
+ for valid_compositional_type in (
+ SPECIFICATION_COMPOSITIONAL_TYPES + PYTHON_COMPOSITIONAL_TYPES
):
- sub_type1 = compositional_type[
- compositional_type.index("[") + 1 : compositional_type.rindex("]")
- ].strip()
- sub_types_list.append(sub_type1)
- if (
- compositional_type.startswith("FrozenSet")
- or compositional_type.startswith("pt:set")
- or compositional_type.startswith("pt:list")
- ):
- sub_type1 = compositional_type[
- compositional_type.index("[") + 1 : compositional_type.rindex("]")
- ].strip()
- sub_types_list.append(sub_type1)
- if compositional_type.startswith("Tuple"):
- sub_type1 = compositional_type[
- compositional_type.index("[") + 1 : compositional_type.rindex("]")
- ].strip()
- sub_type1 = sub_type1[:-5]
- sub_types_list.append(sub_type1)
- if compositional_type.startswith("Dict") or compositional_type.startswith(
- "pt:dict"
- ):
- sub_type1 = compositional_type[
- compositional_type.index("[") + 1 : compositional_type.index(",")
- ].strip()
- sub_type2 = compositional_type[
- compositional_type.index(",") + 1 : compositional_type.rindex("]")
- ].strip()
- sub_types_list.extend([sub_type1, sub_type2])
- if compositional_type.startswith("Union") or compositional_type.startswith(
- "pt:union"
- ):
- inside_union = compositional_type[
- compositional_type.index("[") + 1 : compositional_type.rindex("]")
- ].strip()
- while inside_union != "":
- if inside_union.startswith("Dict") or inside_union.startswith("pt:dict"):
- sub_type = inside_union[: inside_union.index("]") + 1].strip()
- rest_of_inside_union = inside_union[
- inside_union.index("]") + 1 :
- ].strip()
- if rest_of_inside_union.find(",") == -1:
- # it is the last sub-type
- inside_union = rest_of_inside_union.strip()
- else:
- # it is not the last sub-type
- inside_union = rest_of_inside_union[
- rest_of_inside_union.index(",") + 1 :
+ if compositional_type.startswith(valid_compositional_type):
+ inside_string = compositional_type[
+ compositional_type.index("[") + 1 : compositional_type.rindex("]")
+ ].strip()
+ while inside_string != "":
+ do_not_add = False
+ if inside_string.find(",") == -1: # No comma; this is the last sub-type
+ provisional_sub_type = inside_string.strip()
+ if (
+ provisional_sub_type == "..."
+ ): # The sub-string is ... used for Tuple, e.g. Tuple[int, ...]
+ do_not_add = True
+ else:
+ sub_type = provisional_sub_type
+ inside_string = ""
+ else: # There is a comma; this MAY not be the last sub-type
+ sub_string_until_comma = inside_string[
+ : inside_string.index(",")
].strip()
- elif inside_union.startswith("Tuple"):
- sub_type = inside_union[: inside_union.index("]") + 1].strip()
- rest_of_inside_union = inside_union[
- inside_union.index("]") + 1 :
- ].strip()
- if rest_of_inside_union.find(",") == -1:
- # it is the last sub-type
- inside_union = rest_of_inside_union.strip()
- else:
- # it is not the last sub-type
- inside_union = rest_of_inside_union[
- rest_of_inside_union.index(",") + 1 :
- ].strip()
- else:
- if inside_union.find(",") == -1:
- # it is the last sub-type
- sub_type = inside_union.strip()
- inside_union = ""
- else:
- # it is not the last sub-type
- sub_type = inside_union[: inside_union.index(",")].strip()
- inside_union = inside_union[inside_union.index(",") + 1 :].strip()
- sub_types_list.append(sub_type)
- return tuple(sub_types_list)
+ if (
+ sub_string_until_comma.find("[") == -1
+ ): # No open brackets; this is a primitive type and NOT the last sub-type
+ sub_type = sub_string_until_comma
+ inside_string = inside_string[
+ inside_string.index(",") + 1 :
+ ].strip()
+ else: # There is an open bracket'['; this is a compositional type
+ try:
+ closing_bracket_index = _match_brackets(
+ inside_string, inside_string.index("[")
+ )
+ except SyntaxError:
+ raise SyntaxError(
+ "Bad formatting. No matching close bracket ']' for the open bracket at {}".format(
+ inside_string[
+ : inside_string.index("[") + 1
+ ].strip()
+ )
+ )
+ sub_type = inside_string[: closing_bracket_index + 1].strip()
+ the_rest_of_inside_string = inside_string[
+ closing_bracket_index + 1 :
+ ].strip()
+ if (
+ the_rest_of_inside_string.find(",") == -1
+ ): # No comma; this is the last sub-type
+ inside_string = the_rest_of_inside_string.strip()
+ else: # There is a comma; this is not the last sub-type
+ inside_string = the_rest_of_inside_string[
+ the_rest_of_inside_string.index(",") + 1 :
+ ].strip()
+ if not do_not_add:
+ sub_types_list.append(sub_type)
+ return tuple(sub_types_list)
+ raise SyntaxError(
+ "{} is not a valid compositional type.".format(compositional_type)
+ )
def _union_sub_type_to_protobuf_variable_name(
diff --git a/aea/protocols/generator/validate.py b/aea/protocols/generator/validate.py
index 93742dca24..073fb18d94 100644
--- a/aea/protocols/generator/validate.py
+++ b/aea/protocols/generator/validate.py
@@ -26,6 +26,7 @@
SPECIFICATION_COMPOSITIONAL_TYPES,
SPECIFICATION_PRIMITIVE_TYPES,
_get_sub_types_of_compositional_types,
+ _has_matched_brackets,
)
# The following names are reserved for standard message fields and cannot be
@@ -36,7 +37,7 @@
PERFORMATIVE_REGEX_PATTERN = "^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$"
CONTENT_NAME_REGEX_PATTERN = "^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$"
-CT_CONTENT_REGEX_PATTERN = "^ct:([A-Z]+[a-z]*)+$" # or maybe "ct:(?:[A-Z][a-z]+)+" or # "^ct:[A-Z][a-zA-Z0-9]*$"
+CT_CONTENT_TYPE_REGEX_PATTERN = "^ct:([A-Z]+[a-z]*)+$" # or maybe "ct:(?:[A-Z][a-z]+)+" or # "^ct:[A-Z][a-zA-Z0-9]*$"
ROLE_REGEX_PATTERN = "^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$"
END_STATE_REGEX_PATTERN = "^[a-zA-Z0-9]+$|^[a-zA-Z0-9]+(_?[a-zA-Z0-9]+)+$"
@@ -69,29 +70,62 @@ def _is_valid_regex(regex_pattern: str, text: str) -> bool:
def _has_brackets(content_type: str) -> bool:
+ """
+ Evaluate whether a compositional content type in a protocol specification is valid has corresponding brackets.
+
+ :param content_type: an 'set' content type.
+ :return: Boolean result
+ """
for compositional_type in SPECIFICATION_COMPOSITIONAL_TYPES:
if content_type.startswith(compositional_type):
content_type = content_type[len(compositional_type) :]
- return content_type[0] == "[" and content_type[len(content_type) - 1] == "]"
+ if len(content_type) < 2:
+ return False
+ else:
+ return (
+ content_type[0] == "["
+ and content_type[len(content_type) - 1] == "]"
+ )
raise SyntaxError("Content type must be a compositional type!")
def _is_valid_ct(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'ct' content type in a protocol specification is valid.
+
+ :param content_type: a 'ct' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
- return _is_valid_regex(CT_CONTENT_REGEX_PATTERN, content_type)
+ return _is_valid_regex(CT_CONTENT_TYPE_REGEX_PATTERN, content_type)
def _is_valid_pt(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'pt' content type in a protocol specification is valid.
+
+ :param content_type: a 'pt' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
return content_type in SPECIFICATION_PRIMITIVE_TYPES
def _is_valid_set(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'set' content type in a protocol specification is valid.
+
+ :param content_type: a 'set' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
if not content_type.startswith("pt:set"):
return False
+ if not _has_matched_brackets(content_type):
+ return False
+
if not _has_brackets(content_type):
return False
@@ -104,11 +138,20 @@ def _is_valid_set(content_type: str) -> bool:
def _is_valid_list(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'list' content type in a protocol specification is valid.
+
+ :param content_type: a 'list' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
if not content_type.startswith("pt:list"):
return False
+ if not _has_matched_brackets(content_type):
+ return False
+
if not _has_brackets(content_type):
return False
@@ -121,11 +164,20 @@ def _is_valid_list(content_type: str) -> bool:
def _is_valid_dict(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'dict' content type in a protocol specification is valid.
+
+ :param content_type: a 'dict' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
if not content_type.startswith("pt:dict"):
return False
+ if not _has_matched_brackets(content_type):
+ return False
+
if not _has_brackets(content_type):
return False
@@ -139,15 +191,33 @@ def _is_valid_dict(content_type: str) -> bool:
def _is_valid_union(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a 'union' content type in a protocol specification is valid.
+
+ :param content_type: an 'union' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
if not content_type.startswith("pt:union"):
return False
+ if not _has_matched_brackets(content_type):
+ return False
+
if not _has_brackets(content_type):
return False
sub_types = _get_sub_types_of_compositional_types(content_type)
+ # check there are at least two subtypes in the union
+ if len(sub_types) < 2:
+ return False
+
+ # check there are no duplicate subtypes in the union
+ sub_types_set = set(sub_types)
+ if len(sub_types) != len(sub_types_set):
+ return False
+
for sub_type in sub_types:
if not (
_is_valid_ct(sub_type)
@@ -162,11 +232,20 @@ def _is_valid_union(content_type: str) -> bool:
def _is_valid_optional(content_type: str) -> bool:
+ """
+ Evaluate whether the format of an 'optional' content type in a protocol specification is valid.
+
+ :param content_type: an 'optional' content type.
+ :return: Boolean result
+ """
content_type = content_type.strip()
if not content_type.startswith("pt:optional"):
return False
+ if not _has_matched_brackets(content_type):
+ return False
+
if not _has_brackets(content_type):
return False
@@ -186,6 +265,12 @@ def _is_valid_optional(content_type: str) -> bool:
def _is_valid_content_type_format(content_type: str) -> bool:
+ """
+ Evaluate whether the format of a content type in a protocol specification is valid.
+
+ :param content_type: a content type.
+ :return: Boolean result
+ """
return (
_is_valid_ct(content_type)
or _is_valid_pt(content_type)
@@ -232,7 +317,7 @@ def _validate_content_name(content_name: str, performative: str) -> Tuple[bool,
:return: Boolean result, and associated message.
"""
- if not _is_valid_regex(PERFORMATIVE_REGEX_PATTERN, content_name):
+ if not _is_valid_regex(CONTENT_NAME_REGEX_PATTERN, content_name):
return (
False,
"Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
@@ -296,6 +381,14 @@ def _validate_speech_acts_section(
custom_types_set = set()
performatives_set = set()
+ if len(protocol_specification.speech_acts.read_all()) == 0:
+ return (
+ False,
+ "Speech-acts cannot be empty!",
+ None,
+ None,
+ )
+
for (
performative,
speech_act_content_config,
@@ -397,6 +490,12 @@ def _validate_initiation(
:return: Boolean result, and associated message.
"""
+ if len(initiation) == 0 or initiation is None:
+ return (
+ False,
+ "At least one initial performative for this dialogue must be specified.",
+ )
+
for performative in initiation:
if performative not in performatives_set:
return (
@@ -454,6 +553,12 @@ def _validate_termination(
:return: Boolean result, and associated message.
"""
+ if len(termination) == 0 or termination is None:
+ return (
+ False,
+ "At least one terminal performative for this dialogue must be specified.",
+ )
+
for performative in termination:
if performative not in performatives_set:
return (
@@ -473,6 +578,14 @@ def _validate_roles(roles: Set[str]) -> Tuple[bool, str]:
:param roles: Set of roles of a dialogue.
:return: Boolean result, and associated message.
"""
+ if not 1 <= len(roles) <= 2:
+ return (
+ False,
+ "There must be either 1 or 2 roles defined in this dialogue. Found {}".format(
+ len(roles)
+ ),
+ )
+
for role in roles:
if not _is_valid_regex(ROLE_REGEX_PATTERN, role):
return (
diff --git a/aea/protocols/scaffold/message.py b/aea/protocols/scaffold/message.py
index b620d8a8e3..ecb37e9f06 100644
--- a/aea/protocols/scaffold/message.py
+++ b/aea/protocols/scaffold/message.py
@@ -21,7 +21,7 @@
from enum import Enum
-from aea.configurations.base import PublicId
+from aea.configurations.base import ProtocolId
from aea.protocols.base import Message
from aea.protocols.scaffold.serialization import MyScaffoldSerializer
@@ -29,7 +29,7 @@
class MyScaffoldMessage(Message):
"""The scaffold message class."""
- protocol_id = PublicId("fetchai", "scaffold", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/scaffold:0.1.0")
serializer = MyScaffoldSerializer
class Performative(Enum):
diff --git a/aea/protocols/scaffold/protocol.yaml b/aea/protocols/scaffold/protocol.yaml
index 4f365f7a80..bd236f8c6b 100644
--- a/aea/protocols/scaffold/protocol.yaml
+++ b/aea/protocols/scaffold/protocol.yaml
@@ -6,7 +6,7 @@ license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmedGZfo1UqT6UJoRkHys9kmquia9BQcK17y2touwSENDU
- message.py: QmR9baHynNkr4mLvEdzJQpiNzPEfsPm2gzYa1H9jT3TxTQ
+ message.py: QmQBEHSHTH19n3dBr2WKAW9vqjytCTHCB2avExs9wMGPxw
serialization.py: QmNjyzqmoYnCxiLoBeZjXMhYkQzJpbDSFm7A9wytyRa2Xn
fingerprint_ignore_patterns: []
dependencies: {}
diff --git a/examples/protocol_specification_ex/signing.yaml b/aea/protocols/signing/README.md
similarity index 82%
rename from examples/protocol_specification_ex/signing.yaml
rename to aea/protocols/signing/README.md
index 438c1f13c3..7875b0552f 100644
--- a/examples/protocol_specification_ex/signing.yaml
+++ b/aea/protocols/signing/README.md
@@ -1,7 +1,26 @@
+# Signing Protocol
+
+**Name:** signing
+
+**Author**: fetchai
+
+**Version**: 0.2.0
+
+**Short Description**: A protocol for communication between skills and decision maker.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for communication between a skill and a decision maker.
+
+## Specification
+
+```yaml
---
name: signing
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for communication between skills and decision maker.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -59,3 +78,6 @@ termination: [signed_transaction, signed_message, error]
roles: {skill, decision_maker}
end_states: [successful, failed]
...
+```
+
+## Links
diff --git a/aea/protocols/signing/dialogues.py b/aea/protocols/signing/dialogues.py
index c5a0f52016..40bde9680b 100644
--- a/aea/protocols/signing/dialogues.py
+++ b/aea/protocols/signing/dialogues.py
@@ -145,7 +145,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> SigningDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of signing dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/aea/protocols/signing/message.py b/aea/protocols/signing/message.py
index 559a0dc56b..5150a27d5a 100644
--- a/aea/protocols/signing/message.py
+++ b/aea/protocols/signing/message.py
@@ -42,7 +42,7 @@
class SigningMessage(Message):
"""A protocol for communication between skills and decision maker."""
- protocol_id = ProtocolId("fetchai", "signing", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/signing:0.2.0")
ErrorCode = CustomErrorCode
diff --git a/aea/protocols/signing/protocol.yaml b/aea/protocols/signing/protocol.yaml
index 1265c0fc90..15ce140129 100644
--- a/aea/protocols/signing/protocol.yaml
+++ b/aea/protocols/signing/protocol.yaml
@@ -1,14 +1,15 @@
name: signing
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for communication between skills and decision maker.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmSYzpWru7bswJGW1DBtuLgYUrbF5MXZ3KkDwnwxfB2yYk
__init__.py: QmcCL3TTdvd8wxYKzf2d3cgKEtY9RzLjPCn4hex4wmb6h6
custom_types.py: Qmc7sAyCQbAaVs5dZf9hFkTrB2BG8VAioWzbyKBAybrQ1J
- dialogues.py: QmdQz9MJNXSaXxWPfmGKgbfYHittDap9BbBW7WZZifQ8RF
- message.py: QmeyubdB5wTu6S1PMVCb5WDweNNvYi6GUDnoTSXY9qBDjG
+ dialogues.py: QmaoSYB1baPGuVa64H7xtMkNjTybQguPbFBSzBwLsTVT8x
+ message.py: QmRXGbAy2oYWecxXmdxfQW9dNspinwhxVuSK4RqR4WZTvE
serialization.py: QmPUWHUpQ9pst42s1naM5nTbsxxko5HxPi2gB86FQnMGnL
signing.proto: QmT59ZVsevFoJ51uiuAzCgHGowmwfo3bLAKRSgXV1qyXFo
signing_pb2.py: QmPZFneKLZUipxAZ3usnmUm1br6VvetzvBpid6GU4JjR39
diff --git a/examples/protocol_specification_ex/state_update.yaml b/aea/protocols/state_update/README.md
similarity index 67%
rename from examples/protocol_specification_ex/state_update.yaml
rename to aea/protocols/state_update/README.md
index 2f88d847e2..4caf292f7f 100644
--- a/examples/protocol_specification_ex/state_update.yaml
+++ b/aea/protocols/state_update/README.md
@@ -1,7 +1,26 @@
+# State Update Protocol
+
+**Name:** state_update
+
+**Author**: fetchai
+
+**Version**: 0.2.0
+
+**Short Description**: A protocol for state updates to the decision maker state.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for updating the state of a decision maker.
+
+## Specification
+
+```yaml
---
name: state_update
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for state updates to the decision maker state.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -16,10 +35,6 @@ speech_acts:
quantities_by_good_id: pt:dict[pt:str, pt:int]
...
---
-ct:StateUpdate: |
- bytes state_update = 1;
-...
----
initiation: [initialize]
reply:
initialize: [apply]
@@ -28,3 +43,6 @@ termination: [apply]
roles: {skill, decision_maker}
end_states: [successful]
...
+```
+
+## Links
diff --git a/aea/protocols/state_update/dialogues.py b/aea/protocols/state_update/dialogues.py
index 48292d5a56..ad8d959dad 100644
--- a/aea/protocols/state_update/dialogues.py
+++ b/aea/protocols/state_update/dialogues.py
@@ -122,7 +122,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> StateUpdateDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of state_update dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/aea/protocols/state_update/message.py b/aea/protocols/state_update/message.py
index 1c247f0d57..cd11ba9a48 100644
--- a/aea/protocols/state_update/message.py
+++ b/aea/protocols/state_update/message.py
@@ -34,7 +34,7 @@
class StateUpdateMessage(Message):
"""A protocol for state updates to the decision maker state."""
- protocol_id = ProtocolId("fetchai", "state_update", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/state_update:0.2.0")
class Performative(Enum):
"""Performatives for the state_update protocol."""
diff --git a/aea/protocols/state_update/protocol.yaml b/aea/protocols/state_update/protocol.yaml
index 4be82dbb24..34dd71115a 100644
--- a/aea/protocols/state_update/protocol.yaml
+++ b/aea/protocols/state_update/protocol.yaml
@@ -1,13 +1,14 @@
name: state_update
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for state updates to the decision maker state.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmQ2sQno2YXxkHx9copJsb9wwhwfryz3oJmnXnarP4Pcsb
__init__.py: Qma2opyN54gwTpkVV1E14jjeMmMfoqgE6XMM9LsvGuTdkm
- dialogues.py: QmPk4bgw1o5Uon2cpnRH6Y5WzJKUDcvMgFfDt2qQVUdJex
- message.py: QmPHEGuepwmrLsNhe8JVLKcdPmNGaziDfdeqshirRJhAKY
+ dialogues.py: QmUo2zDoSShCy6dY6HWR1i2yb7rfBSSyHK1xpAp1WmMpLT
+ message.py: QmZo4tX6fjyJmcRezrVC8EQ882iV1y3sm2RyWK6ByhTUdY
serialization.py: QmQDdbN4pgfdL1LUhV4J7xMUhdqUJ2Tamz7Nheca3yGw2G
state_update.proto: QmdmEUSa7PDxJ98ZmGE7bLFPmUJv8refgbkHPejw6uDdwD
state_update_pb2.py: QmQr5KXhapRv9AnfQe7Xbr5bBqYWp9DEMLjxX8UWmK75Z4
diff --git a/aea/registries/base.py b/aea/registries/base.py
index a316a6455a..673daa188f 100644
--- a/aea/registries/base.py
+++ b/aea/registries/base.py
@@ -18,6 +18,8 @@
# ------------------------------------------------------------------------------
"""This module contains registries."""
+
+import copy
import logging
from abc import ABC, abstractmethod
from typing import Dict, Generic, List, Optional, Set, Tuple, TypeVar, cast
@@ -48,12 +50,15 @@ def __init__(self):
super().__init__(logger)
@abstractmethod
- def register(self, item_id: ItemId, item: Item) -> None:
+ def register(
+ self, item_id: ItemId, item: Item, is_dynamically_added: bool = False
+ ) -> None:
"""
Register an item.
:param item_id: the public id of the item.
:param item: the item.
+ :param is_dynamicall_added: whether or not the item is dynamicall added.
:return: None
:raises: ValueError if an item is already registered with that item id.
"""
@@ -116,13 +121,17 @@ def __init__(self) -> None:
self._registered_keys: Set[ComponentId] = set()
def register(
- self, component_id: ComponentId, component: Component
+ self,
+ component_id: ComponentId,
+ component: Component,
+ is_dynamically_added: bool = False,
) -> None: # pylint: disable=arguments-differ
"""
Register a component.
:param component_id: the id of the component.
:param component: the component object.
+ :param is_dynamicall_added: whether or not the item is dynamicall added.
"""
if component_id in self._registered_keys:
raise ValueError(
@@ -227,8 +236,7 @@ def teardown(self) -> None:
:return: None
"""
- self._components_by_type = {}
- self._registered_keys = set()
+ pass
class ComponentRegistry(
@@ -244,13 +252,20 @@ def __init__(self) -> None:
"""
super().__init__()
self._items = {} # type: Dict[SkillId, Dict[str, SkillComponentType]]
+ self._dynamically_added = {} # type: Dict[SkillId, Set[str]]
- def register(self, item_id: Tuple[SkillId, str], item: SkillComponentType) -> None:
+ def register(
+ self,
+ item_id: Tuple[SkillId, str],
+ item: SkillComponentType,
+ is_dynamically_added: bool = False,
+ ) -> None:
"""
Register a item.
:param item_id: a pair (skill id, item name).
:param item: the item to register.
+ :param is_dynamicall_added: whether or not the item is dynamicall added.
:return: None
:raises: ValueError if an item is already registered with that item id.
"""
@@ -263,11 +278,25 @@ def register(self, item_id: Tuple[SkillId, str], item: SkillComponentType) -> No
)
)
self._items.setdefault(skill_id, {})[item_name] = item
+ if is_dynamically_added:
+ self._dynamically_added.setdefault(skill_id, set()).add(item_name)
def unregister(self, item_id: Tuple[SkillId, str]) -> None:
"""
Unregister a item.
+ :param item_id: a pair (skill id, item name).
+ :return: None
+ :raises: ValueError if no item registered with that item id.
+ """
+ self._unregister_from_main_index(item_id)
+
+ def _unregister_from_main_index(
+ self, item_id: Tuple[SkillId, str]
+ ) -> SkillComponentType:
+ """
+ Unregister a item.
+
:param item_id: a pair (skill id, item name).
:return: None
:raises: ValueError if no item registered with that item id.
@@ -280,11 +309,17 @@ def unregister(self, item_id: Tuple[SkillId, str]) -> None:
"No item registered with component id '{}'".format(item_id)
)
self.logger.debug("Unregistering item with id {}".format(item_id))
- name_to_item.pop(item_name)
-
+ item = name_to_item.pop(item_name)
if len(name_to_item) == 0:
self._items.pop(skill_id, None)
+ items = self._dynamically_added.get(skill_id, None)
+ if items is not None:
+ items.remove(item_name)
+ if len(items) == 0:
+ self._dynamically_added.pop(skill_id, None)
+ return item
+
def fetch(self, item_id: Tuple[SkillId, str]) -> Optional[SkillComponentType]:
"""
Fetch an item.
@@ -313,6 +348,7 @@ def unregister_by_skill(self, skill_id: SkillId) -> None:
"No component of skill {} present in the registry.".format(skill_id)
)
self._items.pop(skill_id, None)
+ self._dynamically_added.pop(skill_id, None)
def setup(self) -> None:
"""
@@ -351,6 +387,10 @@ def teardown(self) -> None:
skill_id, type(item).__name__, str(e)
)
)
+ _dynamically_added = copy.deepcopy(self._dynamically_added)
+ for skill_id, items_names in _dynamically_added.items():
+ for item_name in items_names:
+ self.unregister((skill_id, item_name))
class HandlerRegistry(ComponentRegistry[Handler]):
@@ -367,16 +407,22 @@ def __init__(self) -> None:
{}
) # type: Dict[ProtocolId, Dict[SkillId, Handler]]
- def register(self, item_id: Tuple[SkillId, str], item: Handler) -> None:
+ def register(
+ self,
+ item_id: Tuple[SkillId, str],
+ item: Handler,
+ is_dynamically_added: bool = False,
+ ) -> None:
"""
Register a handler.
:param item_id: the item id.
:param item: the handler.
+ :param is_dynamicall_added: whether or not the item is dynamicall added.
:return: None
:raises ValueError: if the protocol is None, or an item with pair (skill_id, protocol_id_ already exists.
"""
- super().register(item_id, item)
+ super().register(item_id, item, is_dynamically_added=is_dynamically_added)
skill_id = item_id[0]
@@ -411,21 +457,8 @@ def unregister(self, item_id: Tuple[SkillId, str]) -> None:
:return: None
:raises: ValueError if no item is registered with that item id.
"""
- # remove from main index
skill_id = item_id[0]
- item_name = item_id[1]
- name_to_item = self._items.get(skill_id, {})
- if item_name not in name_to_item:
- raise ValueError(
- "No item registered with component id '{}'".format(item_id)
- )
- self.logger.debug( # pylint: disable=no-member
- "Unregistering item with id {}".format(item_id)
- )
- handler = name_to_item.pop(item_name)
-
- if len(name_to_item) == 0:
- self._items.pop(skill_id, None)
+ handler = super()._unregister_from_main_index(item_id)
# remove from index by protocol and skill
protocol_id = cast(ProtocolId, handler.SUPPORTED_PROTOCOL)
@@ -443,6 +476,9 @@ def unregister_by_skill(self, skill_id: SkillId) -> None:
raise ValueError(
"No component of skill {} present in the registry.".format(skill_id)
)
+
+ self._dynamically_added.pop(skill_id, None)
+
handlers = self._items.pop(skill_id).values()
# unregister from the protocol-skill index
diff --git a/aea/registries/filter.py b/aea/registries/filter.py
index 562dde7ff8..d362568890 100644
--- a/aea/registries/filter.py
+++ b/aea/registries/filter.py
@@ -19,6 +19,7 @@
"""This module contains registries."""
+import copy
import logging
import queue
from queue import Queue
@@ -100,8 +101,9 @@ def handle_internal_messages(self) -> None:
:return: None
"""
self._handle_decision_maker_out_queue()
- # get new behaviours from the agent skills
+ # get new behaviours and handlers from the agent skills
self._handle_new_behaviours()
+ self._handle_new_handlers()
def _handle_decision_maker_out_queue(self) -> None:
"""Process descision maker's messages."""
@@ -136,12 +138,29 @@ def _handle_new_behaviours(self) -> None:
self.resources.behaviour_registry.register(
(skill.skill_context.skill_id, new_behaviour.name),
new_behaviour,
+ is_dynamically_added=True,
)
except ValueError as e:
logger.warning(
"Error when trying to add a new behaviour: {}".format(str(e))
)
+ def _handle_new_handlers(self) -> None:
+ """Register new handlers added to skills."""
+ for skill in self.resources.get_all_skills():
+ while not skill.skill_context.new_handlers.empty():
+ new_handler = skill.skill_context.new_handlers.get()
+ try:
+ self.resources.handler_registry.register(
+ (skill.skill_context.skill_id, new_handler.name),
+ new_handler,
+ is_dynamically_added=True,
+ )
+ except ValueError as e:
+ logger.warning(
+ "Error when trying to add a new handler: {}".format(str(e))
+ )
+
def _handle_signing_message(self, signing_message: SigningMessage):
"""Handle transaction message from the Decision Maker."""
skill_callback_ids = [
@@ -150,15 +169,22 @@ def _handle_signing_message(self, signing_message: SigningMessage):
]
for skill_id in skill_callback_ids:
handler = self.resources.handler_registry.fetch_by_protocol_and_skill(
- signing_message.protocol_id, skill_id
+ signing_message.protocol_id,
+ skill_id, # TODO: route based on component id specified on message
)
if handler is not None:
logger.debug(
"Calling handler {} of skill {}".format(type(handler), skill_id)
)
- signing_message.counterparty = "decision_maker" # TODO: temp fix
- signing_message.is_incoming = True
- handler.handle(cast(Message, signing_message))
+ # TODO: remove next three lines
+ copy_signing_message = copy.copy(
+ signing_message
+ ) # we do a shallow copy as we only need the message object to be copied; not its referenced objects
+ copy_signing_message.counterparty = signing_message.sender
+ copy_signing_message.sender = signing_message.sender
+ # copy_signing_message.to = signing_message.to
+ copy_signing_message.is_incoming = True
+ handler.handle(cast(Message, copy_signing_message))
else:
logger.warning(
"No internal handler fetched for skill_id={}".format(skill_id)
diff --git a/aea/registries/resources.py b/aea/registries/resources.py
index 9ba282fb5a..d136a7678c 100644
--- a/aea/registries/resources.py
+++ b/aea/registries/resources.py
@@ -19,7 +19,7 @@
"""This module contains the resources class."""
from contextlib import suppress
-from typing import Dict, List, Optional, cast
+from typing import List, Optional, cast
from aea.components.base import Component
from aea.configurations.base import (
@@ -244,28 +244,6 @@ def add_skill(self, skill: Skill) -> None:
if skill.models is not None:
for model in skill.models.values():
self._model_registry.register((skill.public_id, model.name), model)
- self.inject_contracts(skill)
-
- def inject_contracts(self, skill: Skill) -> None:
- """
- Inject contracts into a skill context.
-
- :param skill: a skill
- :return: None
- """
- if skill.config.contracts is not None:
- # check all contracts are present
- contracts = {} # type: Dict[str, Contract]
- for contract_id in skill.config.contracts:
- contract = self._component_registry.fetch(
- ComponentId(ComponentType.CONTRACT, contract_id)
- )
- if contract is None:
- raise ValueError(
- "Missing contract for contract id {}".format(contract_id)
- )
- contracts[contract_id.name] = cast(Contract, contract)
- skill.inject_contracts(contracts)
def get_skill(self, skill_id: SkillId) -> Optional[Skill]:
"""
diff --git a/aea/runtime.py b/aea/runtime.py
index dadf82f494..895decc423 100644
--- a/aea/runtime.py
+++ b/aea/runtime.py
@@ -25,7 +25,7 @@
from asyncio.events import AbstractEventLoop
from contextlib import suppress
from enum import Enum
-from typing import Optional, TYPE_CHECKING
+from typing import Optional, TYPE_CHECKING, cast
from aea.agent_loop import AsyncState
from aea.helpers.async_utils import ensure_loop
@@ -41,12 +41,11 @@
class RuntimeStates(Enum):
"""Runtime states."""
- initial = "not_started"
starting = "starting"
- started = "started"
- loop_stopped = "loop_stopped"
+ running = "running"
stopping = "stopping"
stopped = "stopped"
+ error = "error"
class BaseRuntime(ABC):
@@ -66,17 +65,33 @@ def __init__(
self._loop = ensure_loop(
loop
) # TODO: decide who constructs loop: agent, runtime, multiplexer.
- self._state: AsyncState = AsyncState(RuntimeStates.initial)
+ self._state: AsyncState = AsyncState(RuntimeStates.stopped, RuntimeStates)
+ self._state.add_callback(self._log_runtime_state)
+ self._was_started = False
+
+ def _log_runtime_state(self, state) -> None:
+ logger.debug(f"[{self._agent.name}]: Runtime state changed to {state}.")
def start(self) -> None:
"""Start agent using runtime."""
- if self._state.get() is RuntimeStates.started: # pragma: nocover
- logger.error("[{}]: Runtime already started".format(self._agent.name))
+ if self._state.get() is not RuntimeStates.stopped:
+ logger.error(
+ "[{}]: Runtime is not stopped. Please stop it and start after.".format(
+ self._agent.name
+ )
+ )
return
+ self._was_started = True
self._start()
def stop(self) -> None:
"""Stop agent and runtime."""
+ if self._state.get() in (RuntimeStates.stopped, RuntimeStates.stopping):
+ logger.error(
+ "[{}]: Runtime is already stopped or stopping.".format(self._agent.name)
+ )
+ return
+
logger.debug("[{}]: Runtime stopping...".format(self._agent.name))
self._teardown()
self._stop()
@@ -100,12 +115,12 @@ def _stop(self) -> None: # pragma: nocover
@property
def is_running(self) -> bool:
"""Get running state of the runtime."""
- return self._state.get() == RuntimeStates.started
+ return self._state.get() == RuntimeStates.running
@property
def is_stopped(self) -> bool:
"""Get stopped state of the runtime."""
- return self._state.get() in [RuntimeStates.stopped, RuntimeStates.initial]
+ return self._state.get() in [RuntimeStates.stopped]
def set_loop(self, loop: AbstractEventLoop) -> None:
"""
@@ -116,6 +131,15 @@ def set_loop(self, loop: AbstractEventLoop) -> None:
self._loop = loop
asyncio.set_event_loop(self._loop)
+ @property
+ def state(self) -> RuntimeStates:
+ """
+ Get runtime state.
+
+ :return: RuntimeStates
+ """
+ return cast(RuntimeStates, self._state.get())
+
class AsyncRuntime(BaseRuntime):
"""Asynchronous runtime: uses asyncio loop for multiplexer and async agent main loop."""
@@ -156,28 +180,24 @@ def _start(self) -> None:
"""
self.set_loop(self._loop)
- self._state.set(RuntimeStates.started)
-
logger.debug(f"Start runtime event loop {self._loop}: {id(self._loop)}")
self._task = self._loop.create_task(self.run_runtime())
try:
self._loop.run_until_complete(self._task)
- self._state.set(RuntimeStates.loop_stopped)
logger.debug("Runtime loop stopped!")
except Exception:
logger.exception("Exception raised during runtime processing")
+ self._state.set(RuntimeStates.error)
raise
finally:
self._stopping_task = None
async def run_runtime(self) -> None:
"""Run agent and starts multiplexer."""
+ self._state.set(RuntimeStates.starting)
try:
- self._state.set(RuntimeStates.starting)
- self._agent.setup_multiplexer()
await self._start_multiplexer()
- self._agent.start_setup()
await self._start_agent_loop()
except Exception:
logger.exception("AsyncRuntime exception during run:")
@@ -192,12 +212,14 @@ async def _multiplexer_disconnect(self) -> None:
async def _start_multiplexer(self) -> None:
"""Call multiplexer connect asynchronous way."""
+ self._agent.setup_multiplexer()
await AsyncMultiplexer.connect(self._agent.multiplexer)
async def _start_agent_loop(self) -> None:
"""Start agent main loop asynchronous way."""
logger.debug("[{}]: Runtime started".format(self._agent.name))
- self._state.set(RuntimeStates.started)
+ self._agent.start_setup()
+ self._state.set(RuntimeStates.running)
await self._agent.main_loop.run_loop()
async def _stop_runtime(self) -> None:
@@ -214,7 +236,10 @@ async def _stop_runtime(self) -> None:
async with self._async_stop_lock:
- if self._state.get() is not RuntimeStates.started:
+ if self._state.get() in (
+ RuntimeStates.stopped,
+ RuntimeStates.stopping,
+ ): # pragma: nocover
return
self._state.set(RuntimeStates.stopping)
@@ -276,10 +301,15 @@ def _start_agent_loop(self) -> None:
"""Start aget's main loop."""
logger.debug("[{}]: Runtime started".format(self._agent.name))
try:
- self._state.set(RuntimeStates.started)
+ self._state.set(RuntimeStates.running)
self._agent.main_loop.start()
- finally:
- self._state.set(RuntimeStates.loop_stopped)
+ logger.debug("[{}]: Runtime stopped".format(self._agent.name))
+ except KeyboardInterrupt:
+ raise
+ except BaseException: # pragma: nocover
+ logger.exception("Runtime exception during stop:")
+ self._state.set(RuntimeStates.error)
+ raise
def _stop(self) -> None:
"""Implement runtime stop function here."""
diff --git a/aea/skills/base.py b/aea/skills/base.py
index ae11fa8703..0fc2c26004 100644
--- a/aea/skills/base.py
+++ b/aea/skills/base.py
@@ -25,11 +25,11 @@
import queue
import re
from abc import ABC, abstractmethod
-from logging import Logger, LoggerAdapter
+from logging import Logger
from pathlib import Path
from queue import Queue
from types import SimpleNamespace
-from typing import Any, Dict, Optional, Sequence, Set, Tuple, Type, Union, cast
+from typing import Any, Dict, Optional, Sequence, Set, Tuple, Type, cast
from aea.components.base import Component
from aea.configurations.base import (
@@ -40,18 +40,16 @@
SkillComponentConfiguration,
SkillConfig,
)
-from aea.connections.base import ConnectionStatus
from aea.context.base import AgentContext
-from aea.contracts.base import Contract
from aea.exceptions import AEAException
from aea.helpers.base import load_aea_package, load_module
from aea.helpers.logging import AgentLoggerAdapter
from aea.mail.base import Address
-from aea.multiplexer import OutBox
+from aea.multiplexer import ConnectionStatus, OutBox
from aea.protocols.base import Message
from aea.skills.tasks import TaskManager
-logger = logging.getLogger(__name__)
+_default_logger = logging.getLogger(__name__)
class SkillContext:
@@ -74,17 +72,18 @@ def __init__(
self._is_active = True # type: bool
self._new_behaviours_queue = queue.Queue() # type: Queue
- self._logger: Optional[Union[Logger, LoggerAdapter]] = None
+ self._new_handlers_queue = queue.Queue() # type: Queue
+ self._logger: Optional[Logger] = None
@property
- def logger(self) -> Union[Logger, LoggerAdapter]:
+ def logger(self) -> Logger:
"""Get the logger."""
if self._logger is None:
- return logging.getLogger("aea")
+ return _default_logger
return self._logger
@logger.setter
- def logger(self, logger_: Union[Logger, AgentLoggerAdapter]) -> None:
+ def logger(self, logger_: Logger) -> None:
assert self._logger is None, "Logger already set."
self._logger = logger_
@@ -122,14 +121,14 @@ def is_active(self) -> bool:
def is_active(self, value: bool) -> None:
"""Set the status of the skill (active/not active)."""
self._is_active = value
- logger.debug(
+ self.logger.debug(
"New status of skill {}: is_active={}".format(
self.skill_id, self._is_active
)
)
@property
- def new_behaviours(self) -> Queue:
+ def new_behaviours(self) -> "Queue[Behaviour]":
"""
Queue for the new behaviours.
@@ -140,6 +139,18 @@ def new_behaviours(self) -> Queue:
"""
return self._new_behaviours_queue
+ @property
+ def new_handlers(self) -> "Queue[Handler]":
+ """
+ Queue for the new handlers.
+
+ This queue can be used to send messages to the framework
+ to request the registration of a handler.
+
+ :return the queue of new handlers.
+ """
+ return self._new_handlers_queue
+
@property
def agent_addresses(self) -> Dict[str, str]:
"""Get addresses."""
@@ -200,12 +211,6 @@ def behaviours(self) -> SimpleNamespace:
assert self._skill is not None, "Skill not initialized."
return SimpleNamespace(**self._skill.behaviours)
- @property
- def contracts(self) -> SimpleNamespace:
- """Get contracts the skill has access to."""
- assert self._skill is not None, "Skill not initialized."
- return SimpleNamespace(**self._skill.contracts)
-
@property
def namespace(self) -> SimpleNamespace:
"""Get the agent context namespace."""
@@ -242,7 +247,7 @@ def __init__(
self._name = name
self._context = skill_context
if len(kwargs) != 0:
- logger.warning(
+ self.context.logger.warning(
"The kwargs={} passed to {} have not been set!".format(kwargs, name)
)
@@ -381,6 +386,7 @@ def parse_module(
name_to_class = dict(behaviours_classes)
_print_warning_message_for_non_declared_skill_components(
+ skill_context,
set(name_to_class.keys()),
{
behaviour_config.class_name
@@ -392,13 +398,15 @@ def parse_module(
for behaviour_id, behaviour_config in behaviour_configs.items():
behaviour_class_name = cast(str, behaviour_config.class_name)
- logger.debug("Processing behaviour {}".format(behaviour_class_name))
+ skill_context.logger.debug(
+ "Processing behaviour {}".format(behaviour_class_name)
+ )
assert (
behaviour_id.isidentifier()
), "'{}' is not a valid identifier.".format(behaviour_id)
behaviour_class = name_to_class.get(behaviour_class_name, None)
if behaviour_class is None:
- logger.warning(
+ skill_context.logger.warning(
"Behaviour '{}' cannot be found.".format(behaviour_class_name)
)
else:
@@ -462,6 +470,7 @@ def parse_module(
name_to_class = dict(handler_classes)
_print_warning_message_for_non_declared_skill_components(
+ skill_context,
set(name_to_class.keys()),
{handler_config.class_name for handler_config in handler_configs.values()},
"handlers",
@@ -469,13 +478,15 @@ def parse_module(
)
for handler_id, handler_config in handler_configs.items():
handler_class_name = cast(str, handler_config.class_name)
- logger.debug("Processing handler {}".format(handler_class_name))
+ skill_context.logger.debug(
+ "Processing handler {}".format(handler_class_name)
+ )
assert handler_id.isidentifier(), "'{}' is not a valid identifier.".format(
handler_id
)
handler_class = name_to_class.get(handler_class_name, None)
if handler_class is None:
- logger.warning(
+ skill_context.logger.warning(
"Handler '{}' cannot be found.".format(handler_class_name)
)
else:
@@ -534,7 +545,7 @@ def parse_module(
)
for module_path in module_paths:
- logger.debug("Trying to load module {}".format(module_path))
+ skill_context.logger.debug("Trying to load module {}".format(module_path))
module_name = module_path.replace(".py", "")
model_module = load_module(module_name, Path(module_path))
classes = inspect.getmembers(model_module, inspect.isclass)
@@ -555,6 +566,7 @@ def parse_module(
_check_duplicate_classes(models)
name_to_class = dict(models)
_print_warning_message_for_non_declared_skill_components(
+ skill_context,
set(name_to_class.keys()),
{model_config.class_name for model_config in model_configs.values()},
"models",
@@ -562,7 +574,7 @@ def parse_module(
)
for model_id, model_config in model_configs.items():
model_class_name = model_config.class_name
- logger.debug(
+ skill_context.logger.debug(
"Processing model id={}, class={}".format(model_id, model_class_name)
)
assert model_id.isidentifier(), "'{}' is not a valid identifier.".format(
@@ -570,7 +582,9 @@ def parse_module(
)
model = name_to_class.get(model_class_name, None)
if model is None:
- logger.warning("Model '{}' cannot be found.".format(model_class_name))
+ skill_context.logger.warning(
+ "Model '{}' cannot be found.".format(model_class_name)
+ )
else:
model_instance = model(
name=model_id,
@@ -635,19 +649,8 @@ def __init__(
) # type: Dict[str, Behaviour]
self._models = {} if models is None else models # type: Dict[str, Model]
- self._contracts = {} # type: Dict[str, Contract]
-
self._skill_context._skill = self
- @property
- def contracts(self) -> Dict[str, Contract]:
- """Get the contracts associated with the skill."""
- return self._contracts
-
- def inject_contracts(self, contracts: Dict[str, Contract]) -> None:
- """Add the contracts to the skill."""
- self._contracts = contracts
-
@property
def skill_context(self) -> SkillContext:
"""Get the skill context."""
@@ -670,7 +673,7 @@ def models(self) -> Dict[str, Model]:
return self._models
@classmethod
- def from_dir(cls, directory: str, agent_context: AgentContext) -> "Skill":
+ def from_dir(cls, directory: str, agent_context: AgentContext, **kwargs) -> "Skill":
"""
Load the skill from a directory.
@@ -686,7 +689,7 @@ def from_dir(cls, directory: str, agent_context: AgentContext) -> "Skill":
return Skill.from_config(configuration, agent_context)
@property
- def logger(self) -> Union[Logger, LoggerAdapter]:
+ def logger(self) -> Logger:
"""
Get the logger.
@@ -698,11 +701,11 @@ def logger(self) -> Union[Logger, LoggerAdapter]:
@logger.setter
def logger(self, *args) -> None:
"""Set the logger."""
- raise ValueError("Cannot set logger to a skill component..")
+ raise ValueError("Cannot set logger to a skill component.")
@classmethod
def from_config(
- cls, configuration: SkillConfig, agent_context: AgentContext
+ cls, configuration: SkillConfig, agent_context: AgentContext, **kwargs
) -> "Skill":
"""
Load the skill from configuration.
@@ -721,10 +724,10 @@ def from_config(
skill_context = SkillContext()
skill_context.set_agent_context(agent_context)
logger_name = f"aea.packages.{configuration.author}.skills.{configuration.name}"
- logger = AgentLoggerAdapter(
+ _logger = AgentLoggerAdapter(
logging.getLogger(logger_name), agent_context.agent_name
)
- skill_context.logger = logger
+ skill_context.logger = cast(Logger, _logger)
skill = Skill(configuration, skill_context)
@@ -753,11 +756,15 @@ def from_config(
def _print_warning_message_for_non_declared_skill_components(
- classes: Set[str], config_components: Set[str], item_type, skill_path
+ skill_context: SkillContext,
+ classes: Set[str],
+ config_components: Set[str],
+ item_type,
+ skill_path,
):
"""Print a warning message if a skill component is not declared in the config files."""
for class_name in classes.difference(config_components):
- logger.warning(
+ skill_context.logger.warning(
"Class {} of type {} found but not declared in the configuration file {}.".format(
class_name, item_type, skill_path
)
diff --git a/aea/skills/error/handlers.py b/aea/skills/error/handlers.py
index 5905313c37..9ff282306a 100644
--- a/aea/skills/error/handlers.py
+++ b/aea/skills/error/handlers.py
@@ -82,6 +82,7 @@ def send_unsupported_protocol(self, envelope: Envelope) -> None:
},
)
reply.counterparty = envelope.sender
+ reply.sender = self.context.agent_address
self.context.outbox.put_message(message=reply)
def send_decoding_error(self, envelope: Envelope) -> None:
@@ -107,6 +108,7 @@ def send_decoding_error(self, envelope: Envelope) -> None:
error_data={"envelope": encoded_envelope},
)
reply.counterparty = envelope.sender
+ reply.sender = self.context.agent_address
self.context.outbox.put_message(message=reply)
def send_unsupported_skill(self, envelope: Envelope) -> None:
@@ -139,4 +141,5 @@ def send_unsupported_skill(self, envelope: Envelope) -> None:
error_data={"envelope": encoded_envelope},
)
reply.counterparty = envelope.sender
+ reply.sender = self.context.agent_address
self.context.outbox.put_message(message=reply)
diff --git a/aea/skills/error/skill.yaml b/aea/skills/error/skill.yaml
index 9a4882704c..f089e39ade 100644
--- a/aea/skills/error/skill.yaml
+++ b/aea/skills/error/skill.yaml
@@ -1,16 +1,16 @@
name: error
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The error skill implements basic error handling required by all AEAs.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmYm7UaWVmRy2i35MBKZRnBrpWBJswLdEH6EY1QQKXdQES
- handlers.py: QmV1yRiqVZr5fKd6xbDVxtE68kjcWvrH7UEcxKd82jLM68
+ handlers.py: QmTHJ2EFdyRPdDb93po118eqkVMpxxVLZeF4XitLq76yPx
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: []
behaviours: {}
handlers:
diff --git a/aea/skills/scaffold/behaviours.py b/aea/skills/scaffold/behaviours.py
index ecdc1fabc0..1df3678311 100644
--- a/aea/skills/scaffold/behaviours.py
+++ b/aea/skills/scaffold/behaviours.py
@@ -31,7 +31,7 @@ def setup(self) -> None:
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
def act(self) -> None:
"""
@@ -39,7 +39,7 @@ def act(self) -> None:
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
def teardown(self) -> None:
"""
@@ -47,4 +47,4 @@ def teardown(self) -> None:
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
diff --git a/aea/skills/scaffold/handlers.py b/aea/skills/scaffold/handlers.py
index 406c615d4f..1ed480fead 100644
--- a/aea/skills/scaffold/handlers.py
+++ b/aea/skills/scaffold/handlers.py
@@ -37,7 +37,7 @@ def setup(self) -> None:
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
def handle(self, message: Message) -> None:
"""
@@ -46,7 +46,7 @@ def handle(self, message: Message) -> None:
:param message: the message
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
def teardown(self) -> None:
"""
@@ -54,4 +54,4 @@ def teardown(self) -> None:
:return: None
"""
- raise NotImplementedError # pragma: no cover
+ raise NotImplementedError
diff --git a/aea/skills/scaffold/skill.yaml b/aea/skills/scaffold/skill.yaml
index 70320b482e..1f4ac58a33 100644
--- a/aea/skills/scaffold/skill.yaml
+++ b/aea/skills/scaffold/skill.yaml
@@ -6,8 +6,8 @@ license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmNkZAetyctaZCUf6ACxP5onGWsSxu2hjSNoFmJ3ta6Lta
- behaviours.py: QmYa1rczhGTtMJBgCd1QR9uZhhkf45orm7TnGTE5Eizjpy
- handlers.py: QmZYyTENRr6ecnxx1FeBdgjLiBhFLVn9mqarzUtFQmNUFn
+ behaviours.py: QmNgDDAmBzWBeBF7e5gUCny38kdqVVfpvHGaAZVZcMtm9Q
+ handlers.py: QmUFLmnyph4sstd5vxq4Q7up8PVbVMctiiZi8EZMsK1Kj6
my_model.py: QmPaZ6G37Juk63mJj88nParaEp71XyURts8AmmX1axs24V
fingerprint_ignore_patterns: []
contracts: []
diff --git a/aea/skills/tasks.py b/aea/skills/tasks.py
index 50a0e5a15b..7a01b025f4 100644
--- a/aea/skills/tasks.py
+++ b/aea/skills/tasks.py
@@ -27,14 +27,13 @@
from aea.helpers.logging import WithLogger
-logger = logging.getLogger(__name__)
-
-class Task:
+class Task(WithLogger):
"""This class implements an abstract task."""
def __init__(self, **kwargs):
"""Initialize a task."""
+ super().__init__(**kwargs)
self._is_executed = False
# this is where we store the result.
self._result = None
@@ -57,7 +56,7 @@ def __call__(self, *args, **kwargs):
self._result = self.execute(*args, **kwargs)
return self
except Exception as e: # pylint: disable=broad-except
- logger.debug(
+ self.logger.debug(
"Got exception of type {} with message '{}' while executing task.".format(
type(e), str(e)
)
@@ -83,10 +82,9 @@ def result(self) -> Any:
raise ValueError("Task not executed yet.")
return self._result
- @abstractmethod
def setup(self) -> None:
"""
- Implement the behaviour setup.
+ Implement the task setup.
:return: None
"""
@@ -99,10 +97,9 @@ def execute(self, *args, **kwargs) -> None:
:return: None
"""
- @abstractmethod
def teardown(self) -> None:
"""
- Implement the behaviour teardown.
+ Implement the task teardown.
:return: None
"""
@@ -125,7 +122,12 @@ def init_worker() -> None:
class TaskManager(WithLogger):
"""A Task manager."""
- def __init__(self, nb_workers: int = 1, is_lazy_pool_start: bool = True):
+ def __init__(
+ self,
+ nb_workers: int = 1,
+ is_lazy_pool_start: bool = True,
+ logger: Optional[logging.Logger] = None,
+ ):
"""
Initialize the task manager.
@@ -240,7 +242,7 @@ def _start_pool(self) -> None:
:return: None
"""
if self._pool:
- self.logger.debug("Pool was already started!.")
+ self.logger.debug("Pool was already started!")
return
self._pool = Pool(self._nb_workers, initializer=init_worker)
diff --git a/aea/test_tools/click_testing.py b/aea/test_tools/click_testing.py
index 160f7fbb70..bc6d80b50c 100644
--- a/aea/test_tools/click_testing.py
+++ b/aea/test_tools/click_testing.py
@@ -18,7 +18,7 @@
# ------------------------------------------------------------------------------
"""
-This module contains an adaptation of click.testing.CliRunner
+This module contains an adaptation of click.testing.CliRunner.
In particular, it fixes an issue in
CLIRunner.invoke, in the 'finally' clause. More precisely, before reading from
@@ -37,7 +37,7 @@
class CliRunner(ClickCliRunner):
- """Patch of click.testing.CliRunner"""
+ """Patch of click.testing.CliRunner."""
def invoke(
self,
@@ -49,12 +49,12 @@ def invoke(
color=False,
**extra
):
- """Patch click.testing.CliRunner.invoke()."""
+ """Call a cli command with click.testing.CliRunner.invoke."""
exc_info = None
- with self.isolation(input=input, env=env, color=color) as outstreams:
- exception = None
- exit_code = 0
+ exception = None
+ exit_code = 0
+ with self.isolation(input=input, env=env, color=color) as outstreams:
if isinstance(args, string_types):
args = shlex.split(args)
@@ -68,10 +68,10 @@ def invoke(
except SystemExit as e:
exc_info = sys.exc_info()
exit_code = e.code
- if exit_code is None:
+ if exit_code is None: # pragma: nocover
exit_code = 0
- if exit_code != 0:
+ if exit_code != 0: # pragma: nocover
exception = e
if not isinstance(exit_code, int):
diff --git a/aea/test_tools/test_cases.py b/aea/test_tools/test_cases.py
index 075a46a786..4889d8788b 100644
--- a/aea/test_tools/test_cases.py
+++ b/aea/test_tools/test_cases.py
@@ -16,7 +16,6 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""This module contains test case classes based on pytest for AEA end-to-end testing."""
import copy
import logging
@@ -30,6 +29,7 @@
import tempfile
import time
from abc import ABC
+from contextlib import suppress
from filecmp import dircmp
from io import TextIOWrapper
from pathlib import Path
@@ -88,6 +88,7 @@ class BaseAEATestCase(ABC):
agents: Set[str] = set() # the set of created agents
stdout: Dict[int, str] # dict of process.pid: string stdout
stderr: Dict[int, str] # dict of process.pid: string stderr
+ _is_teardown_class_called: bool = False
@classmethod
def set_agent_context(cls, agent_name: str):
@@ -100,18 +101,19 @@ def unset_agent_context(cls):
cls.current_agent_context = ""
@classmethod
- def set_config(cls, dotted_path: str, value: Any, type_: str = "str") -> None:
+ def set_config(cls, dotted_path: str, value: Any, type_: str = "str") -> Result:
"""
Set a config.
+
Run from agent's directory.
:param dotted_path: str dotted path to config param.
:param value: a new value to set.
:param type_: the type
- :return: None
+ :return: Result
"""
- cls.run_cli_command(
+ return cls.run_cli_command(
"config",
"set",
dotted_path,
@@ -128,9 +130,10 @@ def force_set_config(cls, dotted_path: str, value: Any) -> None:
force_set_config(dotted_path, value)
@classmethod
- def disable_aea_logging(cls):
+ def disable_aea_logging(cls) -> None:
"""
Disable AEA logging of specific agent.
+
Run from agent's directory.
:return: None
@@ -143,7 +146,7 @@ def disable_aea_logging(cls):
cls.run_cli_command("config", "set", path, value, cwd=cls._get_cwd())
@classmethod
- def run_cli_command(cls, *args: str, cwd: str = ".") -> None:
+ def run_cli_command(cls, *args: str, cwd: str = ".") -> Result:
"""
Run AEA CLI command.
@@ -151,7 +154,7 @@ def run_cli_command(cls, *args: str, cwd: str = ".") -> None:
:param cwd: the working directory from where to run the command.
:raises AEATestingException: if command fails.
- :return: None
+ :return: Result
"""
with cd(cwd):
result = cls.runner.invoke(
@@ -165,6 +168,7 @@ def run_cli_command(cls, *args: str, cwd: str = ".") -> None:
args, result.exit_code, result.exception
)
)
+ return result
@classmethod
def _run_python_subprocess(cls, *args: str, cwd: str = ".") -> subprocess.Popen:
@@ -199,7 +203,7 @@ def start_subprocess(cls, *args: str, cwd: str = ".") -> subprocess.Popen:
return process
@classmethod
- def start_thread(cls, target: Callable, **kwargs) -> None:
+ def start_thread(cls, target: Callable, **kwargs) -> Thread:
"""
Start python Thread.
@@ -214,6 +218,7 @@ def start_thread(cls, target: Callable, **kwargs) -> None:
thread = Thread(target=target)
thread.start()
cls.threads.append(thread)
+ return thread
@classmethod
def create_agents(cls, *agents_names: str) -> None:
@@ -251,7 +256,7 @@ def difference_to_fetched_agent(cls, public_id: str, agent_name: str) -> List[st
:return: list of files differing in the projects
"""
-
+ # for pydocstyle
def is_allowed_diff_in_agent_config(
path_to_fetched_aea, path_to_manually_created_aea
) -> Tuple[bool, Dict[str, str], Dict[str, str]]:
@@ -281,26 +286,30 @@ def is_allowed_diff_in_agent_config(
path_to_manually_created_aea = os.path.join(cls.t, agent_name)
new_cwd = os.path.join(cls.t, "fetch_dir")
os.mkdir(new_cwd)
- path_to_fetched_aea = os.path.join(new_cwd, agent_name)
+ fetched_agent_name = agent_name
+ path_to_fetched_aea = os.path.join(new_cwd, fetched_agent_name)
registry_tmp_dir = os.path.join(new_cwd, cls.packages_dir_path)
shutil.copytree(str(cls.package_registry_src), str(registry_tmp_dir))
with cd(new_cwd):
- cls.run_cli_command("fetch", "--local", public_id, "--alias", agent_name)
+ cls.run_cli_command(
+ "fetch", "--local", public_id, "--alias", fetched_agent_name
+ )
comp = dircmp(path_to_manually_created_aea, path_to_fetched_aea)
file_diff = comp.diff_files
result, diff1, diff2 = is_allowed_diff_in_agent_config(
path_to_fetched_aea, path_to_manually_created_aea
)
if result:
- file_diff.remove("aea-config.yaml") # won't match!
+ if "aea-config.yaml" in file_diff: # pragma: nocover
+ file_diff.remove("aea-config.yaml") # won't match!
else:
file_diff.append(
"Difference in aea-config.yaml: " + str(diff1) + " vs. " + str(diff2)
)
- try:
+
+ with suppress(OSError, IOError):
shutil.rmtree(new_cwd)
- except (OSError, IOError):
- pass
+
return file_diff
@classmethod
@@ -320,6 +329,7 @@ def delete_agents(cls, *agents_names: str) -> None:
def run_agent(cls, *args: str) -> subprocess.Popen:
"""
Run agent as subprocess.
+
Run from agent's directory.
:param args: CLI args
@@ -337,6 +347,7 @@ def run_agent(cls, *args: str) -> subprocess.Popen:
def run_interaction(cls) -> subprocess.Popen:
"""
Run interaction as subprocess.
+
Run from agent's directory.
:param args: CLI args
@@ -359,6 +370,7 @@ def terminate_agents(
) -> None:
"""
Terminate agent subprocesses.
+
Run from agent's directory.
:param subprocesses: the subprocesses running the agents
@@ -374,9 +386,7 @@ def terminate_agents(
@classmethod
def is_successfully_terminated(cls, *subprocesses: subprocess.Popen):
- """
- Check if all subprocesses terminated successfully
- """
+ """Check if all subprocesses terminated successfully."""
if not subprocesses:
subprocesses = tuple(cls.subprocesses)
@@ -393,52 +403,58 @@ def initialize_aea(cls, author) -> None:
cls.run_cli_command("init", "--local", "--author", author, cwd=cls._get_cwd())
@classmethod
- def add_item(cls, item_type: str, public_id: str, local: bool = True) -> None:
+ def add_item(cls, item_type: str, public_id: str, local: bool = True) -> Result:
"""
Add an item to the agent.
+
Run from agent's directory.
:param item_type: str item type.
:param public_id: public id of the item.
:param local: a flag for local folder add True by default.
- :return: None
+ :return: Result
"""
cli_args = ["add", "--local", item_type, public_id]
- if not local:
+ if not local: # pragma: nocover
cli_args.remove("--local")
- cls.run_cli_command(*cli_args, cwd=cls._get_cwd())
+ return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())
@classmethod
- def scaffold_item(cls, item_type: str, name: str) -> None:
+ def scaffold_item(cls, item_type: str, name: str) -> Result:
"""
Scaffold an item for the agent.
+
Run from agent's directory.
:param item_type: str item type.
:param name: name of the item.
- :return: None
+ :return: Result
"""
- cls.run_cli_command("scaffold", item_type, name, cwd=cls._get_cwd())
+ return cls.run_cli_command("scaffold", item_type, name, cwd=cls._get_cwd())
@classmethod
- def fingerprint_item(cls, item_type: str, public_id: str) -> None:
+ def fingerprint_item(cls, item_type: str, public_id: str) -> Result:
"""
- Scaffold an item for the agent.
+ Fingerprint an item for the agent.
+
Run from agent's directory.
:param item_type: str item type.
:param name: public id of the item.
- :return: None
+ :return: Result
"""
- cls.run_cli_command("fingerprint", item_type, public_id, cwd=cls._get_cwd())
+ return cls.run_cli_command(
+ "fingerprint", item_type, public_id, cwd=cls._get_cwd()
+ )
@classmethod
- def eject_item(cls, item_type: str, public_id: str) -> None:
+ def eject_item(cls, item_type: str, public_id: str) -> Result:
"""
Eject an item in the agent.
+
Run from agent's directory.
:param item_type: str item type.
@@ -447,29 +463,37 @@ def eject_item(cls, item_type: str, public_id: str) -> None:
:return: None
"""
cli_args = ["eject", item_type, public_id]
- cls.run_cli_command(*cli_args, cwd=cls._get_cwd())
+ return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())
@classmethod
- def run_install(cls):
+ def run_install(cls) -> Result:
"""
Execute AEA CLI install command.
+
Run from agent's directory.
- :return: None
+ :return: Result
"""
- cls.run_cli_command("install", cwd=cls._get_cwd())
+ return cls.run_cli_command("install", cwd=cls._get_cwd())
@classmethod
- def generate_private_key(cls, ledger_api_id: str = DEFAULT_LEDGER) -> None:
+ def generate_private_key(
+ cls, ledger_api_id: str = DEFAULT_LEDGER, private_key_file: Optional[str] = None
+ ) -> Result:
"""
Generate AEA private key with CLI command.
+
Run from agent's directory.
:param ledger_api_id: ledger API ID.
+ :param private_key_file: the private key file.
- :return: None
+ :return: Result
"""
- cls.run_cli_command("generate-key", ledger_api_id, cwd=cls._get_cwd())
+ cli_args = ["generate-key", ledger_api_id]
+ if private_key_file is not None:
+ cli_args.append(private_key_file)
+ return cls.run_cli_command(*cli_args, cwd=cls._get_cwd())
@classmethod
def add_private_key(
@@ -477,19 +501,20 @@ def add_private_key(
ledger_api_id: str = DEFAULT_LEDGER,
private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE,
connection: bool = False,
- ) -> None:
+ ) -> Result:
"""
Add private key with CLI command.
+
Run from agent's directory.
:param ledger_api_id: ledger API ID.
:param private_key_filepath: private key filepath.
:param connection: whether or not the private key filepath is for a connection.
- :return: None
+ :return: Result
"""
if connection:
- cls.run_cli_command(
+ return cls.run_cli_command(
"add-key",
ledger_api_id,
private_key_filepath,
@@ -497,7 +522,7 @@ def add_private_key(
cwd=cls._get_cwd(),
)
else:
- cls.run_cli_command(
+ return cls.run_cli_command(
"add-key", ledger_api_id, private_key_filepath, cwd=cls._get_cwd()
)
@@ -514,21 +539,22 @@ def replace_private_key_in_file(
:return: None
:raises: exception if file does not exist
"""
- with cd(cls._get_cwd()):
+ with cd(cls._get_cwd()): # pragma: nocover
with open(private_key_filepath, "wt") as f:
f.write(private_key)
@classmethod
- def generate_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> None:
+ def generate_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> Result:
"""
Generate wealth with CLI command.
+
Run from agent's directory.
:param ledger_api_id: ledger API ID.
- :return: None
+ :return: Result
"""
- cls.run_cli_command(
+ return cls.run_cli_command(
"generate-wealth", ledger_api_id, "--sync", cwd=cls._get_cwd()
)
@@ -536,6 +562,7 @@ def generate_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> None:
def get_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> str:
"""
Get wealth with CLI command.
+
Run from agent's directory.
:param ledger_api_id: ledger API ID.
@@ -547,15 +574,16 @@ def get_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> str:
return str(cls.last_cli_runner_result.stdout_bytes, "utf-8")
@classmethod
- def replace_file_content(cls, src: Path, dest: Path) -> None:
+ def replace_file_content(cls, src: Path, dest: Path) -> None: # pragma: nocover
"""
Replace the content of the source file to the dest file.
+
:param src: the source file.
:param dest: the destination file.
:return: None
"""
assert src.is_file() and dest.is_file(), "Source or destination is not a file."
- src.write_text(dest.read_text())
+ dest.write_text(src.read_text())
@classmethod
def change_directory(cls, path: Path) -> None:
@@ -586,12 +614,12 @@ def _join_threads(cls):
cls.threads = []
@classmethod
- def _read_out(cls, process: subprocess.Popen):
+ def _read_out(cls, process: subprocess.Popen): # pragma: nocover # runs in thread!
for line in TextIOWrapper(process.stdout, encoding="utf-8"):
cls.stdout[process.pid] += line
@classmethod
- def _read_err(cls, process: subprocess.Popen):
+ def _read_err(cls, process: subprocess.Popen): # pragma: nocover # runs in thread!
if process.stderr is not None:
for line in TextIOWrapper(process.stderr, encoding="utf-8"):
cls.stderr[process.pid] += line
@@ -646,6 +674,7 @@ def missing_from_output(
) -> List[str]:
"""
Check if strings are present in process output.
+
Read process stdout in thread and terminate when all strings are present
or timeout expired.
@@ -719,11 +748,11 @@ def setup_class(cls):
@classmethod
def teardown_class(cls):
"""Teardown the test."""
+ cls.change_directory(cls.old_cwd)
cls.terminate_agents(*cls.subprocesses)
cls._terminate_subprocesses()
cls._join_threads()
cls.unset_agent_context()
- cls.change_directory(cls.old_cwd)
cls.last_cli_runner_result = None
cls.packages_dir_path = Path("packages")
cls.use_packages_dir = True
@@ -732,17 +761,16 @@ def teardown_class(cls):
cls.package_registry_src = Path(ROOT_DIR, "packages")
cls.stdout = {}
cls.stderr = {}
- try:
+
+ with suppress(OSError, IOError):
shutil.rmtree(cls.t)
- except (OSError, IOError):
- pass
+
+ cls._is_teardown_class_called = True
@pytest.mark.integration
class UseOef:
- """
- Inherit from this class to launch an OEF node.
- """
+ """Inherit from this class to launch an OEF node."""
@pytest.fixture(autouse=True)
def _start_oef_node(self, network_node):
@@ -759,7 +787,7 @@ class AEATestCaseEmpty(BaseAEATestCase):
@classmethod
def setup_class(cls):
"""Set up the test class."""
- BaseAEATestCase.setup_class()
+ super(AEATestCaseEmpty, cls).setup_class()
cls.agent_name = "agent-" + "".join(random.choices(string.ascii_lowercase, k=5))
cls.create_agents(cls.agent_name)
cls.set_agent_context(cls.agent_name)
@@ -771,12 +799,12 @@ class AEATestCaseMany(BaseAEATestCase):
@classmethod
def setup_class(cls):
"""Set up the test class."""
- BaseAEATestCase.setup_class()
+ super(AEATestCaseMany, cls).setup_class()
@classmethod
def teardown_class(cls):
"""Teardown the test class."""
- BaseAEATestCase.teardown_class()
+ super(AEATestCaseMany, cls).teardown_class()
class AEATestCase(BaseAEATestCase):
@@ -809,8 +837,8 @@ def setup_class(cls):
# this will create a temporary directory and move into it
# TODO: decide whether to keep optionally: BaseAEATestCase.packages_dir_path = cls.packages_dir_path
- BaseAEATestCase.use_packages_dir = False
- BaseAEATestCase.setup_class()
+ cls.use_packages_dir = False
+ super(AEATestCase, cls).setup_class()
# copy the content of the agent into the temporary directory
shutil.copytree(str(cls.path_to_aea), str(cls.t / cls.agent_name))
@@ -822,4 +850,4 @@ def teardown_class(cls):
cls.path_to_aea = Path(".")
# TODO: decide whether to keep optionally: cls.packages_dir_path = Path("..", "packages")
cls.agent_configuration = None
- BaseAEATestCase.teardown_class()
+ super(AEATestCase, cls).teardown_class()
diff --git a/benchmark/framework/fake_connection.py b/benchmark/framework/fake_connection.py
index 8c152101a7..5ba0618ffe 100644
--- a/benchmark/framework/fake_connection.py
+++ b/benchmark/framework/fake_connection.py
@@ -20,7 +20,7 @@
import asyncio
from typing import Optional
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import Envelope
@@ -37,7 +37,7 @@ def __init__(self, envelope: Envelope, num: int, *args, **kwargs):
Connection.__init__(self, *args, **kwargs)
self.num = num
self.envelope = envelope
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
async def connect(self) -> None:
"""
@@ -52,7 +52,7 @@ async def disconnect(self) -> None:
:return: None
"""
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: Envelope) -> None:
"""
diff --git a/deploy-image/docker-env.sh b/deploy-image/docker-env.sh
index 649a323822..832182a1c4 100755
--- a/deploy-image/docker-env.sh
+++ b/deploy-image/docker-env.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Swap the following lines if you want to work with 'latest'
-DOCKER_IMAGE_TAG=aea-deploy:0.5.2
+DOCKER_IMAGE_TAG=aea-deploy:0.5.3
# DOCKER_IMAGE_TAG=aea-deploy:latest
DOCKER_BUILD_CONTEXT_DIR=..
diff --git a/develop-image/docker-env.sh b/develop-image/docker-env.sh
index 66af064978..7def9004c0 100755
--- a/develop-image/docker-env.sh
+++ b/develop-image/docker-env.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Swap the following lines if you want to work with 'latest'
-DOCKER_IMAGE_TAG=aea-develop:0.5.2
+DOCKER_IMAGE_TAG=aea-develop:0.5.3
# DOCKER_IMAGE_TAG=aea-develop:latest
DOCKER_BUILD_CONTEXT_DIR=..
diff --git a/docs/acn.md b/docs/acn.md
new file mode 100644
index 0000000000..ff5e4ec970
--- /dev/null
+++ b/docs/acn.md
@@ -0,0 +1,7 @@
+
+
+
Note
+
Details coming soon. In the meantime check out this section.
+
+
+
diff --git a/docs/agent-vs-aea.md b/docs/agent-vs-aea.md
index f5bc543e65..7160ea3ae4 100644
--- a/docs/agent-vs-aea.md
+++ b/docs/agent-vs-aea.md
@@ -67,6 +67,8 @@ class MyAgent(Agent):
envelope.to = sender
envelope.sender = receiver
envelope.message = DefaultMessage.serializer.decode(envelope.message)
+ envelope.message.sender = receiver
+ envelope.message.counterparty = sender
print(
"Received envelope from {} with protocol_id={}".format(
sender, envelope.protocol_id
@@ -122,7 +124,7 @@ We use the input and output text files to send an envelope to our agent and rece
``` python
# Create a message inside an envelope and get the stub connection to pass it into the agent
message_text = (
- b"my_agent,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ b"my_agent,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "wb") as f:
f.write(message_text)
@@ -196,6 +198,8 @@ class MyAgent(Agent):
envelope.to = sender
envelope.sender = receiver
envelope.message = DefaultMessage.serializer.decode(envelope.message)
+ envelope.message.sender = receiver
+ envelope.message.counterparty = sender
print(
"Received envelope from {} with protocol_id={}".format(
sender, envelope.protocol_id
@@ -241,7 +245,7 @@ def run():
# Create a message inside an envelope and get the stub connection to pass it into the agent
message_text = (
- b"my_agent,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ b"my_agent,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "wb") as f:
f.write(message_text)
diff --git a/docs/api/aea.md b/docs/api/aea.md
index c66b584623..0ddaa454cb 100644
--- a/docs/api/aea.md
+++ b/docs/api/aea.md
@@ -7,7 +7,7 @@ This module contains the implementation of an autonomous economic agent (AEA).
## AEA Objects
```python
-class AEA(Agent)
+class AEA(Agent, WithLogger)
```
This class implements an autonomous economic agent.
diff --git a/docs/api/aea_builder.md b/docs/api/aea_builder.md
index 4eb0737345..87258cd202 100644
--- a/docs/api/aea_builder.md
+++ b/docs/api/aea_builder.md
@@ -632,3 +632,21 @@ Construct the builder from an AEA project.
an AEABuilder.
+
+#### make`_`logger
+
+```python
+make_logger(configuration: ComponentConfiguration, agent_name: str) -> Optional[logging.Logger]
+```
+
+Make the logger for a component.
+
+**Arguments**:
+
+- `configuration`: the component configuration
+- `agent_name`: the agent name
+
+**Returns**:
+
+the logger.
+
diff --git a/docs/api/agent.md b/docs/api/agent.md
index 6e1052704f..a1c5153b10 100644
--- a/docs/api/agent.md
+++ b/docs/api/agent.md
@@ -3,67 +3,6 @@
This module contains the implementation of a generic agent.
-
-## AgentState Objects
-
-```python
-class AgentState(Enum)
-```
-
-Enumeration for an agent state.
-
-In particular, it can be one of the following states:
-
-- AgentState.INITIATED: when the Agent object has been created.
-- AgentState.CONNECTED: when the agent is connected.
-- AgentState.RUNNING: when the agent is running.
-
-
-## Liveness Objects
-
-```python
-class Liveness()
-```
-
-Determines the liveness of the agent.
-
-
-#### `__`init`__`
-
-```python
- | __init__()
-```
-
-Instantiate the liveness.
-
-
-#### is`_`stopped
-
-```python
- | @property
- | is_stopped() -> bool
-```
-
-Check whether the liveness is stopped.
-
-
-#### start
-
-```python
- | start() -> None
-```
-
-Start the liveness.
-
-
-#### stop
-
-```python
- | stop() -> None
-```
-
-Stop the liveness.
-
## Agent Objects
@@ -171,16 +110,6 @@ Envelopes placed in the Outbox are processed by the Multiplexer.
Get the agent name.
-
-#### liveness
-
-```python
- | @property
- | liveness() -> Liveness
-```
-
-Get the liveness.
-
#### tick
@@ -203,24 +132,6 @@ Each agent loop (one call to each one of act(), react(), update()) increments th
Get the time in (fractions of) seconds to time out an agent between act and react.
-
-#### agent`_`state
-
-```python
- | @property
- | agent_state() -> AgentState
-```
-
-Get the state of the agent.
-
-**Raises**:
-
-- `ValueError`: if the state does not satisfy any of the foreseen conditions.
-
-**Returns**:
-
-None
-
#### loop`_`mode
@@ -258,7 +169,7 @@ Get the runtime.
| setup_multiplexer() -> None
```
-Set up the multiplexer
+Set up the multiplexer.
#### start
@@ -392,3 +303,17 @@ Tear down the agent.
None
+
+#### state
+
+```python
+ | @property
+ | state() -> RuntimeStates
+```
+
+Get state of the agent's runtime.
+
+**Returns**:
+
+RuntimeStates
+
diff --git a/docs/api/components/base.md b/docs/api/components/base.md
index cb767491b8..53f1e4b718 100644
--- a/docs/api/components/base.md
+++ b/docs/api/components/base.md
@@ -16,7 +16,7 @@ Abstract class for an agent component.
#### `__`init`__`
```python
- | __init__(configuration: Optional[ComponentConfiguration] = None, is_vendor: bool = False)
+ | __init__(configuration: Optional[ComponentConfiguration] = None, is_vendor: bool = False, **kwargs)
```
Initialize a package.
diff --git a/docs/api/connections/base.md b/docs/api/connections/base.md
index 2eed51ed94..704f128a97 100644
--- a/docs/api/connections/base.md
+++ b/docs/api/connections/base.md
@@ -3,23 +3,14 @@
The base connection package.
-
-## ConnectionStatus Objects
+
+## ConnectionStates Objects
```python
-class ConnectionStatus()
+class ConnectionStates(Enum)
```
-The connection status class.
-
-
-#### `__`init`__`
-
-```python
- | __init__()
-```
-
-Initialize the connection status.
+Connection states enum.
## Connection Objects
@@ -34,7 +25,7 @@ Abstract definition of a connection.
#### `__`init`__`
```python
- | __init__(configuration: ConnectionConfig, identity: Optional[Identity] = None, crypto_store: Optional[CryptoStore] = None, restricted_to_protocols: Optional[Set[PublicId]] = None, excluded_protocols: Optional[Set[PublicId]] = None)
+ | __init__(configuration: ConnectionConfig, identity: Optional[Identity] = None, crypto_store: Optional[CryptoStore] = None, restricted_to_protocols: Optional[Set[PublicId]] = None, excluded_protocols: Optional[Set[PublicId]] = None, **kwargs)
```
Initialize the connection.
@@ -148,12 +139,12 @@ Get the ids of the protocols this connection is restricted to.
Get the ids of the excluded protocols for this connection.
-
-#### connection`_`status
+
+#### state
```python
| @property
- | connection_status() -> ConnectionStatus
+ | state() -> ConnectionStates
```
Get the connection status.
@@ -215,7 +206,7 @@ the received envelope, or None if an error occurred.
```python
| @classmethod
- | from_dir(cls, directory: str, identity: Identity, crypto_store: CryptoStore) -> "Connection"
+ | from_dir(cls, directory: str, identity: Identity, crypto_store: CryptoStore, **kwargs) -> "Connection"
```
Load the connection from a directory.
@@ -235,7 +226,7 @@ the connection object.
```python
| @classmethod
- | from_config(cls, configuration: ConnectionConfig, identity: Identity, crypto_store: CryptoStore) -> "Connection"
+ | from_config(cls, configuration: ConnectionConfig, identity: Identity, crypto_store: CryptoStore, **kwargs) -> "Connection"
```
Load a connection from a configuration.
@@ -250,3 +241,23 @@ Load a connection from a configuration.
an instance of the concrete connection class.
+
+#### is`_`connected
+
+```python
+ | @property
+ | is_connected() -> bool
+```
+
+Return is connected state.
+
+
+#### is`_`disconnected
+
+```python
+ | @property
+ | is_disconnected() -> bool
+```
+
+Return is disconnected state.
+
diff --git a/docs/api/contracts/base.md b/docs/api/contracts/base.md
index 0620975a70..b7d4bbd02f 100644
--- a/docs/api/contracts/base.md
+++ b/docs/api/contracts/base.md
@@ -16,7 +16,7 @@ Abstract definition of a contract.
#### `__`init`__`
```python
- | __init__(contract_config: ContractConfig)
+ | __init__(contract_config: ContractConfig, **kwargs)
```
Initialize the contract.
@@ -70,7 +70,7 @@ the contract instance
```python
| @classmethod
- | from_dir(cls, directory: str) -> "Contract"
+ | from_dir(cls, directory: str, **kwargs) -> "Contract"
```
Load the protocol from a directory.
@@ -88,7 +88,7 @@ the contract object.
```python
| @classmethod
- | from_config(cls, configuration: ContractConfig) -> "Contract"
+ | from_config(cls, configuration: ContractConfig, **kwargs) -> "Contract"
```
Load contract from configuration.
@@ -101,3 +101,91 @@ Load contract from configuration.
the contract object.
+
+#### get`_`deploy`_`transaction
+
+```python
+ | @classmethod
+ | get_deploy_transaction(cls, ledger_api: LedgerApi, **kwargs) -> bytes
+```
+
+Handler method for the 'GET_DEPLOY_TRANSACTION' requests.
+
+Implement this method in the sub class if you want
+to handle the contract requests manually.
+
+**Arguments**:
+
+- `ledger_api`: the ledger apis.
+- `kwargs`: keyword arguments.
+
+**Returns**:
+
+the bytes representing the state.
+
+
+#### get`_`raw`_`transaction
+
+```python
+ | @classmethod
+ | get_raw_transaction(cls, ledger_api: LedgerApi, contract_address: str, **kwargs) -> bytes
+```
+
+Handler method for the 'GET_RAW_TRANSACTION' requests.
+
+Implement this method in the sub class if you want
+to handle the contract requests manually.
+
+**Arguments**:
+
+- `ledger_api`: the ledger apis.
+- `contract_address`: the contract address.
+
+**Returns**:
+
+the bytes representing the state.
+
+
+#### get`_`raw`_`message
+
+```python
+ | @classmethod
+ | get_raw_message(cls, ledger_api: LedgerApi, contract_address: str, **kwargs) -> 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.
+
+**Arguments**:
+
+- `ledger_api`: the ledger apis.
+- `contract_address`: the contract address.
+
+**Returns**:
+
+the bytes representing the state.
+
+
+#### get`_`state
+
+```python
+ | @classmethod
+ | get_state(cls, ledger_api: LedgerApi, contract_address: str, **kwargs) -> bytes
+```
+
+Handler method for the 'GET_STATE' requests.
+
+Implement this method in the sub class if you want
+to handle the contract requests manually.
+
+**Arguments**:
+
+- `ledger_api`: the ledger apis.
+- `contract_address`: the contract address.
+
+**Returns**:
+
+the bytes representing the state.
+
diff --git a/docs/api/crypto/base.md b/docs/api/crypto/base.md
index c3bf1ab83f..425d185000 100644
--- a/docs/api/crypto/base.md
+++ b/docs/api/crypto/base.md
@@ -291,6 +291,25 @@ Recover the addresses from the hash.
the recovered addresses
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | @abstractmethod
+ | get_hash(message: bytes) -> str
+```
+
+Get the hash of a message.
+
+**Arguments**:
+
+- `message`: the message to be hashed.
+
+**Returns**:
+
+the hash of the message.
+
## LedgerApi Objects
diff --git a/docs/api/crypto/cosmos.md b/docs/api/crypto/cosmos.md
index 4c7c4d0fd2..6c514792fa 100644
--- a/docs/api/crypto/cosmos.md
+++ b/docs/api/crypto/cosmos.md
@@ -103,6 +103,46 @@ Sign a message in bytes string form.
signature of the message in string form
+
+#### format`_`default`_`transaction
+
+```python
+ | @staticmethod
+ | format_default_transaction(transaction: Any, signature: str, base64_pbk: str) -> Any
+```
+
+Format default CosmosSDK transaction and add signature
+
+**Arguments**:
+
+- `transaction`: the transaction to be formatted
+- `signature`: the transaction signature
+- `base64_pbk`: the base64 formatted public key
+
+**Returns**:
+
+formatted transaction with signature
+
+
+#### format`_`wasm`_`transaction
+
+```python
+ | @staticmethod
+ | format_wasm_transaction(transaction: Any, signature: str, base64_pbk: str) -> Any
+```
+
+Format CosmWasm transaction and add signature
+
+**Arguments**:
+
+- `transaction`: the transaction to be formatted
+- `signature`: the transaction signature
+- `base64_pbk`: the base64 formatted public key
+
+**Returns**:
+
+formatted transaction with signature
+
#### sign`_`transaction
@@ -253,6 +293,24 @@ Recover the addresses from the hash.
the recovered addresses
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | get_hash(message: bytes) -> str
+```
+
+Get the hash of a message.
+
+**Arguments**:
+
+- `message`: the message to be hashed.
+
+**Returns**:
+
+the hash of the message.
+
## CosmosApi Objects
diff --git a/docs/api/crypto/ethereum.md b/docs/api/crypto/ethereum.md
index 063fdfc06c..2d207b4353 100644
--- a/docs/api/crypto/ethereum.md
+++ b/docs/api/crypto/ethereum.md
@@ -253,6 +253,24 @@ Recover the addresses from the hash.
the recovered addresses
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | get_hash(message: bytes) -> str
+```
+
+Get the hash of a message.
+
+**Arguments**:
+
+- `message`: the message to be hashed.
+
+**Returns**:
+
+the hash of the message.
+
## EthereumApi Objects
diff --git a/docs/api/crypto/fetchai.md b/docs/api/crypto/fetchai.md
index 4d0f70f128..ffa7427790 100644
--- a/docs/api/crypto/fetchai.md
+++ b/docs/api/crypto/fetchai.md
@@ -253,6 +253,24 @@ Recover the addresses from the hash.
the recovered addresses
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | get_hash(message: bytes) -> str
+```
+
+Get the hash of a message.
+
+**Arguments**:
+
+- `message`: the message to be hashed.
+
+**Returns**:
+
+the hash of the message.
+
## FetchAIApi Objects
diff --git a/docs/api/crypto/helpers.md b/docs/api/crypto/helpers.md
index 1e7b80e7a8..ac2323abfb 100644
--- a/docs/api/crypto/helpers.md
+++ b/docs/api/crypto/helpers.md
@@ -3,6 +3,19 @@
Module wrapping the helpers of public and private key cryptography.
+
+#### verify`_`or`_`create`_`private`_`keys
+
+```python
+verify_or_create_private_keys(aea_project_path: Path, exit_on_error: bool = True) -> AgentConfig
+```
+
+Verify or create private keys.
+
+**Arguments**:
+
+- `ctx`: Context
+
#### try`_`validate`_`private`_`key`_`path
@@ -26,7 +39,7 @@ None
#### create`_`private`_`key
```python
-create_private_key(ledger_id: str, private_key_file: Optional[str] = None) -> None
+create_private_key(ledger_id: str, private_key_file: str) -> None
```
Create a private key for the specified ledger identifier.
@@ -34,6 +47,7 @@ Create a private key for the specified ledger identifier.
**Arguments**:
- `ledger_id`: the ledger identifier.
+- `private_key_file`: the private key file.
**Returns**:
diff --git a/docs/api/crypto/ledger_apis.md b/docs/api/crypto/ledger_apis.md
index 8604498216..92b1960b1e 100644
--- a/docs/api/crypto/ledger_apis.md
+++ b/docs/api/crypto/ledger_apis.md
@@ -12,83 +12,32 @@ class LedgerApis()
Store all the ledger apis we initialise.
-
-#### `__`init`__`
-
-```python
- | __init__(ledger_api_configs: Dict[str, Dict[str, Union[str, int]]], default_ledger_id: str)
-```
-
-Instantiate a wallet object.
-
-**Arguments**:
-
-- `ledger_api_configs`: the ledger api configs.
-- `default_ledger_id`: the default ledger id.
-
-
-#### configs
-
-```python
- | @property
- | configs() -> Dict[str, Dict[str, Union[str, int]]]
-```
-
-Get the configs.
-
-
-#### apis
-
-```python
- | @property
- | apis() -> Dict[str, LedgerApi]
-```
-
-Get the apis.
-
#### has`_`ledger
```python
+ | @staticmethod
| has_ledger(identifier: str) -> bool
```
-Check if it has a .
+Check if it has the api.
#### get`_`api
```python
- | get_api(identifier: str) -> LedgerApi
+ | @classmethod
+ | get_api(cls, identifier: str) -> LedgerApi
```
Get the ledger API.
-
-#### has`_`default`_`ledger
-
-```python
- | @property
- | has_default_ledger() -> bool
-```
-
-Check if it has the default ledger API.
-
-
-#### default`_`ledger`_`id
-
-```python
- | @property
- | default_ledger_id() -> str
-```
-
-Get the default ledger id.
-
#### get`_`balance
```python
- | get_balance(identifier: str, address: str) -> Optional[int]
+ | @classmethod
+ | get_balance(cls, identifier: str, address: str) -> Optional[int]
```
Get the token balance.
@@ -106,7 +55,8 @@ the token balance
#### get`_`transfer`_`transaction
```python
- | get_transfer_transaction(identifier: str, sender_address: str, destination_address: str, amount: int, tx_fee: int, tx_nonce: str, **kwargs, ,) -> Optional[Any]
+ | @classmethod
+ | get_transfer_transaction(cls, identifier: str, sender_address: str, destination_address: str, amount: int, tx_fee: int, tx_nonce: str, **kwargs, ,) -> Optional[Any]
```
Get a transaction to transfer from self to destination.
@@ -128,7 +78,8 @@ tx
#### send`_`signed`_`transaction
```python
- | send_signed_transaction(identifier: str, tx_signed: Any) -> Optional[str]
+ | @classmethod
+ | send_signed_transaction(cls, identifier: str, tx_signed: Any) -> Optional[str]
```
Send a signed transaction and wait for confirmation.
@@ -146,7 +97,8 @@ the tx_digest, if present
#### get`_`transaction`_`receipt
```python
- | get_transaction_receipt(identifier: str, tx_digest: str) -> Optional[Any]
+ | @classmethod
+ | get_transaction_receipt(cls, identifier: str, tx_digest: str) -> Optional[Any]
```
Get the transaction receipt for a transaction digest.
@@ -164,7 +116,8 @@ the tx receipt, if present
#### get`_`transaction
```python
- | get_transaction(identifier: str, tx_digest: str) -> Optional[Any]
+ | @classmethod
+ | get_transaction(cls, identifier: str, tx_digest: str) -> Optional[Any]
```
Get the transaction for a transaction digest.
@@ -240,3 +193,43 @@ Generate a random str message.
return the hash in hex.
+
+#### recover`_`message
+
+```python
+ | @staticmethod
+ | recover_message(identifier: str, message: bytes, signature: str, is_deprecated_mode: bool = False) -> Tuple[Address, ...]
+```
+
+Recover the addresses from the hash.
+
+**Arguments**:
+
+- `identifier`: ledger identifier.
+- `message`: the message we expect
+- `signature`: the transaction signature
+- `is_deprecated_mode`: if the deprecated signing was used
+
+**Returns**:
+
+the recovered addresses
+
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | get_hash(identifier: str, message: bytes) -> str
+```
+
+Get the hash of a message.
+
+**Arguments**:
+
+- `identifier`: ledger identifier.
+- `message`: the message to be hashed.
+
+**Returns**:
+
+the hash of the message.
+
diff --git a/docs/api/crypto/registries/base.md b/docs/api/crypto/registries/base.md
index 5660e95c9d..e4b435a360 100644
--- a/docs/api/crypto/registries/base.md
+++ b/docs/api/crypto/registries/base.md
@@ -128,6 +128,19 @@ Instantiate an instance of the item object with appropriate arguments.
an item
+
+#### get`_`class
+
+```python
+ | get_class() -> Type[ItemType]
+```
+
+Get the class of the item with class variables instantiated.
+
+**Returns**:
+
+an item class
+
## Registry Objects
@@ -203,6 +216,32 @@ the make can then find the identifier.
the new item instance.
+
+#### make`_`cls
+
+```python
+ | make_cls(id_: Union[ItemId, str], module: Optional[str] = None) -> Type[ItemType]
+```
+
+Load a class of the associated type item id.
+
+**Arguments**:
+
+- `id_`: the id of the item class. Make sure it has been registered earlier
+before calling this function.
+- `module`: dotted path to a module.
+whether a module should be loaded before creating the object.
+this argument is useful when the item might not be registered
+beforehand, and loading the specified module will make the registration.
+E.g. suppose the call to 'register' for a custom object
+is located in some_package/__init__.py. By providing module="some_package",
+the call to 'register' in such module gets triggered and
+the make can then find the identifier.
+
+**Returns**:
+
+the new item class.
+
#### has`_`spec
diff --git a/docs/api/crypto/wallet.md b/docs/api/crypto/wallet.md
index 0452d4e982..37dc2b21d4 100644
--- a/docs/api/crypto/wallet.md
+++ b/docs/api/crypto/wallet.md
@@ -56,6 +56,16 @@ Get the crypto objects (key pair).
Get the crypto addresses.
+
+#### private`_`keys
+
+```python
+ | @property
+ | private_keys() -> Dict[str, str]
+```
+
+Get the crypto addresses.
+
## Wallet Objects
@@ -114,6 +124,16 @@ Get the crypto objects (key pair).
Get the crypto addresses.
+
+#### private`_`keys
+
+```python
+ | @property
+ | private_keys() -> Dict[str, str]
+```
+
+Get the crypto addresses.
+
#### main`_`cryptos
diff --git a/docs/api/helpers/async_utils.md b/docs/api/helpers/async_utils.md
index 426be9b2e3..313cfdf4f7 100644
--- a/docs/api/helpers/async_utils.md
+++ b/docs/api/helpers/async_utils.md
@@ -25,7 +25,7 @@ Awaitable state.
#### `__`init`__`
```python
- | __init__(initial_state: Any = None)
+ | __init__(initial_state: Any = None, states_enum: Optional[Container[Any]] = None)
```
Init async state.
@@ -33,35 +33,33 @@ Init async state.
**Arguments**:
- `initial_state`: state to set on start.
+- `states_enum`: container of valid states if not provided state not checked on set.
-
-#### state
+
+#### set
```python
- | @property
- | state() -> Any
+ | set(state: Any) -> None
```
-Return current state.
+Set state.
-
-#### state
+
+#### add`_`callback
```python
- | @state.setter
- | state(state: Any) -> None
+ | add_callback(callback_fn: Callable[[Any], None]) -> None
```
-Set state.
+Add callback to track state changes.
-
-#### set
+**Arguments**:
-```python
- | set(state: Any) -> None
-```
+- `callback_fn`: callable object to be called on state changed.
-Set state.
+**Returns**:
+
+None
#### get
@@ -199,17 +197,6 @@ Wait for coroutine execution result.
Cancel coroutine task execution in a target loop.
-
-#### future`_`cancel
-
-```python
- | future_cancel() -> None
-```
-
-Cancel task waiting future.
-
-In this case future result will raise CanclledError not waiting for real task exit.
-
#### done
diff --git a/docs/api/helpers/dialogue/base.md b/docs/api/helpers/dialogue/base.md
index 3d920980b7..2ddad349bd 100644
--- a/docs/api/helpers/dialogue/base.md
+++ b/docs/api/helpers/dialogue/base.md
@@ -123,6 +123,15 @@ Return the JSON representation.
Get dialogue label from json.
+
+#### get`_`incomplete`_`version
+
+```python
+ | get_incomplete_version() -> "DialogueLabel"
+```
+
+Get the incomplete version of the label.
+
#### `__`str`__`
@@ -132,6 +141,16 @@ Get dialogue label from json.
Get the string representation.
+
+#### from`_`str
+
+```python
+ | @classmethod
+ | from_str(cls, obj: str) -> "DialogueLabel"
+```
+
+Get the dialogue label from string representation.
+
## Dialogue Objects
@@ -298,6 +317,34 @@ Get the dialogue label.
The dialogue label
+
+#### incomplete`_`dialogue`_`label
+
+```python
+ | @property
+ | incomplete_dialogue_label() -> DialogueLabel
+```
+
+Get the dialogue label.
+
+**Returns**:
+
+The incomplete dialogue label
+
+
+#### dialogue`_`labels
+
+```python
+ | @property
+ | dialogue_labels() -> Set[DialogueLabel]
+```
+
+Get the dialogue labels (incomplete and complete, if it exists)
+
+**Returns**:
+
+the dialogue labels
+
#### agent`_`address
@@ -464,7 +511,7 @@ True if empty, False otherwise
| update(message: Message) -> bool
```
-Extend the list of incoming/outgoing messages with 'message', if 'message' is valid.
+Extend the list of incoming/outgoing messages with 'message', if 'message' belongs to dialogue and is valid.
**Arguments**:
@@ -474,6 +521,40 @@ Extend the list of incoming/outgoing messages with 'message', if 'message' is va
True if message successfully added, false otherwise
+
+#### ensure`_`counterparty
+
+```python
+ | ensure_counterparty(message: Message) -> None
+```
+
+Ensure the counterparty is set (set if not) correctly.
+
+**Arguments**:
+
+- `message`: a message
+
+**Returns**:
+
+None
+
+
+#### is`_`belonging`_`to`_`dialogue
+
+```python
+ | is_belonging_to_dialogue(message: Message) -> bool
+```
+
+Check if the message is belonging to the dialogue.
+
+**Arguments**:
+
+- `message`: the message
+
+**Returns**:
+
+Ture if message is part of the dialogue, False otherwise
+
#### reply
@@ -753,6 +834,20 @@ Retrieve the dialogue 'message' belongs to.
the dialogue, or None in case such a dialogue does not exist
+
+#### get`_`latest`_`label
+
+```python
+ | get_latest_label(dialogue_label: DialogueLabel) -> DialogueLabel
+```
+
+Retrieve the latest dialogue label if present otherwise return same label.
+
+**Arguments**:
+
+- `dialogue_label`: the dialogue label
+:return dialogue_label: the dialogue label
+
#### get`_`dialogue`_`from`_`label
diff --git a/docs/api/helpers/test_cases.md b/docs/api/helpers/test_cases.md
index 8a5c5f4d0a..cfbed4fda6 100644
--- a/docs/api/helpers/test_cases.md
+++ b/docs/api/helpers/test_cases.md
@@ -37,10 +37,11 @@ Unset the current agent context.
```python
| @classmethod
- | set_config(cls, dotted_path: str, value: Any, type_: str = "str") -> None
+ | set_config(cls, dotted_path: str, value: Any, type_: str = "str") -> Result
```
Set a config.
+
Run from agent's directory.
**Arguments**:
@@ -51,7 +52,7 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### force`_`set`_`config
@@ -68,10 +69,11 @@ Force set config.
```python
| @classmethod
- | disable_aea_logging(cls)
+ | disable_aea_logging(cls) -> None
```
Disable AEA logging of specific agent.
+
Run from agent's directory.
**Returns**:
@@ -83,7 +85,7 @@ None
```python
| @classmethod
- | run_cli_command(cls, *args: str, *, cwd: str = ".") -> None
+ | run_cli_command(cls, *args: str, *, cwd: str = ".") -> Result
```
Run AEA CLI command.
@@ -99,7 +101,7 @@ Run AEA CLI command.
**Returns**:
-None
+Result
#### start`_`subprocess
@@ -124,7 +126,7 @@ subprocess object.
```python
| @classmethod
- | start_thread(cls, target: Callable, **kwargs) -> None
+ | start_thread(cls, target: Callable, **kwargs) -> Thread
```
Start python Thread.
@@ -221,6 +223,7 @@ None
```
Run agent as subprocess.
+
Run from agent's directory.
**Arguments**:
@@ -240,6 +243,7 @@ subprocess object.
```
Run interaction as subprocess.
+
Run from agent's directory.
**Arguments**:
@@ -259,6 +263,7 @@ subprocess object.
```
Terminate agent subprocesses.
+
Run from agent's directory.
**Arguments**:
@@ -275,7 +280,7 @@ Run from agent's directory.
| is_successfully_terminated(cls, *subprocesses: subprocess.Popen)
```
-Check if all subprocesses terminated successfully
+Check if all subprocesses terminated successfully.
#### initialize`_`aea
@@ -296,10 +301,11 @@ None
```python
| @classmethod
- | add_item(cls, item_type: str, public_id: str, local: bool = True) -> None
+ | add_item(cls, item_type: str, public_id: str, local: bool = True) -> Result
```
Add an item to the agent.
+
Run from agent's directory.
**Arguments**:
@@ -310,17 +316,18 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### scaffold`_`item
```python
| @classmethod
- | scaffold_item(cls, item_type: str, name: str) -> None
+ | scaffold_item(cls, item_type: str, name: str) -> Result
```
Scaffold an item for the agent.
+
Run from agent's directory.
**Arguments**:
@@ -330,17 +337,18 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### fingerprint`_`item
```python
| @classmethod
- | fingerprint_item(cls, item_type: str, public_id: str) -> None
+ | fingerprint_item(cls, item_type: str, public_id: str) -> Result
```
-Scaffold an item for the agent.
+Fingerprint an item for the agent.
+
Run from agent's directory.
**Arguments**:
@@ -350,17 +358,18 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### eject`_`item
```python
| @classmethod
- | eject_item(cls, item_type: str, public_id: str) -> None
+ | eject_item(cls, item_type: str, public_id: str) -> Result
```
Eject an item in the agent.
+
Run from agent's directory.
**Arguments**:
@@ -377,44 +386,48 @@ None
```python
| @classmethod
- | run_install(cls)
+ | run_install(cls) -> Result
```
Execute AEA CLI install command.
+
Run from agent's directory.
**Returns**:
-None
+Result
#### generate`_`private`_`key
```python
| @classmethod
- | generate_private_key(cls, ledger_api_id: str = DEFAULT_LEDGER) -> None
+ | generate_private_key(cls, ledger_api_id: str = DEFAULT_LEDGER, private_key_file: Optional[str] = None) -> Result
```
Generate AEA private key with CLI command.
+
Run from agent's directory.
**Arguments**:
- `ledger_api_id`: ledger API ID.
+- `private_key_file`: the private key file.
**Returns**:
-None
+Result
#### add`_`private`_`key
```python
| @classmethod
- | add_private_key(cls, ledger_api_id: str = DEFAULT_LEDGER, private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE, connection: bool = False) -> None
+ | add_private_key(cls, ledger_api_id: str = DEFAULT_LEDGER, private_key_filepath: str = DEFAULT_PRIVATE_KEY_FILE, connection: bool = False) -> Result
```
Add private key with CLI command.
+
Run from agent's directory.
**Arguments**:
@@ -425,7 +438,7 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### replace`_`private`_`key`_`in`_`file
@@ -452,10 +465,11 @@ None
```python
| @classmethod
- | generate_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> None
+ | generate_wealth(cls, ledger_api_id: str = DEFAULT_LEDGER) -> Result
```
Generate wealth with CLI command.
+
Run from agent's directory.
**Arguments**:
@@ -464,7 +478,7 @@ Run from agent's directory.
**Returns**:
-None
+Result
#### get`_`wealth
@@ -475,6 +489,7 @@ None
```
Get wealth with CLI command.
+
Run from agent's directory.
**Arguments**:
@@ -551,6 +566,7 @@ Read an envelope from an agent, using the stub connection.
```
Check if strings are present in process output.
+
Read process stdout in thread and terminate when all strings are present
or timeout expired.
diff --git a/docs/api/helpers/transaction/base.md b/docs/api/helpers/transaction/base.md
index 2fead6fa2b..d7f9b47d5f 100644
--- a/docs/api/helpers/transaction/base.md
+++ b/docs/api/helpers/transaction/base.md
@@ -431,10 +431,10 @@ Class to represent the terms of a multi-currency & multi-token ledger transactio
#### `__`init`__`
```python
- | __init__(ledger_id: str, sender_address: Address, counterparty_address: Address, amount_by_currency_id: Dict[str, int], quantities_by_good_id: Dict[str, int], is_sender_payable_tx_fee: bool, nonce: str, fee_by_currency_id: Optional[Dict[str, int]] = None, **kwargs, ,)
+ | __init__(ledger_id: str, sender_address: Address, counterparty_address: Address, amount_by_currency_id: Dict[str, int], quantities_by_good_id: Dict[str, int], nonce: str, is_sender_payable_tx_fee: bool = True, fee_by_currency_id: Optional[Dict[str, int]] = None, is_strict: bool = False, **kwargs, ,)
```
-Instantiate terms.
+Instantiate terms of a transaction.
**Arguments**:
@@ -446,6 +446,37 @@ Instantiate terms.
- `is_sender_payable_tx_fee`: whether the sender or counterparty pays the tx fee.
- `nonce`: nonce to be included in transaction to discriminate otherwise identical transactions.
- `fee_by_currency_id`: the fee associated with the transaction.
+- `is_strict`: whether or not terms must have quantities and amounts of opposite signs.
+
+
+#### id
+
+```python
+ | @property
+ | id() -> str
+```
+
+Get hash of the terms.
+
+
+#### sender`_`hash
+
+```python
+ | @property
+ | sender_hash() -> str
+```
+
+Get the sender hash.
+
+
+#### counterparty`_`hash
+
+```python
+ | @property
+ | counterparty_hash() -> str
+```
+
+Get the sender hash.
#### ledger`_`id
@@ -497,6 +528,46 @@ Set the counterparty address.
Get the amount by currency id.
+
+#### is`_`sender`_`payable`_`tx`_`fee
+
+```python
+ | @property
+ | is_sender_payable_tx_fee() -> bool
+```
+
+Bool indicating whether the tx fee is paid by sender or counterparty.
+
+
+#### is`_`single`_`currency
+
+```python
+ | @property
+ | is_single_currency() -> bool
+```
+
+Check whether a single currency is used for payment.
+
+
+#### is`_`empty`_`currency
+
+```python
+ | @property
+ | is_empty_currency() -> bool
+```
+
+Check whether a single currency is used for payment.
+
+
+#### currency`_`id
+
+```python
+ | @property
+ | currency_id() -> str
+```
+
+Get the amount the sender must pay.
+
#### sender`_`payable`_`amount
@@ -507,6 +578,16 @@ Get the amount by currency id.
Get the amount the sender must pay.
+
+#### sender`_`payable`_`amount`_`incl`_`fee
+
+```python
+ | @property
+ | sender_payable_amount_incl_fee() -> int
+```
+
+Get the amount the sender must pay inclusive fee.
+
#### counterparty`_`payable`_`amount
@@ -517,6 +598,16 @@ Get the amount the sender must pay.
Get the amount the counterparty must pay.
+
+#### counterparty`_`payable`_`amount`_`incl`_`fee
+
+```python
+ | @property
+ | counterparty_payable_amount_incl_fee() -> int
+```
+
+Get the amount the counterparty must pay.
+
#### quantities`_`by`_`good`_`id
@@ -527,15 +618,35 @@ Get the amount the counterparty must pay.
Get the quantities by good id.
-
-#### is`_`sender`_`payable`_`tx`_`fee
+
+#### good`_`ids
```python
| @property
- | is_sender_payable_tx_fee() -> bool
+ | good_ids() -> List[str]
```
-Bool indicating whether the tx fee is paid by sender or counterparty.
+Get the (ordered) good ids.
+
+
+#### sender`_`supplied`_`quantities
+
+```python
+ | @property
+ | sender_supplied_quantities() -> List[int]
+```
+
+Get the (ordered) quantities supplied by the sender.
+
+
+#### counterparty`_`supplied`_`quantities
+
+```python
+ | @property
+ | counterparty_supplied_quantities() -> List[int]
+```
+
+Get the (ordered) quantities supplied by the counterparty.
#### nonce
@@ -567,6 +678,26 @@ Check if fee is set.
Get the fee.
+
+#### sender`_`fee
+
+```python
+ | @property
+ | sender_fee() -> int
+```
+
+Get the sender fee.
+
+
+#### counterparty`_`fee
+
+```python
+ | @property
+ | counterparty_fee() -> int
+```
+
+Get the counterparty fee.
+
#### fee`_`by`_`currency`_`id
@@ -587,6 +718,31 @@ Get fee by currency.
Get the kwargs.
+
+#### get`_`hash
+
+```python
+ | @staticmethod
+ | get_hash(ledger_id: str, sender_address: str, counterparty_address: str, good_ids: List[str], sender_supplied_quantities: List[int], counterparty_supplied_quantities: List[int], sender_payable_amount: int, counterparty_payable_amount: int, nonce: str) -> str
+```
+
+Generate a hash from transaction information.
+
+**Arguments**:
+
+- `sender_addr`: the sender address
+- `counterparty_addr`: the counterparty address
+- `good_ids`: the list of good ids
+- `sender_supplied_quantities`: the quantities supplied by the sender (must all be positive)
+- `counterparty_supplied_quantities`: the quantities supplied by the counterparty (must all be positive)
+- `sender_payable_amount`: the amount payable by the sender
+- `counterparty_payable_amount`: the amount payable by the counterparty
+- `tx_nonce`: the nonce of the transaction
+
+**Returns**:
+
+the hash
+
#### encode
diff --git a/docs/api/multiplexer.md b/docs/api/multiplexer.md
index 7d0c4bbc97..f07ab99ca0 100644
--- a/docs/api/multiplexer.md
+++ b/docs/api/multiplexer.md
@@ -3,6 +3,24 @@
Module for the multiplexer class and related classes.
+
+## ConnectionStatus Objects
+
+```python
+class ConnectionStatus()
+```
+
+The connection status class.
+
+
+#### `__`init`__`
+
+```python
+ | __init__()
+```
+
+Initialize the connection status.
+
## AsyncMultiplexer Objects
@@ -484,17 +502,18 @@ None
#### put`_`message
```python
- | put_message(message: Message, sender: Optional[Address] = None, context: Optional[EnvelopeContext] = None) -> None
+ | put_message(message: Message, context: Optional[EnvelopeContext] = None, sender: Optional[str] = None) -> None
```
Put a message in the outbox.
This constructs an envelope with the input arguments.
+"sender" is a deprecated kwarg and will be removed in the next version
+
**Arguments**:
-- `sender`: the sender of the envelope (optional field only necessary when the non-default address is used for sending).
-- `message`: the message.
+- `message`: the message
- `context`: the envelope context
**Returns**:
diff --git a/docs/api/protocols/base.md b/docs/api/protocols/base.md
index ed15507645..57170e2faf 100644
--- a/docs/api/protocols/base.md
+++ b/docs/api/protocols/base.md
@@ -44,6 +44,78 @@ Initialize a Message object.
- `body`: the dictionary of values to hold.
- `kwargs`: any additional value to add to the body. It will overwrite the body values.
+
+#### has`_`sender
+
+```python
+ | @property
+ | has_sender() -> bool
+```
+
+Check if it has a sender.
+
+
+#### sender
+
+```python
+ | @property
+ | sender() -> Address
+```
+
+Get the sender of the message in Address form.
+
+:return the address
+
+
+#### sender
+
+```python
+ | @sender.setter
+ | sender(sender: Address) -> None
+```
+
+Set the sender of the message.
+
+
+#### has`_`to
+
+```python
+ | @property
+ | has_to() -> bool
+```
+
+Check if it has a sender.
+
+
+#### to
+
+```python
+ | @property
+ | to() -> Address
+```
+
+Get address of receiver.
+
+
+#### to
+
+```python
+ | @to.setter
+ | to(to: Address) -> None
+```
+
+Set address of receiver.
+
+
+#### has`_`counterparty
+
+```python
+ | @property
+ | has_counterparty() -> bool
+```
+
+Check if the counterparty is set.
+
#### counterparty
@@ -390,7 +462,7 @@ It includes a serializer to encode/decode a message.
#### `__`init`__`
```python
- | __init__(configuration: ProtocolConfig, message_class: Type[Message])
+ | __init__(configuration: ProtocolConfig, message_class: Type[Message], **kwargs)
```
Initialize the protocol manager.
@@ -398,7 +470,7 @@ Initialize the protocol manager.
**Arguments**:
- `configuration`: the protocol configurations.
-- `serializer`: the serializer.
+- `message_class`: the message class.
#### serializer
@@ -415,7 +487,7 @@ Get the serializer.
```python
| @classmethod
- | from_dir(cls, directory: str) -> "Protocol"
+ | from_dir(cls, directory: str, **kwargs) -> "Protocol"
```
Load the protocol from a directory.
@@ -433,7 +505,7 @@ the protocol object.
```python
| @classmethod
- | from_config(cls, configuration: ProtocolConfig) -> "Protocol"
+ | from_config(cls, configuration: ProtocolConfig, **kwargs) -> "Protocol"
```
Load the protocol from configuration.
diff --git a/docs/api/registries/base.md b/docs/api/registries/base.md
index 483ba5b224..9306db7d64 100644
--- a/docs/api/registries/base.md
+++ b/docs/api/registries/base.md
@@ -26,7 +26,7 @@ Initialize the registry.
```python
| @abstractmethod
- | register(item_id: ItemId, item: Item) -> None
+ | register(item_id: ItemId, item: Item, is_dynamically_added: bool = False) -> None
```
Register an item.
@@ -35,6 +35,7 @@ Register an item.
- `item_id`: the public id of the item.
- `item`: the item.
+- `is_dynamicall_added`: whether or not the item is dynamicall added.
**Returns**:
@@ -146,7 +147,7 @@ None
#### register
```python
- | register(component_id: ComponentId, component: Component) -> None
+ | register(component_id: ComponentId, component: Component, is_dynamically_added: bool = False) -> None
```
Register a component.
@@ -155,6 +156,7 @@ Register a component.
- `component_id`: the id of the component.
- `component`: the component object.
+- `is_dynamicall_added`: whether or not the item is dynamicall added.
#### unregister
@@ -264,7 +266,7 @@ None
#### register
```python
- | register(item_id: Tuple[SkillId, str], item: SkillComponentType) -> None
+ | register(item_id: Tuple[SkillId, str], item: SkillComponentType, is_dynamically_added: bool = False) -> None
```
Register a item.
@@ -273,6 +275,7 @@ Register a item.
- `item_id`: a pair (skill id, item name).
- `item`: the item to register.
+- `is_dynamicall_added`: whether or not the item is dynamicall added.
**Returns**:
@@ -393,7 +396,7 @@ None
#### register
```python
- | register(item_id: Tuple[SkillId, str], item: Handler) -> None
+ | register(item_id: Tuple[SkillId, str], item: Handler, is_dynamically_added: bool = False) -> None
```
Register a handler.
@@ -402,6 +405,7 @@ Register a handler.
- `item_id`: the item id.
- `item`: the handler.
+- `is_dynamicall_added`: whether or not the item is dynamicall added.
**Returns**:
diff --git a/docs/api/registries/filter.md b/docs/api/registries/filter.md
index c61269dd13..8f8fcfbeda 100644
--- a/docs/api/registries/filter.md
+++ b/docs/api/registries/filter.md
@@ -50,7 +50,7 @@ Get decision maker (out) queue.
#### get`_`active`_`handlers
```python
- | get_active_handlers(protocol_id: PublicId, skill_id: Optional[SkillId]) -> List[Handler]
+ | get_active_handlers(protocol_id: PublicId, skill_id: Optional[SkillId] = None) -> List[Handler]
```
Get active handlers based on protocol id and optional skill id.
diff --git a/docs/api/registries/resources.md b/docs/api/registries/resources.md
index b92e9f4dc3..45b48633fc 100644
--- a/docs/api/registries/resources.md
+++ b/docs/api/registries/resources.md
@@ -281,23 +281,6 @@ Add a skill to the set of resources.
None
-
-#### inject`_`contracts
-
-```python
- | inject_contracts(skill: Skill) -> None
-```
-
-Inject contracts into a skill context.
-
-**Arguments**:
-
-- `skill`: a skill
-
-**Returns**:
-
-None
-
#### get`_`skill
diff --git a/docs/api/runtime.md b/docs/api/runtime.md
index c3e91ca60b..50b3f3f33b 100644
--- a/docs/api/runtime.md
+++ b/docs/api/runtime.md
@@ -90,6 +90,20 @@ Set event loop to be used.
- `loop`: event loop to use.
+
+#### state
+
+```python
+ | @property
+ | state() -> RuntimeStates
+```
+
+Get runtime state.
+
+**Returns**:
+
+RuntimeStates
+
## AsyncRuntime Objects
diff --git a/docs/api/skills/base.md b/docs/api/skills/base.md
index ceac293166..73e024a191 100644
--- a/docs/api/skills/base.md
+++ b/docs/api/skills/base.md
@@ -29,7 +29,7 @@ Initialize a skill context.
```python
| @property
- | logger() -> Union[Logger, LoggerAdapter]
+ | logger() -> Logger
```
Get the logger.
@@ -98,7 +98,7 @@ Set the status of the skill (active/not active).
```python
| @property
- | new_behaviours() -> Queue
+ | new_behaviours() -> "Queue[Behaviour]"
```
Queue for the new behaviours.
@@ -108,6 +108,21 @@ to request the registration of a behaviour.
:return the queue of new behaviours.
+
+#### new`_`handlers
+
+```python
+ | @property
+ | new_handlers() -> "Queue[Handler]"
+```
+
+Queue for the new handlers.
+
+This queue can be used to send messages to the framework
+to request the registration of a handler.
+
+:return the queue of new handlers.
+
#### agent`_`addresses
@@ -218,16 +233,6 @@ Get handlers of the skill.
Get behaviours of the skill.
-
-#### contracts
-
-```python
- | @property
- | contracts() -> SimpleNamespace
-```
-
-Get contracts the skill has access to.
-
#### namespace
@@ -573,25 +578,6 @@ Initialize a skill.
- `behaviours`: dictionary of behaviours.
- `models`: dictionary of models.
-
-#### contracts
-
-```python
- | @property
- | contracts() -> Dict[str, Contract]
-```
-
-Get the contracts associated with the skill.
-
-
-#### inject`_`contracts
-
-```python
- | inject_contracts(contracts: Dict[str, Contract]) -> None
-```
-
-Add the contracts to the skill.
-
#### skill`_`context
@@ -637,7 +623,7 @@ Get the handlers.
```python
| @classmethod
- | from_dir(cls, directory: str, agent_context: AgentContext) -> "Skill"
+ | from_dir(cls, directory: str, agent_context: AgentContext, **kwargs) -> "Skill"
```
Load the skill from a directory.
@@ -656,7 +642,7 @@ the skill object.
```python
| @property
- | logger() -> Union[Logger, LoggerAdapter]
+ | logger() -> Logger
```
Get the logger.
@@ -679,7 +665,7 @@ Set the logger.
```python
| @classmethod
- | from_config(cls, configuration: SkillConfig, agent_context: AgentContext) -> "Skill"
+ | from_config(cls, configuration: SkillConfig, agent_context: AgentContext, **kwargs) -> "Skill"
```
Load the skill from configuration.
diff --git a/docs/api/skills/tasks.md b/docs/api/skills/tasks.md
index df6d8c9bd9..908cb9976e 100644
--- a/docs/api/skills/tasks.md
+++ b/docs/api/skills/tasks.md
@@ -7,7 +7,7 @@ This module contains the classes for tasks.
## Task Objects
```python
-class Task()
+class Task(WithLogger)
```
This class implements an abstract task.
@@ -70,11 +70,10 @@ Get the result.
#### setup
```python
- | @abstractmethod
| setup() -> None
```
-Implement the behaviour setup.
+Implement the task setup.
**Returns**:
@@ -98,11 +97,10 @@ None
#### teardown
```python
- | @abstractmethod
| teardown() -> None
```
-Implement the behaviour teardown.
+Implement the task teardown.
**Returns**:
@@ -137,7 +135,7 @@ A Task manager.
#### `__`init`__`
```python
- | __init__(nb_workers: int = 1, is_lazy_pool_start: bool = True)
+ | __init__(nb_workers: int = 1, is_lazy_pool_start: bool = True, logger: Optional[logging.Logger] = None)
```
Initialize the task manager.
diff --git a/docs/aries-cloud-agent-demo.md b/docs/aries-cloud-agent-demo.md
index 46b06c199a..22e49d79f4 100644
--- a/docs/aries-cloud-agent-demo.md
+++ b/docs/aries-cloud-agent-demo.md
@@ -24,7 +24,7 @@ The aim of this demo is to illustrate how AEAs can connect to ACAs, thus gaining
activate aaca
activate aaea
- Note right of aaea: Shows identity
+ Note right of aaea: Shows p2p ID
faea->>faca: Request status?
faca->>faea: status
@@ -54,8 +54,10 @@ Each AEA is connected to its corresponding ACA: **Alice_AEA** to **Alice_ACA** a
The following lists the sequence of interactions between the four agents:
* **Alice_AEA**: starts
- * **Alice_AEA**: shows its identity in the terminal and waits for an `invitation` detail from **Faber_AEA**.
+ * **Alice_AEA**: shows its p2p address in the terminal and waits for an `invitation` detail from **Faber_AEA**.
+ * **Alice_AEA**: registers itself on the SOEF.
* **Faber_AEA**: starts
+ * **Faber_AEA**: searches the SOEF and finds **Alice_AEA**.
* **Faber_AEA**: tests its connection to **Faber_ACA**.
* **Faber_ACA**: responds to **Faber_AEA**.
* **Faber_AEA**: requests **Faber_ACA** to create an invitation.
@@ -66,11 +68,11 @@ The following lists the sequence of interactions between the four agents:
All messages from an AEA to an ACA are http requests (using `http_client` connection).
-All messages from an AEA to another AEA utilise the `oef` communication network accessed via the `oef` connection.
+All messages from an AEA to another AEA utilise the p2p communication network accessed via the `p2p_libp2p` connection.
All messages initiated from an ACA to an AEA are webhooks (using `webhook` connection).
-This is the extent of the demo, at this point. The rest of the interactions require an instance of the Indy ledger to run. This is what will be implemented next.
+This is the extent of the demo at this point. The rest of the interactions require an instance of the Indy ledger to run. This is what will be implemented next.
The rest of the interactions are broadly as follows:
@@ -146,105 +148,49 @@ Again, make sure the above ports are unused and take note of the specific IP add
Now you can create **Alice_AEA** and **Faber_AEA** in terminals 3 and 4 respectively.
-There are two methods for creating each AEA, constructing it piece by piece, or fetching the whole agent project.
+### Alice_AEA
-### Alice_AEA -- Method 1: Construct the Agent
-
-In the third terminal, create **Alice_AEA** and move into its project folder:
+In the third terminal, fetch **Alice_AEA** and move into its project folder:
``` bash
-aea create aries_alice
+aea fetch fetchai/aries_alice:0.7.0
cd aries_alice
```
-#### Add and Configure the Skill
-
-Add the `aries_alice` skill:
-
-``` bash
-aea add skill fetchai/aries_alice:0.3.0
-```
-
-You now need to configure this skill to ensure `admin_host` and `admin_port` values in the skill's configuration file `alice/vendor/fetchai/skills/aries_alice/skill.yaml` match with the values you noted above for **Alice_ACA**.
-
-You can use the framework's handy `config` CLI command to set these values:
-
-``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_port 8031
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_port 8031
-```
-
-#### Add and Configure the Connections
-
-Add `http_client`, `oef` and `webhook` connections:
-
-``` bash
-aea add connection fetchai/http_client:0.5.0
-aea add connection fetchai/webhook:0.4.0
-aea add connection fetchai/oef:0.6.0
-```
-
-You now need to configure the `webhook` connection.
-
-First is ensuring the value of `webhook_port` in `webhook` connection's configuration file `alice/vendor/fetchai/connections/webhook/connection.yaml` matches with what you used above for **Alice_ACA**.
-
-``` bash
-aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032
-```
-
-Next, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`.
-
-``` bash
-aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
-```
-
-#### Configure Alice_AEA:
-
-Now you must ensure **Alice_AEA**'s default connection is `oef`.
-
-``` bash
-aea config set agent.default_connection fetchai/oef:0.6.0
-```
-
-### Alice_AEA -- Method 2: Fetch the Agent
-
-Alternatively, in the third terminal, fetch **Alice_AEA** and move into its project folder:
+Alternatively, create from scratch.
+
+The following steps create **Alice_AEA** from scratch:
``` bash
-aea fetch fetchai/aries_alice:0.6.0
+aea create aries_alice
cd aries_alice
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/http_client:0.6.0
+aea add connection fetchai/webhook:0.5.0
+aea add skill fetchai/aries_alice:0.4.0
```
+
+
-#### Configure the skill and connections:
+#### Configure the `aries_alice` skill:
-You need to configure the `aries_alice` skill of the AEA to ensure `admin_host` and `admin_port` values in the skill's configuration file `alice/vendor/fetchai/skills/aries_alice/skill.yaml` match with the values you noted above for **Alice_ACA**.
+(configuration file: `alice/vendor/fetchai/skills/aries_alice/skill.yaml`)
-You can use the framework's handy `config` CLI command to set these values:
+Ensure `admin_host` and `admin_port` values match with the values you noted above for **Alice_ACA**. You can use the framework's handy `config` CLI command to set these values:
``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_host 127.0.0.1
+aea config set vendor.fetchai.skills.aries_alice.behaviours.alice.args.admin_host 127.0.0.1
```
``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_port 8031
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_port 8031
+aea config set --type int vendor.fetchai.skills.aries_alice.behaviours.alice.args.admin_port 8031
```
-You now need to configure the `webhook` connection.
+#### Configure the `webhook` connection:
+
+(configuration file: `alice/vendor/fetchai/connections/webhook/connection.yaml`).
-First is ensuring the value of `webhook_port` in `webhook` connection's configuration file `alice/vendor/fetchai/connections/webhook/connection.yaml` matches with what you used above for **Alice_ACA**.
+First ensure the value of `webhook_port` matches with what you used above for **Alice_ACA**.
``` bash
aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032
@@ -258,7 +204,7 @@ aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webho
### Install the Dependencies and Run Alice_AEA:
-After creating **Alice_AEA** using either of the methods above, you must install all the dependencies:
+Now install all the dependencies:
``` bash
aea install
@@ -270,67 +216,52 @@ Finally run **Alice_AEA**:
aea run
```
-You should see **Alice_AEA** running and showing its identity on the terminal. For example:
-
-``` bash
-My address is: YrP7H2qdCb3VyPwpQa53o39cWCDHhVcjwCtJLes6HKWM8FpVK
-```
-
-Take note of this value. We will refer to this as **Alice_AEA's address**.
+Once you see a message of the form `My libp2p addresses: ['SOME_ADDRESS']` take note of the address. We will refer to this as **Alice_AEA's p2p address**.
-### Faber_AEA -- Method 1: Construct the Agent
+### Faber_AEA
-In the fourth terminal, create **Faber_AEA** and move into its project folder:
+In the fourth terminal, fetch **Faber_AEA** and move into its project folder:
``` bash
-aea create aries_faber
+aea fetch fetchai/aries_faber:0.7.0
cd aries_faber
```
-#### Add and Configure the Skill:
-
-Add the `aries_faber` skill:
+Alternatively, create from scratch.
+
+The following steps create **Faber_AEA** from scratch:
``` bash
+aea create aries_faber
+cd aries_faber
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/http_client:0.6.0
+aea add connection fetchai/webhook:0.5.0
aea add skill fetchai/aries_faber:0.3.0
```
-You now need to configure this skill to ensure `admin_host` and `admin_port` values in the skill's configuration file `faber/vendor/fetchai/skills/aries_alice/skill.yaml` match with the values you noted above for **Faber_ACA**.
+
+
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_host 127.0.0.1
-```
+#### Configure the `aries_faber` skill:
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
+(configuration file: `faber/vendor/fetchai/skills/aries_alice/skill.yaml`)
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_port 8021
-```
+Ensure `admin_host` and `admin_port` values match with those you noted above for **Faber_ACA**.
``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_port 8021
+aea config set vendor.fetchai.skills.aries_faber.behaviours.faber.args.admin_host 127.0.0.1
```
-Additionally, make sure that the value of `alice_id` matches **Alice_AEA's address** as displayed in the third terminal.
-
``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.alice_id
+aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.faber.args.admin_port 8021
```
-#### Add and Configure the Connections:
-
-Add `http_client`, `oef` and `webhook` connections:
+#### Configure the `webhook` connection:
-``` bash
-aea add connection fetchai/http_client:0.5.0
-aea add connection fetchai/webhook:0.4.0
-aea add connection fetchai/oef:0.6.0
-```
+(configuration file: `faber/vendor/fetchai/connections/webhook/connection.yaml`).
-You now need to configure the `webhook` connection.
-
-First is ensuring the value of `webhook_port` in `webhook` connection's configuration file `faber/vendor/fetchai/connections/webhook/connection.yaml` matches with what you used above for **Faber_ACA**.
+First, ensure the value of `webhook_port` matches with what you used above for **Faber_ACA**.
``` bash
aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022
@@ -342,66 +273,26 @@ Next, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`.
aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
```
-#### Configure Faber_AEA:
-
-Now you must ensure **Faber_AEA**'s default connection is `http_client`.
-
-``` bash
-aea config set agent.default_connection fetchai/http_client:0.5.0
-```
+#### Configure the `p2p_libp2p` connection:
-### Alice_AEA -- Method 2: Fetch the Agent
+(configuration file: `vendor/fetchai/connections/p2p_libp2p/connection.yaml`)
-Alternatively, in the fourth terminal, fetch **Faber_AEA** and move into its project folder:
+Replace the `config` section with the following (note the changes in the URIs):
-``` bash
-aea fetch fetchai/aries_faber:0.6.0
-cd aries_faber
+``` yaml
+config:
+ delegate_uri: 127.0.0.1:11001
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9001
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9001
```
-#### Configure the skill and connections:
-
-You need to configure the `aries_faber` skill of the AEA to ensure `admin_host` and `admin_port` values in the skill's configuration file `faber/vendor/fetchai/skills/aries_alice/skill.yaml` match with the values you noted above for **Faber_ACA**.
-
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_host 127.0.0.1
-```
-
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_port 8021
-```
-
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_port 8021
-```
-
-Additionally, make sure that the value of `alice_id` matches **Alice_AEA's address** as displayed in the third terminal.
-
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.alice_id
-```
-
-You now need to configure the `webhook` connection.
-
-First is ensuring the value of `webhook_port` in `webhook` connection's configuration file `faber/vendor/fetchai/connections/webhook/connection.yaml` matches with what you used above for **Faber_ACA**.
-
-``` bash
-aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022
-```
-
-Next, make sure the value of `webhook_url_path` is `/webhooks/topic/{topic}/`.
-
-``` bash
-aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
-```
+where `SOME_ADDRESS` is **Alice_AEA's p2p address** as displayed in the third terminal.
### Install the Dependencies and Run Faber_AEA:
-After creating **Faber_AEA** using either of the methods above, you must install all the dependencies:
+Now install all the dependencies:
``` bash
aea install
diff --git a/docs/assets/aries-demo-alice.png b/docs/assets/aries-demo-alice.png
index fa6fc2c081..e2b431fd77 100644
Binary files a/docs/assets/aries-demo-alice.png and b/docs/assets/aries-demo-alice.png differ
diff --git a/docs/assets/aries-demo-faber.png b/docs/assets/aries-demo-faber.png
index 019c4e3d59..3fb6fa88e8 100644
Binary files a/docs/assets/aries-demo-faber.png and b/docs/assets/aries-demo-faber.png differ
diff --git a/docs/build-aea-programmatically.md b/docs/build-aea-programmatically.md
index 06693b080c..c77fd8ebd0 100644
--- a/docs/build-aea-programmatically.md
+++ b/docs/build-aea-programmatically.md
@@ -32,7 +32,7 @@ OUTPUT_FILE = "output_file"
We need a private key to populate the AEA's wallet.
``` python
# Create a private key
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
```
## Clearing the input and output files
@@ -46,7 +46,7 @@ We will use the stub connection to pass envelopes in and out of the AEA. Ensure
```
## Initialise the AEA
-We use the `AEABuilder` to readily build an AEA. By default, the `AEABuilder` adds the `fetchai/default:0.3.0` protocol, the `fetchai/stub:0.6.0` connection and the `fetchai/error:0.3.0` skill.
+We use the `AEABuilder` to readily build an AEA. By default, the `AEABuilder` adds the `fetchai/default:0.4.0` protocol, the `fetchai/stub:0.7.0` connection and the `fetchai/error:0.4.0` skill.
``` python
# Instantiate the builder and build the AEA
# By default, the default protocol, error skill and stub connection are added
@@ -120,7 +120,7 @@ We use the input and output text files to send an envelope to our AEA and receiv
``` python
# Create a message inside an envelope and get the stub connection to pass it on to the echo skill
message_text = (
- "my_aea,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "my_aea,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
@@ -147,8 +147,8 @@ Finally stop our AEA and wait for it to finish
## Running the AEA
If you now run this python script file, you should see this output:
- input message: my_aea,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello
- output message: other_agent,my_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello
+ input message: my_aea,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello
+ output message: other_agent,my_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello
## Entire code listing
@@ -175,7 +175,7 @@ OUTPUT_FILE = "output_file"
def run():
# Create a private key
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
# Ensure the input and output files do not exist initially
if os.path.isfile(INPUT_FILE):
@@ -235,7 +235,7 @@ def run():
# Create a message inside an envelope and get the stub connection to pass it on to the echo skill
message_text = (
- "my_aea,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "my_aea,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
diff --git a/docs/car-park-skills.md b/docs/car-park-skills.md
index 8d5dd97d52..690ecee025 100644
--- a/docs/car-park-skills.md
+++ b/docs/car-park-skills.md
@@ -55,7 +55,7 @@ Follow the Preliminaries and
@@ -89,7 +89,7 @@ default_routing:
Then, fetch the car data client AEA:
``` bash
-aea fetch fetchai/car_data_buyer:0.8.0
+aea fetch fetchai/car_data_buyer:0.9.0
cd car_data_buyer
aea install
```
@@ -101,19 +101,19 @@ The following steps create the car data client from scratch:
``` bash
aea create car_data_buyer
cd car_data_buyer
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/carpark_client:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/carpark_client:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `car_data_buyer/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/docs/cli-how-to.md b/docs/cli-how-to.md
index c636992d9e..ea990b74ac 100644
--- a/docs/cli-how-to.md
+++ b/docs/cli-how-to.md
@@ -2,13 +2,13 @@ The command line interface is the easiest way to build an AEA.
## Installation
-The following installs the AEA cli package.
+The following installs the AEA CLI package.
``` bash
pip install aea[cli]
```
-The following installs the entire AEA package including the cli.
+The following installs the entire AEA package including the CLI.
``` bash
pip install aea[all]
@@ -24,6 +24,19 @@ pip install 'aea[all]'
```
respectively.
+Be sure that the `bin` folder of your Python environment
+is in the `PATH` variable. If so, you can execute the CLI tool as:
+``` bash
+aea
+```
+
+You might find useful the execution of the `aea.cli` package
+as a script:
+``` bash
+python -m aea.cli
+```
+which is just an alternative entry-point to the CLI tool.
+
## Troubleshooting
To ensure no cache is used run.
diff --git a/docs/cli-vs-programmatic-aeas.md b/docs/cli-vs-programmatic-aeas.md
index 52b39017f5..3dc1894262 100644
--- a/docs/cli-vs-programmatic-aeas.md
+++ b/docs/cli-vs-programmatic-aeas.md
@@ -28,7 +28,7 @@ If you want to create the weather station AEA step by step you can follow this g
Fetch the weather station AEA with the following command :
``` bash
-aea fetch fetchai/weather_station:0.8.0
+aea fetch fetchai/weather_station:0.9.0
cd weather_station
```
@@ -92,6 +92,7 @@ SOEF_PORT = 9002
ENTRY_PEER_ADDRESS = (
"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmAzvu5uNbcnD2qaqrkSULhJsc6GJUg3iikWerJkoD72pr"
)
+COSMOS_PRIVATE_KEY_FILE_CONNECTION = "cosmos_connection_private_key.txt"
ROOT_DIR = os.getcwd()
logger = logging.getLogger("aea")
@@ -100,22 +101,25 @@ logging.basicConfig(stream=sys.stdout, level=logging.INFO)
def run():
# Create a private key
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
# Set up the wallet, identity and (empty) resources
wallet = Wallet(
private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
- connection_private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
+ connection_private_key_paths={
+ CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ },
)
identity = Identity("my_aea", address=wallet.addresses.get(CosmosCrypto.identifier))
resources = Resources()
# specify the default routing for some protocols
default_routing = {
- PublicId.from_str("fetchai/ledger_api:0.1.0"): LedgerConnection.connection_id,
- PublicId.from_str("fetchai/oef_search:0.3.0"): SOEFConnection.connection_id,
+ PublicId.from_str("fetchai/ledger_api:0.2.0"): LedgerConnection.connection_id,
+ PublicId.from_str("fetchai/oef_search:0.4.0"): SOEFConnection.connection_id,
}
- default_connection = SOEFConnection.connection_id
+ default_connection = P2PLibp2pConnection.connection_id
# create the AEA
my_aea = AEA(
@@ -180,13 +184,8 @@ def run():
api_key=API_KEY,
soef_addr=SOEF_ADDR,
soef_port=SOEF_PORT,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
- delegate_uri="127.0.0.1:11001",
- entry_peers=[ENTRY_PEER_ADDRESS],
- local_uri="127.0.0.1:9001",
- log_file="libp2p_node.log",
- public_uri="127.0.0.1:9001",
)
soef_connection = SOEFConnection(configuration=configuration, identity=identity)
resources.add_connection(soef_connection)
diff --git a/docs/config.md b/docs/config.md
index ba85de6e24..4acab54abe 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -21,13 +21,13 @@ aea_version: '>=0.5.0, <0.6.0' # AEA framework version(s) compa
fingerprint: {} # Fingerprint of AEA project components.
fingerprint_ignore_patterns: [] # Ignore pattern for the fingerprinting tool.
connections: # The list of connection public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX)
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
contracts: [] # The list of contract public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
protocols: # The list of protocol public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: # The list of skill public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
-- fetchai/error:0.3.0
-default_connection: fetchai/oef:0.6.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).
+- fetchai/error:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).
default_ledger: cosmos # The default ledger identifier the AEA project uses (must satisfy LEDGER_ID_REGEX)
logging_config: # The logging configurations the AEA project uses
disable_existing_loggers: false
diff --git a/docs/connect-a-frontend.md b/docs/connect-a-frontend.md
index 5659b9d3d3..b3e2f13086 100644
--- a/docs/connect-a-frontend.md
+++ b/docs/connect-a-frontend.md
@@ -3,7 +3,7 @@ This demo discusses the options we have to connect a front-end to the AEA. The f
## Case 1
-The first option we have is to create a `Connection` that will handle the incoming requests from the rest API. In this scenario, the rest API communicates with the AEA and requests are handled by the `HTTP Server` Connection package. The rest API should send CRUD requests to the `HTTP Server` Connection (`fetchai/http_server:0.5.0`) which translates these into Envelopes to be consumed by the correct skill.
+The first option we have is to create a `Connection` that will handle the incoming requests from the rest API. In this scenario, the rest API communicates with the AEA and requests are handled by the `HTTP Server` Connection package. The rest API should send CRUD requests to the `HTTP Server` Connection (`fetchai/http_server:0.6.0`) which translates these into Envelopes to be consumed by the correct skill.
## Case 2
-The other option we have is to create a stand-alone `Multiplexer` with an `OEF` connection (`fetchai/oef:0.6.0`). In this scenario, the front-end needs to incorporate a Multiplexer with an `OEF` Connection. Then the [OEF communication node](../oef-ledger) can be used to send Envelopes from the AEA to the front-end.
+The other option we have is to create a stand-alone `Multiplexer` with a `P2P` connection (`fetchai/p2p_libp2p:0.6.0`). In this scenario, the front-end needs to incorporate a Multiplexer with an `P2P` Connection. Then the [Agent Communication Network](../acn) can be used to send Envelopes from the AEA to the front-end.
diff --git a/docs/erc1155-skills.md b/docs/erc1155-skills.md
index 8f5d7132e2..4937da3012 100644
--- a/docs/erc1155-skills.md
+++ b/docs/erc1155-skills.md
@@ -19,14 +19,6 @@ with a one-step atomic swap functionality. That means the trade between the two
This demo serves demonstrative purposes only. Since the AEA deploying the contract also has the ability to mint tokens, in reality the transfer of tokens from the AEA signing the transaction is worthless.
-### Launch an OEF node
-In a separate terminal, launch a local OEF node (for search and discovery).
-``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-
-Keep it running for all the following demos.
-
## Demo
### Create the deployer AEA
@@ -34,7 +26,7 @@ Keep it running for all the following demos.
Fetch the AEA that will deploy the contract.
``` bash
-aea fetch fetchai/erc1155_deployer:0.9.0
+aea fetch fetchai/erc1155_deployer:0.10.0
cd erc1155_deployer
aea install
```
@@ -47,18 +39,20 @@ Create the AEA that will deploy the contract.
``` bash
aea create erc1155_deployer
cd erc1155_deployer
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/erc1155_deploy:0.9.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/erc1155_deploy:0.10.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
Then update the agent config (`aea-config.yaml`) with the default routing:
``` yaml
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
And change the default ledger:
@@ -76,12 +70,18 @@ aea generate-key ethereum
aea add-key ethereum eth_private_key.txt
```
+And one for the P2P connection:
+``` bash
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt --connection
+```
+
### Create the client AEA
In another terminal, fetch the AEA that will get some tokens from the deployer.
``` bash
-aea fetch fetchai/erc1155_client:0.9.0
+aea fetch fetchai/erc1155_client:0.10.0
cd erc1155_client
aea install
```
@@ -94,18 +94,20 @@ Create the AEA that will get some tokens from the deployer.
``` bash
aea create erc1155_client
cd erc1155_client
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/erc1155_client:0.8.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/erc1155_client:0.9.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
Then update the agent config (`aea-config.yaml`) with the default routing:
``` yaml
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
And change the default ledger:
@@ -123,6 +125,12 @@ aea generate-key ethereum
aea add-key ethereum eth_private_key.txt
```
+And one for the P2P connection:
+``` bash
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt --connection
+```
+
### Fund the AEAs
To create some wealth for your AEAs for the Ethereum `ropsten` network. Note that this needs to be executed from each AEA folder:
@@ -142,6 +150,14 @@ aea get-wealth ethereum
If no wealth appears after a while, then try funding the private key directly using a web faucet.
+
+## Update SOEF configs for both AEAs
+
+To update the SOEF config, run in each AEA project:
+``` bash
+aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum
+```
+
## Run the AEAs
First, run the deployer AEA.
diff --git a/docs/generic-skills-step-by-step.md b/docs/generic-skills-step-by-step.md
index dba6e941d1..a1106ac01b 100644
--- a/docs/generic-skills-step-by-step.md
+++ b/docs/generic-skills-step-by-step.md
@@ -41,16 +41,16 @@ Follow the Preliminaries and MetaMask Faucet and reques
Run both AEAs from their respective terminals.
``` bash
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea run
```
diff --git a/docs/generic-skills.md b/docs/generic-skills.md
index 04f67b8662..30b1fa258c 100644
--- a/docs/generic-skills.md
+++ b/docs/generic-skills.md
@@ -59,7 +59,7 @@ Follow the Preliminaries and
@@ -93,7 +93,7 @@ default_routing:
Then, fetch the buyer AEA:
``` bash
-aea fetch fetchai/generic_buyer:0.5.0 --alias my_buyer_aea
+aea fetch fetchai/generic_buyer:0.6.0 --alias my_buyer_aea
cd my_buyer_aea
aea install
```
@@ -105,19 +105,19 @@ The following steps create the buyer from scratch:
``` bash
aea create my_buyer_aea
cd my_buyer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/generic_buyer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/generic_buyer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_buyer_aea/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/docs/gym-skill.md b/docs/gym-skill.md
index 503784d838..ff193cbbdc 100644
--- a/docs/gym-skill.md
+++ b/docs/gym-skill.md
@@ -19,7 +19,7 @@ Follow the Preliminaries and None:
@@ -120,7 +117,7 @@ class HttpHandler(Handler):
bodyy=json.dumps({"tom": {"type": "cat", "age": 10}}).encode("utf-8"),
)
self.context.logger.info(
- "[{}] responding with: {}".format(self.context.agent_name, http_response)
+ "responding with: {}".format(http_response)
)
http_response.counterparty = http_msg.counterparty
self.context.outbox.put_message(message=http_response)
@@ -144,7 +141,7 @@ class HttpHandler(Handler):
bodyy=b"",
)
self.context.logger.info(
- "[{}] responding with: {}".format(self.context.agent_name, http_response)
+ "responding with: {}".format(http_response)
)
http_response.counterparty = http_msg.counterparty
self.context.outbox.put_message(message=http_response)
@@ -169,7 +166,7 @@ handlers:
Finally, we run the fingerprinter:
``` bash
-aea fingerprint skill fetchai/http_echo:0.3.0
+aea fingerprint skill fetchai/http_echo:0.4.0
```
Note, you will have to replace the author name with your author handle.
diff --git a/docs/index.md b/docs/index.md
index 0fb637039d..0924c12825 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -18,7 +18,7 @@ Autonomous Economic Agents are digital entities that run complex dynamic decisio
AEAs are not:
-* just any agents: AEAs have an express purpose to generate economic value.
+* just any agents: AEAs have an express purpose to generate economic value in a multi-stakeholder environment.
* APIs or sensors which do not have agency.
* smart contracts which do not display any proactiveness and are purely reactive to external requests (=contract calls).
* artificial general intelligence (AGI): AEAs can have a very narrow goal directed focus involving some economic gain and implemented via simple conditional logic.
diff --git a/docs/language-agnostic-definition.md b/docs/language-agnostic-definition.md
index b362045fda..5cec1d2406 100644
--- a/docs/language-agnostic-definition.md
+++ b/docs/language-agnostic-definition.md
@@ -104,7 +104,7 @@ message DefaultMessage{
It is recommended that it processes `Envelopes` asynchronously. Note, the specification regarding the processing of messages does not impose any particular implementation choice/constraint; for example, the AEA can process envelopes either synchronously and asynchronously. However, due to the high level of activity that an AEA might be subject to, other AEAs expect a certain minimum level of responsiveness and reactivity of an AEA's implementation, especially in the case of many concurrent dialogues with other peers. That could imply the need for asynchronous programming to make the AEA's implementation scalable.
- It MUST have an identity in the form of, at a minimum, an address derived from a public key and its associated private key.
+ It MUST have an identity in the form of, at a minimum, an address derived from a public key and its associated private key (where the eliptic curve must be of type SECP256k1).
It SHOULD implement handling of errors using the `default` protocol. The protobuf schema is given above.
diff --git a/docs/logging.md b/docs/logging.md
index 432b1397be..9c2ac79ffd 100644
--- a/docs/logging.md
+++ b/docs/logging.md
@@ -18,17 +18,17 @@ author: fetchai
version: 0.1.0
description: ''
license: Apache-2.0
-aea_version: 0.5.2
+aea_version: 0.5.3
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills:
-- fetchai/error:0.3.0
-default_connection: fetchai/stub:0.6.0
+- fetchai/error:0.4.0
+default_connection: fetchai/stub:0.7.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/docs/ml-skills.md b/docs/ml-skills.md
index 087f76a5c2..fb75872311 100644
--- a/docs/ml-skills.md
+++ b/docs/ml-skills.md
@@ -62,7 +62,7 @@ Follow the Preliminaries and
@@ -96,7 +96,7 @@ default_routing:
Then, fetch the model trainer AEA:
``` bash
-aea fetch fetchai/ml_model_trainer:0.8.0
+aea fetch fetchai/ml_model_trainer:0.9.0
cd ml_model_trainer
aea install
```
@@ -108,19 +108,19 @@ The following steps create the model trainer from scratch:
``` bash
aea create ml_model_trainer
cd ml_model_trainer
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/ml_train:0.7.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/ml_train:0.8.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea install
```
In `ml_model_trainer/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/docs/multiplexer-standalone.md b/docs/multiplexer-standalone.md
index 664ba6b514..59b47e0971 100644
--- a/docs/multiplexer-standalone.md
+++ b/docs/multiplexer-standalone.md
@@ -60,7 +60,7 @@ We use the input and output text files to send an envelope to our agent and rece
``` python
# Create a message inside an envelope and get the stub connection to pass it into the multiplexer
message_text = (
- "multiplexer,some_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "multiplexer,some_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
@@ -155,7 +155,7 @@ def run():
# Create a message inside an envelope and get the stub connection to pass it into the multiplexer
message_text = (
- "multiplexer,some_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "multiplexer,some_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
diff --git a/docs/oef-ledger.md b/docs/oef-ledger.md
index cad6d88126..2efd676972 100644
--- a/docs/oef-ledger.md
+++ b/docs/oef-ledger.md
@@ -21,7 +21,7 @@ The latter will be decentralized over time.
### Agent Communication Network (ACN)
-The agent communication network is a peer-to-peer communication network for agents. It allows agents, in particular AEAs, to send and receive envelopes between each other.
+The agent communication network is a peer-to-peer communication network for agents. It allows agents, in particular AEAs, to send and receive envelopes between each other.
The implementation builds on the open-source libp2p library. A distributed hash table is used by all participating peers to maintain a mapping between agents' cryptographic addresses and their network addresses.
@@ -33,9 +33,7 @@ A `simple OEF search node` allows agents to search a
For two agents to be able to find each other, at least one must register themselves and the other must query the `simple OEF search node` for it. Detailed documentation is provided `here`.
-### Deprecated alternative (for local development only)
-
-Click here for a local development alternative.
+
## Ledgers
@@ -72,3 +94,5 @@ The Python version of the AEA Framework currently integrates with three ledgers:
- [Fetch.ai ledger](https://docs.fetch.ai/ledger/)
- [Ethereum ledger](https://ethereum.org/build/)
- [Cosmos ledger](https://cosmos.network/sdk)
+
+However, the framework makes it straightforward for further ledgers to be added by any developer.
diff --git a/docs/orm-integration.md b/docs/orm-integration.md
index 2716ff6a84..2b2a7da3d6 100644
--- a/docs/orm-integration.md
+++ b/docs/orm-integration.md
@@ -59,7 +59,7 @@ A demo to run a scenario with a true ledger transaction on Fetch.ai `testnet` ne
First, fetch the seller AEA, which will provide data:
``` bash
-aea fetch fetchai/thermometer_aea:0.6.0 --alias my_thermometer_aea
+aea fetch fetchai/thermometer_aea:0.7.0 --alias my_thermometer_aea
cd my_thermometer_aea
aea install
```
@@ -71,19 +71,19 @@ The following steps create the seller from scratch:
``` bash
aea create my_thermometer_aea
cd my_thermometer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_thermometer_aea/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
@@ -94,7 +94,7 @@ default_routing:
In another terminal, fetch the AEA that will query the seller AEA.
``` bash
-aea fetch fetchai/thermometer_client:0.6.0 --alias my_thermometer_client
+aea fetch fetchai/thermometer_client:0.7.0 --alias my_thermometer_client
cd my_thermometer_client
aea install
```
@@ -106,19 +106,19 @@ The following steps create the car data client from scratch:
``` bash
aea create my_thermometer_client
cd my_thermometer_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_buyer_aea/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
@@ -214,7 +214,7 @@ aea install
Before being able to modify a package we need to eject it from vendor:
``` bash
-aea eject skill fetchai/thermometer:0.7.0
+aea eject skill fetchai/thermometer:0.8.0
```
This will move the package to your `skills` directory and reset the version to `0.1.0` and the author to your author handle.
diff --git a/docs/p2p-connection.md b/docs/p2p-connection.md
index e216500117..fd2c5deeea 100644
--- a/docs/p2p-connection.md
+++ b/docs/p2p-connection.md
@@ -1,4 +1,4 @@
-The `fetchai/p2p_libp2p:0.5.0` connection allows AEAs to create a peer-to-peer communication network. In particular, the connection creates an overlay network which maps agents' public keys to IP addresses.
+The `fetchai/p2p_libp2p:0.6.0` connection allows AEAs to create a peer-to-peer communication network. In particular, the connection creates an overlay network which maps agents' public keys to IP addresses.
## Local demo
@@ -9,9 +9,9 @@ Create one AEA as follows:
``` bash
aea create my_genesis_aea
cd my_genesis_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
-aea run --connections fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea run --connections fetchai/p2p_libp2p:0.6.0
```
###Â Create and run another AEA
@@ -21,8 +21,8 @@ Create a second AEA:
``` bash
aea create my_other_aea
cd my_other_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
Provide the AEA with the information it needs to find the genesis by replacing the following block in `vendor/fetchai/connnections/p2p_libp2p/connection.yaml`:
@@ -40,7 +40,7 @@ Here `MULTI_ADDRESSES` needs to be replaced with the list of multi addresses dis
Run the AEA:
``` bash
-aea run --connections fetchai/p2p_libp2p:0.5.0
+aea run --connections fetchai/p2p_libp2p:0.6.0
```
You can inspect the `libp2p_node.log` log files of the AEA to see how they discover each other.
@@ -48,78 +48,7 @@ You can inspect the `libp2p_node.log` log files of the AEA to see how they disco
## Local demo with skills
-### Fetch the weather station and client
-
-Create one AEA as follows:
-
-``` bash
-aea fetch fetchai/weather_station:0.8.0
-aea fetch fetchai/weather_client:0.8.0
-```
-
-Then enter each project individually and execute the following to add the `p2p_libp2p` connection:
-``` bash
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
-```
-
-Then extend the `aea-config.yaml` of each project as follows:
-``` yaml
-default_routing:
- ? "fetchai/oef_search:0.3.0"
- : "fetchai/oef:0.6.0"
-```
-###Â Run OEF
-
-Run the oef for search and discovery:
-``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-
-### Run weather station
-
-Run the weather station first:
-``` bash
-aea run --connections "fetchai/p2p_libp2p:0.5.0,fetchai/oef:0.6.0"
-```
-The weather station will form the genesis node. Wait until you see the lines:
-``` bash
-My libp2p addresses: ...
-```
-Take note of these as the genesis' `MULTI_ADDRESSES = ["{addr1}", "{addr2}"]`.
-
-### Generate wealth for the weather client AEA
-
-The weather client needs to have some wealth to purchase the weather station information.
-
-First, create the private key for the weather client AEA based on the network you want to transact. To generate and add a private-public key pair for Fetch.ai use:
-``` bash
-aea generate-key fetchai
-aea add-key fetchai fet_private_key.txt
-```
-
-Then, create some wealth for your weather client based on the network you want to transact with. On the Fetch.ai `testnet` network:
-``` bash
-aea generate-wealth fetchai
-```
-
-### Run the weather client
-
-Provide the weather client AEA with the information it needs to find the genesis by adding the following block to `vendor/fetchai/connnections/p2p_libp2p/connection.yaml`:
-``` yaml
-config:
- delegate_uri: 127.0.0.1:11001
- entry_peers: MULTI_ADDRESSES
- local_uri: 127.0.0.1:9001
- log_file: libp2p_node.log
- public_uri: 127.0.0.1:9001
-```
-Here `MULTI_ADDRESSES` needs to be replaced with the list of multi addresses displayed in the log output of the weather station AEA.
-
-Now run the weather client:
-``` bash
-aea run --connections "fetchai/p2p_libp2p:0.5.0,fetchai/oef:0.6.0"
-```
+Explore the demo section for further examples.
## Deployed agent communication network
diff --git a/docs/package-imports.md b/docs/package-imports.md
index 09b25cd1a5..63b8e02088 100644
--- a/docs/package-imports.md
+++ b/docs/package-imports.md
@@ -47,7 +47,7 @@ The `aea-config.yaml` is the top level configuration file of an AEA. It defines
For the AEA to use a package, the `public_id` for the package must be listed in the `aea-config.yaml` file, e.g.
``` yaml
connections:
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
```
The above shows a part of the `aea-config.yaml`. If you see the connections, you will see that we follow a pattern of `author/name_package:version` to identify each package, also referred to as `public_id`. Here the `author` is the author of the package.
diff --git a/docs/protocol.md b/docs/protocol.md
index 8fa534845a..5191af75d2 100644
--- a/docs/protocol.md
+++ b/docs/protocol.md
@@ -66,9 +66,9 @@ The developer can generate custom protocols with the generic skills step by step guide.
+For examples of the usage of the `fetchai/fipa:0.5.0` protocol check out the generic skills step by step guide.
### Fipa dialogue
diff --git a/docs/questions-and-answers.md b/docs/questions-and-answers.md
index 7dd4842d34..ddb0638b96 100644
--- a/docs/questions-and-answers.md
+++ b/docs/questions-and-answers.md
@@ -72,7 +72,7 @@ You can find more details about the CLI commands here
When a new AEA is created, is the `vendor` folder populated with some default packages?
-All AEA projects by default hold the `fetchai/stub:0.6.0` connection, the `fetchai/default:0.3.0` protocol and the `fetchai/error:0.3.0` skill. These (as all other packages installed from the registry) are placed in the vendor's folder.
+All AEA projects by default hold the `fetchai/stub:0.7.0` connection, the `fetchai/default:0.4.0` protocol and the `fetchai/error:0.4.0` skill. These (as all other packages installed from the registry) are placed in the vendor's folder.
You can find more details about the file structure here
@@ -86,3 +86,7 @@ By default, envelopes of a given protocol get routed to all skills which have a
The `URI` in the `EnvelopeContext` can be used to route envelopes of a given protocol to a specific skill. The `URI` path needs to be set to the skill's `public_id.to_uri_path`.
+
+Why does the AEA framework use its own package registry?
+AEA packages could be described as personalized plugins for the AEA runtime. They are not like a library and therefore not suitable for distribution via PyPI.
+
diff --git a/docs/quickstart.md b/docs/quickstart.md
index 5d2f9af968..d5e86fa734 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -5,6 +5,12 @@ you can use the Fetch.ai AEA framework.
This example will take you through the simplest AEA in order to make you familiar with the framework.
+## System Requirements
+
+The AEA framework can be used on `Windows`, `Ubuntu/Debian` and `MacOS`.
+
+You need Python 3.6 or higher as well as Go 1.14.2 or higher installed.
+
## Preliminaries
Create and enter into a new working directory.
@@ -30,30 +36,6 @@ Once installed, create a new environment and open it (here we use Python 3.7 but
touch Pipfile && pipenv --python 3.7 && pipenv shell
```
-### Installing docker
-
-
-
Note
-
For the purpose of the quickstart only, you can skip installation of docker.
-
-
-At some point, you will need [Docker](https://www.docker.com/) installed on your machine
-(e.g. to run an [OEF search and communication node](../oef-ledger)).
-
-### Download the scripts and examples directories
-
-
-
Note
-
For the purpose of the quickstart only, you can skip downloading the scripts and examples directories.
-
-
-Download folders containing examples and scripts:
-``` bash
-svn export https://github.com/fetchai/agents-aea.git/trunk/examples
-svn export https://github.com/fetchai/agents-aea.git/trunk/scripts
-```
-You can install the `svn` command with (`brew install subversion` or `sudo apt-get install subversion`).
-
## Installation
The following installs the entire AEA package which also includes a [command-line interface (CLI)](../cli-commands).
@@ -104,7 +86,7 @@ Confirm password:
/ ___ \ | |___ / ___ \
/_/ \_\|_____|/_/ \_\
-v0.5.2
+v0.5.3
AEA configurations successfully initialized: {'author': 'fetchai'}
```
@@ -121,7 +103,7 @@ The echo skill is a simple demo that introduces you to the main business logic c
If you want to follow a step by step guide we show you how to do it at the end of the file.
``` bash
-aea fetch fetchai/my_first_aea:0.7.0
+aea fetch fetchai/my_first_aea:0.8.0
cd my_first_aea
```
@@ -141,9 +123,9 @@ cd my_first_aea
Second, add the echo skill to the project.
``` bash
-aea add skill fetchai/echo:0.3.0
+aea add skill fetchai/echo:0.4.0
```
-This copies the `fetchai/echo:0.3.0` skill code containing the "behaviours", and "handlers" into the project, ready to run. The identifier of the skill `fetchai/echo:0.3.0` consists of the name of the author of the skill, followed by the skill name and its version.
+This copies the `fetchai/echo:0.4.0` skill code containing the "behaviours", and "handlers" into the project, ready to run. The identifier of the skill `fetchai/echo:0.4.0` consists of the name of the author of the skill, followed by the skill name and its version.
## Usage of the stub connection
@@ -165,12 +147,12 @@ TO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE,
For example:
``` bash
-recipient_aea,sender_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,
+recipient_aea,sender_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,
```
## Run the AEA
-Run the AEA with the default `fetchai/stub:0.6.0` connection.
+Run the AEA with the default `fetchai/stub:0.7.0` connection.
``` bash
aea run
@@ -179,7 +161,7 @@ aea run
or
``` bash
-aea run --connections fetchai/stub:0.6.0
+aea run --connections fetchai/stub:0.7.0
```
You will see the echo skill running in the terminal window.
@@ -191,7 +173,7 @@ You will see the echo skill running in the terminal window.
/ ___ \ | |___ / ___ \
/_/ \_\|_____|/_/ \_\
-v0.5.2
+v0.5.3
Starting AEA 'my_first_aea' in 'async' mode ...
info: Echo Handler: setup method called.
@@ -212,7 +194,7 @@ Let's look at the `Handler` in more depth.
From a different terminal and same directory, we send the AEA a message wrapped in an envelope via the input file.
``` bash
-echo 'my_first_aea,sender_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,' >> input_file
+echo 'my_first_aea,sender_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,' >> input_file
```
You will see the `Echo Handler` dealing with the envelope and responding with the same message to the `output_file`, and also decoding the Base64 encrypted message in this case.
diff --git a/docs/simple-oef-usage.md b/docs/simple-oef-usage.md
index 005d2322d7..6b94e5ab88 100644
--- a/docs/simple-oef-usage.md
+++ b/docs/simple-oef-usage.md
@@ -1,12 +1,12 @@
You can use the SOEF in the agent framework by using the SOEF connection as a package in your agent project.
## Add the SOEF package
-Check out the CLI guide on details how to add a connection. You will want to add the `fetchai/soef:0.5.0` connection package.
+Check out the CLI guide on details how to add a connection. You will want to add the `fetchai/soef:0.6.0` connection package.
## Register your agent and its services
### Register agent location
-To register your agent's location, you have to send a message in the `fetchai/oef_search:0.3.0` protocol to the SOEF connection.
+To register your agent's location, you have to send a message in the `fetchai/oef_search:0.4.0` protocol to the SOEF connection.
First, define a data model for location data:
``` python
diff --git a/docs/skill-guide.md b/docs/skill-guide.md
index 80015abed6..3ad7e58088 100644
--- a/docs/skill-guide.md
+++ b/docs/skill-guide.md
@@ -70,7 +70,7 @@ class MySearchBehaviour(TickerBehaviour):
:return: None
"""
self.context.logger.info(
- "[{}]: setting up MySearchBehaviour".format(self.context.agent_name)
+ "setting up MySearchBehaviour"
)
def act(self) -> None:
@@ -89,8 +89,8 @@ class MySearchBehaviour(TickerBehaviour):
query=self.query,
)
self.context.logger.info(
- "[{}]: sending search request to OEF search node, search_count={}".format(
- self.context.agent_name, self.sent_search_count
+ "sending search request to OEF search node, search_count={}".format(
+ self.sent_search_count
)
)
search_request.counterparty = self.context.search_service_address
@@ -104,7 +104,7 @@ class MySearchBehaviour(TickerBehaviour):
:return: None
"""
self.context.logger.info(
- "[{}]: tearing down MySearchBehaviour".format(self.context.agent_name)
+ "tearing down MySearchBehaviour"
)
```
@@ -144,7 +144,7 @@ class MySearchHandler(Handler):
def setup(self) -> None:
"""Set up the handler."""
self.context.logger.info(
- "[{}]: setting up MySearchHandler".format(self.context.agent_name)
+ "setting up MySearchHandler"
)
def handle(self, message: Message) -> None:
@@ -215,13 +215,12 @@ class MySearchHandler(Handler):
self.received_search_count += 1
nb_agents_found = len(oef_search_msg.agents)
self.context.logger.info(
- "[{}]: found number of agents={}, received search count={}".format(
- self.context.agent_name, nb_agents_found, self.received_search_count
+ "found number of agents={}, received search count={}".format(
+ nb_agents_found, self.received_search_count
)
)
self.context.logger.info(
- "[{}]: number of search requests sent={} vs. number of search responses received={}".format(
- self.context.agent_name,
+ "number of search requests sent={} vs. number of search responses received={}".format(
self.context.behaviours.my_search_behaviour.sent_search_count,
self.received_search_count,
)
@@ -250,7 +249,7 @@ class MySearchHandler(Handler):
:return: None
"""
self.context.logger.info(
- "[{}]: tearing down MySearchHandler".format(self.context.agent_name)
+ "tearing down MySearchHandler"
)
```
@@ -341,7 +340,7 @@ fingerprint: {}
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
my_search_behaviour:
@@ -385,23 +384,23 @@ Ensure, you use the correct author name to reference your skill (here we use `fe
Our AEA does not have the oef protocol yet so let's add it.
``` bash
-aea add protocol fetchai/oef_search:0.3.0
+aea add protocol fetchai/oef_search:0.4.0
```
This adds the protocol to our AEA and makes it available on the path `packages.fetchai.protocols...`.
We also need to add the soef and p2p connections and install the AEA's dependencies:
``` bash
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
Finally, in the `aea-config.yaml` add the following lines:
``` yaml
default_routing:
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
This will ensure that search requests are processed by the correct connection.
@@ -410,7 +409,7 @@ This will ensure that search requests are processed by the correct connection.
In order to be able to find another AEA when searching, from a different terminal window, we fetch another finished AEA:
``` bash
-aea fetch fetchai/simple_service_registration:0.8.0 && cd simple_service_registration
+aea fetch fetchai/simple_service_registration:0.9.0 && cd simple_service_registration
```
This AEA will simply register a location service on the [SOEF search node](../simple-oef) so we can search for it.
@@ -713,7 +712,7 @@ from packages.fetchai.skills.simple_service_registration.dialogues import (
OefSearchDialogues,
)
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class OefSearchHandler(Handler):
@@ -822,7 +821,7 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
service:
diff --git a/docs/skill.md b/docs/skill.md
index 2e61b90d6b..bb5214712a 100644
--- a/docs/skill.md
+++ b/docs/skill.md
@@ -57,6 +57,13 @@ A handler can be registered in one way:
- By declaring it in the skill configuration file `skill.yaml` (see [below](#skill-config))
+It is possible to register new handlers dynamically by enqueuing new
+`Handler` instances in the queue `context.new_handlers`, e.g. in a skill
+component we can write:
+
+``` python
+self.context.new_handlers.put(MyHandler(name="my_handler", skill_context=self.context))
+```
### `behaviours.py`
@@ -255,7 +262,7 @@ handlers:
models: {}
dependencies: {}
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
```
@@ -268,7 +275,7 @@ All AEAs have a default `error` skill that contains error handling code for a nu
* Envelopes with decoding errors
* Invalid messages with respect to the registered protocol
-The error skill relies on the `fetchai/default:0.3.0` protocol which provides error codes for the above.
+The error skill relies on the `fetchai/default:0.4.0` protocol which provides error codes for the above.
diff --git a/docs/standalone-transaction.md b/docs/standalone-transaction.md
index 93025d0028..8f57ad2a70 100644
--- a/docs/standalone-transaction.md
+++ b/docs/standalone-transaction.md
@@ -7,7 +7,7 @@ import logging
from aea.crypto.cosmos import CosmosCrypto
from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth
-from aea.crypto.ledger_apis import DEFAULT_LEDGER_CONFIGS, LedgerApis
+from aea.crypto.ledger_apis import LedgerApis
from aea.crypto.wallet import Wallet
@@ -40,14 +40,6 @@ Once we created the private keys we need to generate the wallets.
wallet_2 = Wallet({CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_2})
```
-## Create LedgerApis
-
-We need to create the LedgerApis object in order to be able to interact with the Fetch.ai `testnet`
-``` python
- # Set up the LedgerApis
- ledger_apis = LedgerApis(DEFAULT_LEDGER_CONFIGS, CosmosCrypto.identifier)
-```
-
## Generate wealth
Since we want to send funds from `wallet_1` to `wallet_2`, we need to generate some wealth for the `wallet_1`. We can
@@ -65,12 +57,12 @@ Finally, we create a transaction that sends the funds to the `wallet_2`
``` python
# Create the transaction and send it to the ledger.
- tx_nonce = ledger_apis.generate_tx_nonce(
+ tx_nonce = LedgerApis.generate_tx_nonce(
CosmosCrypto.identifier,
wallet_2.addresses.get(CosmosCrypto.identifier),
wallet_1.addresses.get(CosmosCrypto.identifier),
)
- transaction = ledger_apis.get_transfer_transaction(
+ transaction = LedgerApis.get_transfer_transaction(
identifier=CosmosCrypto.identifier,
sender_address=wallet_1.addresses.get(CosmosCrypto.identifier),
destination_address=wallet_2.addresses.get(CosmosCrypto.identifier),
@@ -79,7 +71,7 @@ Finally, we create a transaction that sends the funds to the `wallet_2`
tx_nonce=tx_nonce,
)
signed_transaction = wallet_1.sign_transaction(CosmosCrypto.identifier, transaction)
- transaction_digest = ledger_apis.send_signed_transaction(
+ transaction_digest = LedgerApis.send_signed_transaction(
CosmosCrypto.identifier, signed_transaction
)
@@ -94,7 +86,7 @@ import logging
from aea.crypto.cosmos import CosmosCrypto
from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth
-from aea.crypto.ledger_apis import DEFAULT_LEDGER_CONFIGS, LedgerApis
+from aea.crypto.ledger_apis import LedgerApis
from aea.crypto.wallet import Wallet
@@ -118,9 +110,6 @@ def run():
wallet_1 = Wallet({CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_1})
wallet_2 = Wallet({CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_2})
- # Set up the LedgerApis
- ledger_apis = LedgerApis(DEFAULT_LEDGER_CONFIGS, CosmosCrypto.identifier)
-
# Generate some wealth
try_generate_testnet_wealth(
CosmosCrypto.identifier, wallet_1.addresses[CosmosCrypto.identifier]
@@ -131,12 +120,12 @@ def run():
)
# Create the transaction and send it to the ledger.
- tx_nonce = ledger_apis.generate_tx_nonce(
+ tx_nonce = LedgerApis.generate_tx_nonce(
CosmosCrypto.identifier,
wallet_2.addresses.get(CosmosCrypto.identifier),
wallet_1.addresses.get(CosmosCrypto.identifier),
)
- transaction = ledger_apis.get_transfer_transaction(
+ transaction = LedgerApis.get_transfer_transaction(
identifier=CosmosCrypto.identifier,
sender_address=wallet_1.addresses.get(CosmosCrypto.identifier),
destination_address=wallet_2.addresses.get(CosmosCrypto.identifier),
@@ -145,7 +134,7 @@ def run():
tx_nonce=tx_nonce,
)
signed_transaction = wallet_1.sign_transaction(CosmosCrypto.identifier, transaction)
- transaction_digest = ledger_apis.send_signed_transaction(
+ transaction_digest = LedgerApis.send_signed_transaction(
CosmosCrypto.identifier, signed_transaction
)
diff --git a/docs/tac-skills-contract.md b/docs/tac-skills-contract.md
index 8f42eba869..c6ebeca19e 100644
--- a/docs/tac-skills-contract.md
+++ b/docs/tac-skills-contract.md
@@ -95,21 +95,13 @@ There is an equivalent diagram for seller AEAs set up to search for buyers and t
Follow the Preliminaries and Installation sections from the AEA quick start.
-### Launch an OEF search and communication node
-In a separate terminal, launch a local [OEF search and communication node](../oef-ledger).
-``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-
-Keep it running for the following demo.
-
## Demo instructions:
### Create TAC controller AEA
In the root directory, fetch the controller AEA:
``` bash
-aea fetch fetchai/tac_controller_contract:0.6.0
+aea fetch fetchai/tac_controller_contract:0.7.0
cd tac_controller_contract
aea install
```
@@ -121,10 +113,12 @@ The following steps create the controller from scratch:
``` bash
aea create tac_controller_contract
cd tac_controller_contract
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_control_contract:0.4.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_control_contract:0.5.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
```
@@ -160,12 +154,12 @@ aea get-wealth ethereum
In a separate terminal, in the root directory, fetch at least two participants:
``` bash
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_one
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_one
cd tac_participant_one
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
cd ..
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_two
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_two
cd tac_participant_two
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
@@ -184,11 +178,13 @@ aea create tac_participant_two
Build participant one:
``` bash
cd tac_participant_one
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
@@ -197,11 +193,13 @@ aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_con
Then, build participant two:
``` bash
cd tac_participant_two
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
diff --git a/docs/tac-skills.md b/docs/tac-skills.md
index 3244989d6f..d13c2c3a52 100644
--- a/docs/tac-skills.md
+++ b/docs/tac-skills.md
@@ -94,21 +94,13 @@ There is an equivalent diagram for seller AEAs set up to search for buyers and t
Follow the Preliminaries and Installation sections from the AEA quick start.
-### Launch an OEF search and communication node
-In a separate terminal, launch a local [OEF search and communication node](../oef-ledger).
-``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-
-Keep it running for the following demo.
-
## Demo instructions:
### Create TAC controller AEA
In the root directory, fetch the controller AEA:
``` bash
-aea fetch fetchai/tac_controller:0.5.0
+aea fetch fetchai/tac_controller:0.6.0
cd tac_controller
aea install
```
@@ -120,11 +112,13 @@ The following steps create the controller from scratch:
``` bash
aea create tac_controller
cd tac_controller
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_control:0.3.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_control:0.4.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
```
@@ -134,8 +128,8 @@ aea config set agent.default_ledger ethereum
In a separate terminal, in the root directory, fetch at least two participants:
``` bash
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_one
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_two
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_one
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_two
cd tac_participant_two
aea install
```
@@ -152,28 +146,41 @@ aea create tac_participant_two
Build participant one:
``` bash
cd tac_participant_one
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
```
Then, build participant two:
``` bash
cd tac_participant_two
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
```
+### Add keys for all AEAs
+
+Create the private key for the AEA for Fetch.ai `AgentLand`:
+``` bash
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt
+aea add-key cosmos cosmos_private_key.txt --connection
+```
+
### Update the game parameters in the controller
Navigate to the tac controller project, then use the command line to get and set the start time (set it to at least two minutes in the future):
@@ -183,6 +190,38 @@ aea config get vendor.fetchai.skills.tac_control.models.parameters.args.start_ti
aea config set vendor.fetchai.skills.tac_control.models.parameters.args.start_time '01 01 2020 00:01'
```
+### Update the connection params
+
+Briefly run the controller AEA:
+
+``` bash
+aea run
+```
+
+Once you see a message of the form `My libp2p addresses: ['SOME_ADDRESS']` take note of the address.
+
+Then, update the configuration of the weather client AEA's p2p connection (in `vendor/fetchai/connections/p2p_libp2p/connection.yaml`) replace the following:
+
+``` yaml
+config:
+ delegate_uri: 127.0.0.1:11001
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9001
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9001
+```
+
+``` yaml
+config:
+ delegate_uri: 127.0.0.1:11002
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9002
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9002
+```
+
+where `SOME_ADDRESS` is replaced accordingly.
+
### Run the AEAs
The CLI tool supports the launch of several agents
@@ -259,7 +298,7 @@ models:
class_name: Transactions
args:
pending_transaction_timeout: 30
-protocols: ['fetchai/oef_search:0.3.0', 'fetchai/fipa:0.4.0']
+protocols: ['fetchai/oef_search:0.4.0', 'fetchai/fipa:0.5.0']
```
Above, you can see the registered `Behaviour` class name `GoodsRegisterAndSearchBehaviour` which implements register and search behaviour of an AEA for the `tac_negotiation` skill.
diff --git a/docs/thermometer-skills.md b/docs/thermometer-skills.md
index 50fa822b44..32fb841539 100644
--- a/docs/thermometer-skills.md
+++ b/docs/thermometer-skills.md
@@ -62,7 +62,7 @@ A demo to run the thermometer scenario with a true ledger transaction This demo
First, fetch the thermometer AEA:
``` bash
-aea fetch fetchai/thermometer_aea:0.6.0 --alias my_thermometer_aea
+aea fetch fetchai/thermometer_aea:0.7.0 --alias my_thermometer_aea
cd thermometer_aea
aea install
```
@@ -74,19 +74,19 @@ The following steps create the thermometer AEA from scratch:
``` bash
aea create my_thermometer_aea
cd my_thermometer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_thermometer_aea/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
@@ -96,7 +96,7 @@ default_routing:
Then, fetch the thermometer client AEA:
``` bash
-aea fetch fetchai/thermometer_client:0.6.0 --alias my_thermometer_client
+aea fetch fetchai/thermometer_client:0.7.0 --alias my_thermometer_client
cd my_thermometer_client
aea install
```
@@ -108,19 +108,19 @@ The following steps create the thermometer client from scratch:
``` bash
aea create my_thermometer_client
cd my_thermometer_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_thermometer_aea/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/docs/weather-skills.md b/docs/weather-skills.md
index 01aaf5e7e8..bd3365837d 100644
--- a/docs/weather-skills.md
+++ b/docs/weather-skills.md
@@ -61,7 +61,7 @@ trusts the seller AEA to send the data upon successful payment.
First, fetch the AEA that will provide weather measurements:
``` bash
-aea fetch fetchai/weather_station:0.8.0 --alias my_weather_station
+aea fetch fetchai/weather_station:0.9.0 --alias my_weather_station
cd my_weather_station
aea install
```
@@ -73,19 +73,19 @@ The following steps create the weather station from scratch:
``` bash
aea create my_weather_station
cd my_weather_station
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/weather_station:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/weather_station:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `weather_station/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
@@ -96,7 +96,7 @@ default_routing:
In another terminal, fetch the AEA that will query the weather station:
``` bash
-aea fetch fetchai/weather_client:0.8.0 --alias my_weather_client
+aea fetch fetchai/weather_client:0.9.0 --alias my_weather_client
cd my_weather_client
aea install
```
@@ -108,19 +108,19 @@ The following steps create the weather client from scratch:
``` bash
aea create my_weather_client
cd my_weather_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/weather_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/weather_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
In `my_weather_client/aea-config.yaml` add
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/examples/gym_ex/gyms/env.py b/examples/gym_ex/gyms/env.py
index c50fdc6d52..5d33566a20 100644
--- a/examples/gym_ex/gyms/env.py
+++ b/examples/gym_ex/gyms/env.py
@@ -70,7 +70,8 @@ def __init__(
self.seed() # seed environment randomness
- def reset(self) -> Observation:
+ @staticmethod
+ def reset() -> Observation:
"""
Reset the environment.
diff --git a/examples/gym_ex/proxy/agent.py b/examples/gym_ex/proxy/agent.py
index 7a0baffc74..6923d4a593 100644
--- a/examples/gym_ex/proxy/agent.py
+++ b/examples/gym_ex/proxy/agent.py
@@ -34,7 +34,9 @@
sys.modules["packages.fetchai.connections.gym"] = locate(
"packages.fetchai.connections.gym"
)
-from packages.fetchai.connections.gym.connection import GymConnection # noqa: E402
+from packages.fetchai.connections.gym.connection import ( # noqa: E402 # pylint: disable=wrong-import-position
+ GymConnection,
+)
ADDRESS = "some_address"
diff --git a/examples/gym_ex/proxy/env.py b/examples/gym_ex/proxy/env.py
index cc5bd97697..08c0e003ec 100755
--- a/examples/gym_ex/proxy/env.py
+++ b/examples/gym_ex/proxy/env.py
@@ -16,19 +16,19 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""This contains the proxy gym environment."""
+import copy
import sys
import time
from queue import Queue
from threading import Thread
-from typing import Any, Tuple, cast
+from typing import Any, Optional, Tuple, cast
import gym
-from aea.configurations.base import PublicId
from aea.helpers.base import locate
+from aea.helpers.dialogue.base import Dialogue as BaseDialogue
from aea.mail.base import Envelope
from aea.protocols.base import Message
@@ -36,9 +36,17 @@
"packages.fetchai.connections.gym"
)
sys.modules["packages.fetchai.protocols.gym"] = locate("packages.fetchai.protocols.gym")
-from packages.fetchai.protocols.gym.message import GymMessage # noqa: E402
+from packages.fetchai.protocols.gym.dialogues import ( # noqa: E402 # pylint: disable=wrong-import-position
+ GymDialogue as BaseGymDialogue,
+)
+from packages.fetchai.protocols.gym.dialogues import ( # noqa: E402 # pylint: disable=wrong-import-position
+ GymDialogues as BaseGymDialogues,
+)
+from packages.fetchai.protocols.gym.message import ( # noqa: E402 # pylint: disable=wrong-import-position
+ GymMessage,
+)
-from .agent import ProxyAgent # noqa: E402
+from .agent import ProxyAgent # noqa: E402 # pylint: disable=wrong-import-position
Action = Any
Observation = Any
@@ -49,6 +57,23 @@
DEFAULT_GYM = "gym"
+GymDialogue = BaseGymDialogue
+
+GymDialogues = BaseGymDialogues
+
+
+@staticmethod
+def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseGymDialogue.Role.AGENT
+
+
+GymDialogues.role_from_first_message = role_from_first_message
+
class ProxyEnv(gym.Env):
"""This class implements a proxy gym environment."""
@@ -61,13 +86,22 @@ def __init__(self, gym_env: gym.Env) -> None:
:return: None
"""
super().__init__()
- self._queue = Queue()
- self._action_counter = 0
+ self._queue: Queue = Queue()
+ self._action_counter: int = 0
+ self.gym_address = "fetchai/gym:0.5.0"
self._agent = ProxyAgent(
name="proxy", gym_env=gym_env, proxy_env_queue=self._queue
)
self._agent_address = self._agent.identity.address
self._agent_thread = Thread(target=self._agent.start)
+ self._active_dialogue = None # type: Optional[GymDialogue]
+ self.agent_address = "proxy"
+ self.gym_dialogues = GymDialogues(self.agent_address)
+
+ @property
+ def active_dialogue(self) -> GymDialogue:
+ """Get the active dialogue."""
+ return self._active_dialogue
def step(self, action: Action) -> Feedback:
"""
@@ -105,7 +139,9 @@ def render(self, mode="human") -> None:
:return: None
"""
# TODO: adapt this line to the new APIs. We no longer have a mailbox.
- self._agent.mailbox._connection.channel.gym_env.render(mode)
+ self._agent.mailbox._connection.channel.gym_env.render( # pylint: disable=protected-access,no-member
+ mode
+ )
def reset(self) -> None:
"""
@@ -115,9 +151,20 @@ def reset(self) -> None:
"""
if not self._agent.multiplexer.is_connected:
self._connect()
- gym_msg = GymMessage(performative=GymMessage.Performative.RESET)
- gym_msg.counterparty = DEFAULT_GYM
- self._agent.outbox.put_message(message=gym_msg, sender=self._agent_address)
+ gym_msg = GymMessage(
+ dialogue_reference=self.gym_dialogues.new_self_initiated_dialogue_reference(),
+ performative=GymMessage.Performative.RESET,
+ )
+ gym_msg.counterparty = self.gym_address
+ gym_dialogue = cast(Optional[GymDialogue], self.gym_dialogues.update(gym_msg))
+ assert gym_dialogue is not None
+ self._active_dialogue = gym_dialogue
+ self._agent.outbox.put_message(message=gym_msg)
+
+ # Wait (blocking!) for the response envelope from the environment
+ in_envelope = self._queue.get(block=True, timeout=None) # type: GymMessage
+
+ self._decode_status(in_envelope)
def close(self) -> None:
"""
@@ -125,9 +172,17 @@ def close(self) -> None:
:return: None
"""
- gym_msg = GymMessage(performative=GymMessage.Performative.CLOSE)
- gym_msg.counterparty = DEFAULT_GYM
- self._agent.outbox.put_message(message=gym_msg, sender=self._agent_address)
+ last_msg = self.active_dialogue.last_message
+ assert last_msg is not None, "Cannot retrieve last message."
+ gym_msg = GymMessage(
+ dialogue_reference=self.active_dialogue.dialogue_label.dialogue_reference,
+ performative=GymMessage.Performative.CLOSE,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
+ )
+ gym_msg.counterparty = self.gym_address
+ assert self.active_dialogue.update(gym_msg)
+ self._agent.outbox.put_message(message=gym_msg)
self._disconnect()
@@ -160,16 +215,23 @@ def _encode_and_send_action(self, action: Action, step_id: int) -> None:
:param step_id: the step id
:return: an envelope
"""
+ last_msg = self.active_dialogue.last_message
+ assert last_msg is not None, "Cannot retrieve last message."
gym_msg = GymMessage(
+ dialogue_reference=self.active_dialogue.dialogue_label.dialogue_reference,
performative=GymMessage.Performative.ACT,
action=GymMessage.AnyObject(action),
step_id=step_id,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
)
- gym_msg.counterparty = DEFAULT_GYM
+ gym_msg.counterparty = self.gym_address
+ assert self.active_dialogue.update(gym_msg)
# Send the message via the proxy agent and to the environment
- self._agent.outbox.put_message(message=gym_msg, sender=self._agent_address)
+ self._agent.outbox.put_message(message=gym_msg)
+
+ def _decode_percept(self, envelope: Envelope, expected_step_id: int) -> GymMessage:
- def _decode_percept(self, envelope: Envelope, expected_step_id: int) -> Message:
"""
Receive the response from the gym environment in the form of an envelope and decode it.
@@ -179,8 +241,13 @@ def _decode_percept(self, envelope: Envelope, expected_step_id: int) -> Message:
:return: a message received as a response to the action performed in apply_action.
"""
if envelope is not None:
- if envelope.protocol_id == PublicId.from_str("fetchai/gym:0.3.0"):
- gym_msg = envelope.message
+ if envelope.protocol_id == GymMessage.protocol_id:
+ orig_gym_msg = cast(GymMessage, envelope.message)
+ gym_msg = copy.copy(orig_gym_msg)
+ gym_msg.counterparty = orig_gym_msg.sender
+ gym_msg.is_incoming = True
+ if not self.active_dialogue.update(gym_msg):
+ raise ValueError("Could not udpate dialogue.")
if (
gym_msg.performative == GymMessage.Performative.PERCEPT
and gym_msg.step_id == expected_step_id
@@ -197,7 +264,42 @@ def _decode_percept(self, envelope: Envelope, expected_step_id: int) -> Message:
else:
raise ValueError("Missing envelope.")
- def _message_to_percept(self, message: Message) -> Feedback:
+ def _decode_status(self, envelope: Envelope) -> None:
+
+ """
+ Receive the response from the gym environment in the form of an envelope and decode it.
+
+ The response is a STATUS message.
+
+ :return: a message received as a response to the action performed in apply_action.
+ """
+ if envelope is not None:
+ if envelope.protocol_id == GymMessage.protocol_id:
+ orig_gym_msg = cast(GymMessage, envelope.message)
+ gym_msg = copy.copy(orig_gym_msg)
+ gym_msg.counterparty = orig_gym_msg.sender
+ gym_msg.is_incoming = True
+ if not self.active_dialogue.update(gym_msg):
+ raise ValueError("Could not udpate dialogue.")
+ if (
+ gym_msg.performative == GymMessage.Performative.STATUS
+ and gym_msg.content.get("reset", "failure") == "success"
+ ):
+
+ return None
+ else:
+ raise ValueError(
+ "Unexpected performative or no step_id: {}".format(
+ gym_msg.performative
+ )
+ )
+ else:
+ raise ValueError("Unknown protocol_id: {}".format(envelope.protocol_id))
+ else:
+ raise ValueError("Missing envelope.")
+
+ @staticmethod
+ def _message_to_percept(message: GymMessage) -> Feedback:
"""
Transform the message received from the gym environment into observation, reward, done, info.
diff --git a/examples/gym_ex/rl/agent.py b/examples/gym_ex/rl/agent.py
index 2b2b108b1c..6517b1cc7e 100644
--- a/examples/gym_ex/rl/agent.py
+++ b/examples/gym_ex/rl/agent.py
@@ -38,7 +38,7 @@
Feedback = Tuple[Observation, Reward, Done, Info]
-class PriceBandit(object):
+class PriceBandit:
"""A class for a multi-armed bandit model of price."""
def __init__(self, price: float, beta_a: float = 1.0, beta_b: float = 1.0):
@@ -73,7 +73,7 @@ def update(self, outcome: float) -> None:
self.beta_b += 1 - outcome
-class GoodPriceModel(object):
+class GoodPriceModel:
"""A class for a price model of a good."""
def __init__(self, bound: int = 100):
diff --git a/mkdocs.yml b/mkdocs.yml
index dbedffa360..e15721d305 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -82,7 +82,10 @@ nav:
- Ledger & Crypto APIs: 'ledger-integration.md'
- Message routing: 'message-routing.md'
- Configurations: 'config.md'
+ - Agent Communication:
+ - Agent Communication Network: 'acn.md'
- Search & Discovery:
+ - Simple OEF: 'simple-oef.md'
- Defining Data Models: 'defining-data-models.md'
- The Query Language: 'query-language.md'
- SOEF Connection: 'simple-oef-usage.md'
@@ -182,7 +185,6 @@ nav:
- Task: 'api/skills/tasks.md'
- Test Tools: 'api/test_tools/generic.md'
- Q&A: 'questions-and-answers.md'
- - Simple OEF: 'simple-oef.md'
plugins:
- markdownmermaid
diff --git a/packages/fetchai/agents/aries_alice/aea-config.yaml b/packages/fetchai/agents/aries_alice/aea-config.yaml
index 10467e50f7..18f1ff8a97 100644
--- a/packages/fetchai/agents/aries_alice/aea-config.yaml
+++ b/packages/fetchai/agents/aries_alice/aea-config.yaml
@@ -1,29 +1,32 @@
agent_name: aries_alice
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA representing Alice in the Aries demo.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/http_client:0.5.0
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
-- fetchai/webhook:0.4.0
+- fetchai/http_client:0.6.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
+- fetchai/webhook:0.5.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/http:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/http:0.4.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/aries_alice:0.3.0
-- fetchai/error:0.3.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/aries_alice:0.4.0
+- fetchai/error:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
version: 1
private_key_paths: {}
registry_path: ../packages
+default_routing:
+ fetchai/http:0.4.0: fetchai/http_client:0.6.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/aries_faber/aea-config.yaml b/packages/fetchai/agents/aries_faber/aea-config.yaml
index 757e5cb0ae..cca32532ed 100644
--- a/packages/fetchai/agents/aries_faber/aea-config.yaml
+++ b/packages/fetchai/agents/aries_faber/aea-config.yaml
@@ -1,29 +1,32 @@
agent_name: aries_faber
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA representing Faber in the Aries demo.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/http_client:0.5.0
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
-- fetchai/webhook:0.4.0
+- fetchai/http_client:0.6.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
+- fetchai/webhook:0.5.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/http:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/http:0.4.0
+- fetchai/oef_search:0.4.0
skills:
- fetchai/aries_faber:0.3.0
-- fetchai/error:0.3.0
-default_connection: fetchai/http_client:0.5.0
+- fetchai/error:0.4.0
+default_connection: fetchai/http_client:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
version: 1
private_key_paths: {}
registry_path: ../packages
+default_routing:
+ fetchai/http:0.4.0: fetchai/http_client:0.6.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/car_data_buyer/aea-config.yaml b/packages/fetchai/agents/car_data_buyer/aea-config.yaml
index 2a5ca6263e..47f59754cf 100644
--- a/packages/fetchai/agents/car_data_buyer/aea-config.yaml
+++ b/packages/fetchai/agents/car_data_buyer/aea-config.yaml
@@ -1,6 +1,6 @@
agent_name: car_data_buyer
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: An agent which searches for an instance of a `car_detector` agent and
attempts to purchase car park data from it.
license: Apache-2.0
@@ -8,21 +8,21 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/carpark_client:0.7.0
-- fetchai/error:0.3.0
-- fetchai/generic_buyer:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/carpark_client:0.8.0
+- fetchai/error:0.4.0
+- fetchai/generic_buyer:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -30,5 +30,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/car_detector/aea-config.yaml b/packages/fetchai/agents/car_detector/aea-config.yaml
index dd1fd72304..e7e4dbd759 100644
--- a/packages/fetchai/agents/car_detector/aea-config.yaml
+++ b/packages/fetchai/agents/car_detector/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: car_detector
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: An agent which sells car park data to instances of `car_data_buyer` agents.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/carpark_detection:0.7.0
-- fetchai/error:0.3.0
-- fetchai/generic_seller:0.8.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/carpark_detection:0.8.0
+- fetchai/error:0.4.0
+- fetchai/generic_seller:0.9.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/erc1155_client/aea-config.yaml b/packages/fetchai/agents/erc1155_client/aea-config.yaml
index 6b18e04889..c4e7551bcd 100644
--- a/packages/fetchai/agents/erc1155_client/aea-config.yaml
+++ b/packages/fetchai/agents/erc1155_client/aea-config.yaml
@@ -1,28 +1,29 @@
agent_name: erc1155_client
author: fetchai
-version: 0.9.0
+version: 0.10.0
description: An AEA to interact with the ERC1155 deployer AEA
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
-- fetchai/signing:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
+- fetchai/signing:0.2.0
skills:
-- fetchai/erc1155_client:0.8.0
-- fetchai/error:0.3.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/erc1155_client:0.9.0
+- fetchai/error:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: ethereum
logging_config:
disable_existing_loggers: false
@@ -30,5 +31,6 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/erc1155_deployer/aea-config.yaml b/packages/fetchai/agents/erc1155_deployer/aea-config.yaml
index 2afcc6a916..884037bef2 100644
--- a/packages/fetchai/agents/erc1155_deployer/aea-config.yaml
+++ b/packages/fetchai/agents/erc1155_deployer/aea-config.yaml
@@ -1,28 +1,29 @@
agent_name: erc1155_deployer
author: fetchai
-version: 0.9.0
+version: 0.10.0
description: An AEA to deploy and interact with an ERC1155
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
-- fetchai/signing:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
+- fetchai/signing:0.2.0
skills:
-- fetchai/erc1155_deploy:0.9.0
-- fetchai/error:0.3.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/erc1155_deploy:0.10.0
+- fetchai/error:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: ethereum
logging_config:
disable_existing_loggers: false
@@ -30,5 +31,6 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/generic_buyer/aea-config.yaml b/packages/fetchai/agents/generic_buyer/aea-config.yaml
index d111db3c97..5412b48ae3 100644
--- a/packages/fetchai/agents/generic_buyer/aea-config.yaml
+++ b/packages/fetchai/agents/generic_buyer/aea-config.yaml
@@ -1,26 +1,26 @@
agent_name: generic_buyer
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The buyer AEA purchases the services offered by the seller AEA.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_buyer:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_buyer:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -28,5 +28,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/generic_seller/aea-config.yaml b/packages/fetchai/agents/generic_seller/aea-config.yaml
index ab4e721b72..c2d29dd0a8 100644
--- a/packages/fetchai/agents/generic_seller/aea-config.yaml
+++ b/packages/fetchai/agents/generic_seller/aea-config.yaml
@@ -1,6 +1,6 @@
agent_name: generic_seller
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The seller AEA sells the services specified in the `skill.yaml` file
and delivers them upon payment to the buyer.
license: Apache-2.0
@@ -8,20 +8,20 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_seller:0.8.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_seller:0.9.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/gym_aea/aea-config.yaml b/packages/fetchai/agents/gym_aea/aea-config.yaml
index 551dc0861a..41f52f5da6 100644
--- a/packages/fetchai/agents/gym_aea/aea-config.yaml
+++ b/packages/fetchai/agents/gym_aea/aea-config.yaml
@@ -1,6 +1,6 @@
agent_name: gym_aea
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The gym aea demos the interaction between a skill containing a RL agent
and a gym connection.
license: Apache-2.0
@@ -8,16 +8,16 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/gym:0.4.0
-- fetchai/stub:0.6.0
+- fetchai/gym:0.5.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/gym:0.3.0
-skills:
-- fetchai/error:0.3.0
+- fetchai/default:0.4.0
- fetchai/gym:0.4.0
-default_connection: fetchai/gym:0.4.0
+skills:
+- fetchai/error:0.4.0
+- fetchai/gym:0.5.0
+default_connection: fetchai/gym:0.5.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/packages/fetchai/agents/ml_data_provider/aea-config.yaml b/packages/fetchai/agents/ml_data_provider/aea-config.yaml
index 13d383aca2..7e860c017c 100644
--- a/packages/fetchai/agents/ml_data_provider/aea-config.yaml
+++ b/packages/fetchai/agents/ml_data_provider/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: ml_data_provider
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: An agent that sells data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/ledger_api:0.1.0
-- fetchai/ml_trade:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/ledger_api:0.2.0
+- fetchai/ml_trade:0.4.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_seller:0.8.0
-- fetchai/ml_data_provider:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_seller:0.9.0
+- fetchai/ml_data_provider:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/ml_model_trainer/aea-config.yaml b/packages/fetchai/agents/ml_model_trainer/aea-config.yaml
index b7fe653164..7ceb0bab21 100644
--- a/packages/fetchai/agents/ml_model_trainer/aea-config.yaml
+++ b/packages/fetchai/agents/ml_model_trainer/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: ml_model_trainer
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: An agent buying data and training a model from it.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/ledger_api:0.1.0
-- fetchai/ml_trade:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/ledger_api:0.2.0
+- fetchai/ml_trade:0.4.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_buyer:0.7.0
-- fetchai/ml_train:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_buyer:0.8.0
+- fetchai/ml_train:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/my_first_aea/aea-config.yaml b/packages/fetchai/agents/my_first_aea/aea-config.yaml
index 9075fed729..4d48224cdf 100644
--- a/packages/fetchai/agents/my_first_aea/aea-config.yaml
+++ b/packages/fetchai/agents/my_first_aea/aea-config.yaml
@@ -1,20 +1,20 @@
agent_name: my_first_aea
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: A simple agent to demo the echo skill.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills:
-- fetchai/echo:0.3.0
-- fetchai/error:0.3.0
-default_connection: fetchai/stub:0.6.0
+- fetchai/echo:0.4.0
+- fetchai/error:0.4.0
+default_connection: fetchai/stub:0.7.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/packages/fetchai/agents/simple_service_registration/aea-config.yaml b/packages/fetchai/agents/simple_service_registration/aea-config.yaml
index 5026b42289..54d0278168 100644
--- a/packages/fetchai/agents/simple_service_registration/aea-config.yaml
+++ b/packages/fetchai/agents/simple_service_registration/aea-config.yaml
@@ -1,24 +1,24 @@
agent_name: simple_service_registration
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: A simple example of service registration.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: ''
fingerprint_ignore_patterns: []
connections:
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/simple_service_registration:0.5.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/simple_service_registration:0.6.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -26,4 +26,4 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/tac_controller/aea-config.yaml b/packages/fetchai/agents/tac_controller/aea-config.yaml
index c0b381693d..2e6569f460 100644
--- a/packages/fetchai/agents/tac_controller/aea-config.yaml
+++ b/packages/fetchai/agents/tac_controller/aea-config.yaml
@@ -1,27 +1,30 @@
agent_name: tac_controller
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: An AEA to manage an instance of the TAC (trading agent competition)
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/tac_control:0.3.0
-default_connection: fetchai/oef:0.6.0
-default_ledger: ethereum
+- fetchai/error:0.4.0
+- fetchai/tac_control:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0
+default_ledger: cosmos
logging_config:
disable_existing_loggers: false
version: 1
private_key_paths: {}
registry_path: ../packages
+default_routing:
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/tac_controller_contract/aea-config.yaml b/packages/fetchai/agents/tac_controller_contract/aea-config.yaml
index 144b1d03fb..ab27813aff 100644
--- a/packages/fetchai/agents/tac_controller_contract/aea-config.yaml
+++ b/packages/fetchai/agents/tac_controller_contract/aea-config.yaml
@@ -1,6 +1,6 @@
agent_name: tac_controller_contract
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA to manage an instance of the TAC (trading agent competition) using
an ERC1155 smart contract.
license: Apache-2.0
@@ -8,19 +8,19 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
+- fetchai/oef:0.7.0
+- fetchai/stub:0.7.0
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/tac_control_contract:0.4.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/error:0.4.0
+- fetchai/tac_control_contract:0.5.0
+default_connection: fetchai/oef:0.7.0
default_ledger: ethereum
logging_config:
disable_existing_loggers: false
diff --git a/packages/fetchai/agents/tac_participant/aea-config.yaml b/packages/fetchai/agents/tac_participant/aea-config.yaml
index fafa55c706..177546824c 100644
--- a/packages/fetchai/agents/tac_participant/aea-config.yaml
+++ b/packages/fetchai/agents/tac_participant/aea-config.yaml
@@ -1,29 +1,32 @@
agent_name: tac_participant
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA to participate in the TAC (trading agent competition)
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/oef:0.6.0
-- fetchai/stub:0.6.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/tac_negotiation:0.5.0
-- fetchai/tac_participation:0.4.0
-default_connection: fetchai/oef:0.6.0
-default_ledger: ethereum
+- fetchai/error:0.4.0
+- fetchai/tac_negotiation:0.6.0
+- fetchai/tac_participation:0.5.0
+default_connection: fetchai/p2p_libp2p:0.6.0
+default_ledger: cosmos
logging_config:
disable_existing_loggers: false
version: 1
private_key_paths: {}
registry_path: ../packages
+default_routing:
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/thermometer_aea/aea-config.yaml b/packages/fetchai/agents/thermometer_aea/aea-config.yaml
index ce61010df5..d7a6c5131a 100644
--- a/packages/fetchai/agents/thermometer_aea/aea-config.yaml
+++ b/packages/fetchai/agents/thermometer_aea/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: thermometer_aea
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA to represent a thermometer and sell temperature data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_seller:0.8.0
-- fetchai/thermometer:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_seller:0.9.0
+- fetchai/thermometer:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/thermometer_client/aea-config.yaml b/packages/fetchai/agents/thermometer_client/aea-config.yaml
index 8a8d0cfb83..57b5f1ada1 100644
--- a/packages/fetchai/agents/thermometer_client/aea-config.yaml
+++ b/packages/fetchai/agents/thermometer_client/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: thermometer_client
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: An AEA that purchases thermometer data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_buyer:0.7.0
-- fetchai/thermometer_client:0.6.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_buyer:0.8.0
+- fetchai/thermometer_client:0.7.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/weather_client/aea-config.yaml b/packages/fetchai/agents/weather_client/aea-config.yaml
index 0852aca3d2..f449ddf9a5 100644
--- a/packages/fetchai/agents/weather_client/aea-config.yaml
+++ b/packages/fetchai/agents/weather_client/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: weather_client
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: This AEA purchases weather data from the weather station.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_buyer:0.7.0
-- fetchai/weather_client:0.6.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_buyer:0.8.0
+- fetchai/weather_client:0.7.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/agents/weather_station/aea-config.yaml b/packages/fetchai/agents/weather_station/aea-config.yaml
index ff76b4e17c..653db8f23b 100644
--- a/packages/fetchai/agents/weather_station/aea-config.yaml
+++ b/packages/fetchai/agents/weather_station/aea-config.yaml
@@ -1,27 +1,27 @@
agent_name: weather_station
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: This AEA represents a weather station selling weather data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/ledger:0.2.0
-- fetchai/p2p_libp2p:0.5.0
-- fetchai/soef:0.5.0
-- fetchai/stub:0.6.0
+- fetchai/ledger:0.3.0
+- fetchai/p2p_libp2p:0.6.0
+- fetchai/soef:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/error:0.3.0
-- fetchai/generic_seller:0.8.0
-- fetchai/weather_station:0.7.0
-default_connection: fetchai/p2p_libp2p:0.5.0
+- fetchai/error:0.4.0
+- fetchai/generic_seller:0.9.0
+- fetchai/weather_station:0.8.0
+default_connection: fetchai/p2p_libp2p:0.6.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
@@ -29,5 +29,5 @@ logging_config:
private_key_paths: {}
registry_path: ../packages
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
diff --git a/packages/fetchai/connections/gym/README.md b/packages/fetchai/connections/gym/README.md
new file mode 100644
index 0000000000..3b00a37e79
--- /dev/null
+++ b/packages/fetchai/connections/gym/README.md
@@ -0,0 +1,9 @@
+# Gym connection
+
+Connection providing access to the gym interface (https://github.com/openai/gym) for training reinforcement learning systems.
+
+The connection wraps a gym and allows the AEA to interact with the gym interface via the `gym` protocol.
+
+## Usage
+
+First, add the connection to your AEA project (`aea add connection fetchai/gym:0.5.0`). Then, update the `config` in `connection.yaml` by providing a dotted path to the gym module in the `env` field.
diff --git a/packages/fetchai/connections/gym/connection.py b/packages/fetchai/connections/gym/connection.py
index 3b53544934..21cbd5f5ae 100644
--- a/packages/fetchai/connections/gym/connection.py
+++ b/packages/fetchai/connections/gym/connection.py
@@ -20,27 +20,27 @@
"""Gym connector and gym channel."""
import asyncio
+import copy
import logging
from asyncio import CancelledError
from asyncio.events import AbstractEventLoop
from concurrent.futures.thread import ThreadPoolExecutor
-from typing import Optional, Union, cast
+from typing import Optional, Tuple, Union, cast
import gym
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.helpers.base import locate
from aea.mail.base import Address, Envelope
+from packages.fetchai.protocols.gym.dialogues import GymDialogue, GymDialogues
from packages.fetchai.protocols.gym.message import GymMessage
-logger = logging.getLogger("aea.packages.fetchai.connections.gym")
+logger = logging.getLogger("aea.packages.fetchai.connections.gym")
-"""default 'to' field for Gym envelopes."""
-DEFAULT_GYM = "gym"
-PUBLIC_ID = PublicId.from_str("fetchai/gym:0.4.0")
+PUBLIC_ID = PublicId.from_str("fetchai/gym:0.5.0")
class GymChannel:
@@ -58,6 +58,28 @@ def __init__(self, address: Address, gym_env: gym.Env):
self.THREAD_POOL_SIZE
)
self.logger: Union[logging.Logger, logging.LoggerAdapter] = logger
+ self._dialogues = GymDialogues(str(PUBLIC_ID))
+
+ def _get_message_and_dialogue(
+ self, envelope: Envelope
+ ) -> Tuple[GymMessage, Optional[GymDialogue]]:
+ """
+ Get a message copy and dialogue related to this message.
+
+ :param envelope: incoming envelope
+
+ :return: Tuple[MEssage, Optional[Dialogue]]
+ """
+ orig_message = cast(GymMessage, envelope.message)
+ message = copy.copy(
+ orig_message
+ ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ message.is_incoming = True # TODO: fix; should be done by framework
+ message.counterparty = (
+ orig_message.sender
+ ) # TODO: fix; should be done by framework
+ dialogue = cast(GymDialogue, self._dialogues.update(message))
+ return message, dialogue
@property
def queue(self) -> asyncio.Queue:
@@ -102,7 +124,14 @@ async def handle_gym_message(self, envelope: Envelope) -> None:
assert isinstance(
envelope.message, GymMessage
), "Message not of type GymMessage"
- gym_message = cast(GymMessage, envelope.message)
+ gym_message, dialogue = self._get_message_and_dialogue(envelope)
+
+ if dialogue is None:
+ self.logger.warning(
+ "Could not create dialogue from message={}".format(gym_message)
+ )
+ return
+
if gym_message.performative == GymMessage.Performative.ACT:
action = gym_message.action.any
step_id = gym_message.step_id
@@ -110,7 +139,6 @@ async def handle_gym_message(self, envelope: Envelope) -> None:
observation, reward, done, info = await self._run_in_executor(
self.gym_env.step, action
)
-
msg = GymMessage(
performative=GymMessage.Performative.PERCEPT,
observation=GymMessage.AnyObject(observation),
@@ -118,18 +146,31 @@ async def handle_gym_message(self, envelope: Envelope) -> None:
done=done,
info=GymMessage.AnyObject(info),
step_id=step_id,
+ target=gym_message.message_id,
+ message_id=gym_message.message_id + 1,
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
)
- envelope = Envelope(
- to=envelope.sender,
- sender=DEFAULT_GYM,
- protocol_id=GymMessage.protocol_id,
- message=msg,
- )
- await self._send(envelope)
elif gym_message.performative == GymMessage.Performative.RESET:
await self._run_in_executor(self.gym_env.reset)
+ msg = GymMessage(
+ performative=GymMessage.Performative.STATUS,
+ content={"reset": "success"},
+ target=gym_message.message_id,
+ message_id=gym_message.message_id + 1,
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ )
elif gym_message.performative == GymMessage.Performative.CLOSE:
await self._run_in_executor(self.gym_env.close)
+ return
+ msg.counterparty = gym_message.counterparty
+ assert dialogue.update(msg), "Error during dialogue update."
+ envelope = Envelope(
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
+ message=msg,
+ )
+ await self._send(envelope)
async def _send(self, envelope: Envelope) -> None:
"""Send a message.
@@ -137,7 +178,6 @@ async def _send(self, envelope: Envelope) -> None:
:param envelope: the envelope
:return: None
"""
- assert envelope.to == self.address, "Invalid destination address"
await self.queue.put(envelope)
async def disconnect(self) -> None:
@@ -182,10 +222,13 @@ async def connect(self) -> None:
:return: None
"""
- if not self.connection_status.is_connected:
- self.connection_status.is_connected = True
- self.channel.logger = self.logger
- await self.channel.connect()
+ if self.is_connected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.connecting)
+ self.channel.logger = self.logger
+ await self.channel.connect()
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""
@@ -193,9 +236,12 @@ async def disconnect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected:
- self.connection_status.is_connected = False
- await self.channel.disconnect()
+ if self.is_disconnected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.disconnecting)
+ await self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: Envelope) -> None:
"""
@@ -204,7 +250,7 @@ async def send(self, envelope: Envelope) -> None:
:param envelope: the envelop
:return: None
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
)
@@ -212,7 +258,7 @@ async def send(self, envelope: Envelope) -> None:
async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
"""Receive an envelope."""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
)
diff --git a/packages/fetchai/connections/gym/connection.yaml b/packages/fetchai/connections/gym/connection.yaml
index 7515f475b5..bb1569ae8f 100644
--- a/packages/fetchai/connections/gym/connection.yaml
+++ b/packages/fetchai/connections/gym/connection.yaml
@@ -1,20 +1,21 @@
name: gym
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The gym connection wraps an OpenAI gym.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmPBurf9eeV1J7rrfmeudJXUU7KDVFNJArPrV8nNwjizfx
__init__.py: QmWwxj1hGGZNteCvRtZxwtY9PuEKsrWsEmMWCKwiYCdvRR
- connection.py: QmZHUedJDmV2X1kXcjjyZHwWbwV3553QEKSUYcK6NTtr4F
+ connection.py: QmQFTgN95u1mqPobekFJXvCD9TWS4AsFFq3exeRUGQnyMz
fingerprint_ignore_patterns: []
protocols:
-- fetchai/gym:0.3.0
+- fetchai/gym:0.4.0
class_name: GymConnection
config:
env: ''
excluded_protocols: []
restricted_to_protocols:
-- fetchai/gym:0.3.0
+- fetchai/gym:0.4.0
dependencies:
gym: {}
diff --git a/packages/fetchai/connections/http_client/README.md b/packages/fetchai/connections/http_client/README.md
new file mode 100644
index 0000000000..db3b7a7e6d
--- /dev/null
+++ b/packages/fetchai/connections/http_client/README.md
@@ -0,0 +1,7 @@
+# HTTP client connection
+
+This connection wraps an HTTP client. It consumes messages from the AEA, translates them into HTTP requests, then sends the HTTP response as a message back to the AEA.
+
+## Usage
+
+First, add the connection to your AEA project (`aea add connection fetchai/http_client:0.6.0`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server.
diff --git a/packages/fetchai/connections/http_client/connection.py b/packages/fetchai/connections/http_client/connection.py
index ce7f7f20ee..a8710c77a2 100644
--- a/packages/fetchai/connections/http_client/connection.py
+++ b/packages/fetchai/connections/http_client/connection.py
@@ -16,31 +16,35 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
"""HTTP client connection and channel."""
import asyncio
+import copy
import json
import logging
from asyncio import CancelledError
from asyncio.events import AbstractEventLoop
from asyncio.tasks import Task
from traceback import format_exc
-from typing import Any, Optional, Set, Union, cast
+from typing import Any, Optional, Set, Tuple, Union, cast
import aiohttp
from aiohttp.client_reqrep import ClientResponse
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import Address, Envelope, EnvelopeContext
+from packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
+
SUCCESS = 200
NOT_FOUND = 404
REQUEST_TIMEOUT = 408
SERVER_ERROR = 500
-PUBLIC_ID = PublicId.from_str("fetchai/http_client:0.5.0")
+PUBLIC_ID = PublicId.from_str("fetchai/http_client:0.6.0")
logger = logging.getLogger("aea.packages.fetchai.connections.http_client")
@@ -78,6 +82,7 @@ def __init__(
self.port = port
self.connection_id = connection_id
self.restricted_to_protocols = restricted_to_protocols
+ self._dialogues = HttpDialogues(str(HTTPClientConnection.connection_id))
self._in_queue = None # type: Optional[asyncio.Queue] # pragma: no cover
self._loop = (
@@ -102,7 +107,28 @@ async def connect(self, loop: AbstractEventLoop) -> None:
self._in_queue = asyncio.Queue()
self.is_stopped = False
- async def _http_request_task(self, request_http_message: HttpMessage) -> None:
+ def _get_message_and_dialogue(
+ self, envelope: Envelope
+ ) -> Tuple[HttpMessage, Optional[HttpDialogue]]:
+ """
+ Get a message copy and dialogue related to this message.
+
+ :param envelope: incoming envelope
+
+ :return: Tuple[MEssage, Optional[Dialogue]]
+ """
+ orig_message = cast(HttpMessage, envelope.message)
+ message = copy.copy(
+ orig_message
+ ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ message.is_incoming = True # TODO: fix; should be done by framework
+ message.counterparty = (
+ orig_message.sender
+ ) # TODO: fix; should be done by framework
+ dialogue = cast(HttpDialogue, self._dialogues.update(message))
+ return message, dialogue
+
+ async def _http_request_task(self, request_envelope: Envelope) -> None:
"""
Perform http request and send back response.
@@ -113,6 +139,16 @@ async def _http_request_task(self, request_http_message: HttpMessage) -> None:
if not self._loop: # pragma: nocover
raise ValueError("Channel is not connected")
+ request_http_message, dialogue = self._get_message_and_dialogue(
+ request_envelope
+ )
+
+ if not dialogue:
+ self.logger.warning(
+ "Could not create dialogue for message={}".format(request_http_message)
+ )
+ return
+
try:
resp = await asyncio.wait_for(
self._perform_http_request(request_http_message),
@@ -127,6 +163,7 @@ async def _http_request_task(self, request_http_message: HttpMessage) -> None:
bodyy=resp._body # pylint: disable=protected-access
if resp._body is not None # pylint: disable=protected-access
else b"",
+ dialogue=dialogue,
)
except Exception: # pragma: nocover # pylint: disable=broad-except
envelope = self.to_envelope(
@@ -136,6 +173,7 @@ async def _http_request_task(self, request_http_message: HttpMessage) -> None:
headers={},
status_text="HTTPConnection request error.",
bodyy=format_exc().encode("utf-8"),
+ dialogue=dialogue,
)
if self._in_queue is not None:
@@ -209,7 +247,7 @@ def send(self, request_envelope: Envelope) -> None:
)
return
- task = self._loop.create_task(self._http_request_task(request_http_message))
+ task = self._loop.create_task(self._http_request_task(request_envelope))
task.add_done_callback(self._task_done_callback)
self._tasks.add(task)
@@ -248,6 +286,7 @@ def to_envelope(
headers: dict,
status_text: Optional[Any],
bodyy: bytes,
+ dialogue: HttpDialogue,
) -> Envelope:
"""
Convert an HTTP response object (from the 'requests' library) into an Envelope containing an HttpMessage (from the 'http' Protocol).
@@ -263,20 +302,22 @@ def to_envelope(
"""
context = EnvelopeContext(connection_id=connection_id)
http_message = HttpMessage(
- dialogue_reference=http_request_message.dialogue_reference,
- target=http_request_message.target,
- message_id=http_request_message.message_id,
performative=HttpMessage.Performative.RESPONSE,
status_code=status_code,
headers=json.dumps(dict(headers.items())),
status_text=status_text,
bodyy=bodyy,
version="",
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ target=http_request_message.message_id,
+ message_id=http_request_message.message_id + 1,
)
+ http_message.counterparty = http_request_message.counterparty
+ assert dialogue.update(http_message)
envelope = Envelope(
to=self.agent_address,
sender="HTTP Server",
- protocol_id=PublicId.from_str("fetchai/http:0.3.0"),
+ protocol_id=PublicId.from_str("fetchai/http:0.4.0"),
context=context,
message=http_message,
)
@@ -331,10 +372,12 @@ async def connect(self) -> None:
:return: None
"""
- if not self.connection_status.is_connected:
- self.connection_status.is_connected = True
- self.channel.logger = self.logger
- await self.channel.connect(self._loop)
+ if self.is_connected:
+ return
+ self._state.set(ConnectionStates.connecting)
+ self.channel.logger = self.logger
+ await self.channel.connect(self._loop)
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""
@@ -342,9 +385,11 @@ async def disconnect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected:
- self.connection_status.is_connected = False
- await self.channel.disconnect()
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
+ await self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: "Envelope") -> None:
"""
@@ -353,7 +398,7 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelop
:return: None
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
@@ -365,7 +410,7 @@ async def receive(self, *args, **kwargs) -> Optional[Union["Envelope", None]]:
:return: the envelope received, or None.
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
diff --git a/packages/fetchai/connections/http_client/connection.yaml b/packages/fetchai/connections/http_client/connection.yaml
index 5c05c1312c..b3378752d2 100644
--- a/packages/fetchai/connections/http_client/connection.yaml
+++ b/packages/fetchai/connections/http_client/connection.yaml
@@ -1,23 +1,24 @@
name: http_client
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The HTTP_client connection that wraps a web-based client connecting to
a RESTful API specification.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmQmmM5CU1jh5abqbQqKEW7f51jWAzo1eKMiWyfTZYedGX
__init__.py: QmPdKAks8A6XKAgZiopJzPZYXJumTeUqChd8UorqmLQQPU
- connection.py: QmVYurcnjuRTK6CnuEc6qNbSykmZEzRMkjyGhknJKzKRQt
+ connection.py: QmTcFjUu7HvGo4Ayk2CzoyabdfCvD2dzQvF56cPFwQjmV5
fingerprint_ignore_patterns: []
protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
class_name: HTTPClientConnection
config:
host: 127.0.0.1
port: 8000
excluded_protocols: []
restricted_to_protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
dependencies:
aiohttp:
version: '>=3.6.2,<3.7'
diff --git a/packages/fetchai/connections/http_server/README.md b/packages/fetchai/connections/http_server/README.md
new file mode 100644
index 0000000000..4aa7efbf0c
--- /dev/null
+++ b/packages/fetchai/connections/http_server/README.md
@@ -0,0 +1,7 @@
+# HTTP server connection
+
+This connection wraps an HTTP server. It consumes requests from clients, translates them into messages for the AEA, waits for a response message from the AEA, then serves the response to the client.
+
+## Usage
+
+First, add the connection to your AEA project (`aea add connection fetchai/http_server:0.6.0`). Then, update the `config` in `connection.yaml` by providing a `host` and `port` of the server. Optionally, provide a path to an [OpenAPI spec](https://swagger.io/docs/specification/about/) for request validation.
diff --git a/packages/fetchai/connections/http_server/connection.py b/packages/fetchai/connections/http_server/connection.py
index 496443ed43..1594b04698 100644
--- a/packages/fetchai/connections/http_server/connection.py
+++ b/packages/fetchai/connections/http_server/connection.py
@@ -17,8 +17,10 @@
#
# ------------------------------------------------------------------------------
+
"""HTTP server connection, channel, server, and handler."""
import asyncio
+import copy
import email
import logging
from abc import ABC, abstractmethod
@@ -28,7 +30,6 @@
from traceback import format_exc
from typing import Dict, Optional, Set, cast
from urllib.parse import parse_qs, urlencode, urlparse
-from uuid import uuid4
from aiohttp import web
from aiohttp.web_request import BaseRequest
@@ -54,9 +55,11 @@
)
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
+from aea.helpers.dialogue.base import DialogueLabel
from aea.mail.base import Address, Envelope, EnvelopeContext, URI
+from packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
SUCCESS = 200
@@ -64,10 +67,10 @@
REQUEST_TIMEOUT = 408
SERVER_ERROR = 500
-logger = logging.getLogger("aea.packages.fetchai.connections.http_server")
+_default_logger = logging.getLogger("aea.packages.fetchai.connections.http_server")
-RequestId = str
-PUBLIC_ID = PublicId.from_str("fetchai/http_server:0.5.0")
+RequestId = DialogueLabel
+PUBLIC_ID = PublicId.from_str("fetchai/http_server:0.6.0")
def headers_to_string(headers: Dict):
@@ -87,6 +90,11 @@ def headers_to_string(headers: Dict):
class Request(OpenAPIRequest):
"""Generic request object."""
+ @property
+ def is_id_set(self):
+ """Check if id is set."""
+ return self._id is not None
+
@property
def id(self) -> RequestId:
"""Get the request id."""
@@ -130,20 +138,19 @@ async def create(cls, http_request: BaseRequest) -> "Request":
body=body,
mimetype=mimetype,
)
-
- request.id = uuid4().hex
return request
- def to_envelope(self, connection_id: PublicId, agent_address: str) -> Envelope:
+ def to_envelope_and_set_id(
+ self, connection_id: PublicId, agent_address: str, dialogues: HttpDialogues,
+ ) -> Envelope:
"""
Process incoming API request by packaging into Envelope and sending it in-queue.
- The Envelope's message body contains the "performative", "path", "params", and "payload".
+ :param connection_id: id of the connection
+ :param agent_address: agent's address
+ :param dialogue_reference: new dialog refernece for envelope
- :param http_method: the http method
- :param url: the url
- :param param: the parameter
- :param body: the body
+ :return: envelope
"""
url = (
self.full_url_pattern
@@ -153,9 +160,7 @@ def to_envelope(self, connection_id: PublicId, agent_address: str) -> Envelope:
uri = URI(self.full_url_pattern)
context = EnvelopeContext(connection_id=connection_id, uri=uri)
http_message = HttpMessage(
- dialogue_reference=("", ""),
- target=0,
- message_id=1,
+ dialogue_reference=dialogues.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method=self.method,
url=url,
@@ -163,10 +168,16 @@ def to_envelope(self, connection_id: PublicId, agent_address: str) -> Envelope:
bodyy=self.body if self.body is not None else b"",
version="",
)
+ http_message.counterparty = agent_address
+ dialogue = cast(Optional[HttpDialogue], dialogues.update(http_message))
+ assert dialogue is not None, "Could not create dialogue for message={}".format(
+ http_message
+ )
+ self.id = dialogue.incomplete_dialogue_label
envelope = Envelope(
to=agent_address,
- sender=self.id,
- protocol_id=PublicId.from_str("fetchai/http:0.3.0"),
+ sender=str(connection_id),
+ protocol_id=http_message.protocol_id,
context=context,
message=http_message,
)
@@ -177,25 +188,20 @@ class Response(web.Response):
"""Generic response object."""
@classmethod
- def from_envelope(cls, envelope: Envelope) -> "Response":
+ def from_message(cls, http_message: HttpMessage) -> "Response":
"""
Turn an envelope into a response.
- :param envelope: the envelope
+ :param http_message: the http_message
:return: the response
"""
- assert isinstance(
- envelope.message, HttpMessage
- ), "Message not of type HttpMessage"
-
- http_message = cast(HttpMessage, envelope.message)
if http_message.performative == HttpMessage.Performative.RESPONSE:
response = cls(
status=http_message.status_code,
reason=http_message.status_text,
body=http_message.bodyy,
)
- else:
+ else: # pragma: nocover
response = cls(status=SERVER_ERROR, text="Server error")
return response
@@ -204,7 +210,10 @@ class APISpec:
"""API Spec class to verify a request against an OpenAPI/Swagger spec."""
def __init__(
- self, api_spec_path: Optional[str] = None, server: Optional[str] = None
+ self,
+ api_spec_path: Optional[str] = None,
+ server: Optional[str] = None,
+ logger: logging.Logger = _default_logger,
):
"""
Initialize the API spec.
@@ -212,6 +221,7 @@ def __init__(
:param api_spec_path: Directory API path and filename of the API spec YAML source file.
"""
self._validator = None # type: Optional[RequestValidator]
+ self.logger = logger
if api_spec_path is not None:
try:
api_spec_dict = read_yaml_file(api_spec_path)
@@ -220,11 +230,11 @@ def __init__(
api_spec = create_spec(api_spec_dict)
self._validator = RequestValidator(api_spec)
except OpenAPIValidationError as e: # pragma: nocover
- logger.error(
+ self.logger.error(
f"API specification YAML source file not correctly formatted: {str(e)}"
)
except Exception:
- logger.exception(
+ self.logger.exception(
"API specification YAML source file not correctly formatted."
)
raise
@@ -237,13 +247,13 @@ def verify(self, request: Request) -> bool:
:return: whether or not the request conforms with the API spec
"""
if self._validator is None:
- logger.debug("Skipping API verification!")
+ self.logger.debug("Skipping API verification!")
return True
try:
validate_request(self._validator, request)
except Exception: # pragma: nocover # pylint: disable=broad-except
- logger.exception("APISpec verify error")
+ self.logger.exception("APISpec verify error")
return False
return True
@@ -325,6 +335,7 @@ def __init__(
connection_id: PublicId,
restricted_to_protocols: Set[PublicId],
timeout_window: float = 5.0,
+ logger: logging.Logger = _default_logger,
):
"""
Initialize a channel and process the initial API specification from the file path (if given).
@@ -343,11 +354,11 @@ def __init__(
self.server_address = "http://{}:{}".format(self.host, self.port)
self.restricted_to_protocols = restricted_to_protocols
- self._api_spec = APISpec(api_spec_path, self.server_address)
+ self._api_spec = APISpec(api_spec_path, self.server_address, logger)
self.timeout_window = timeout_window
self.http_server: Optional[web.TCPSite] = None
self.pending_requests: Dict[RequestId, Future] = {}
-
+ self._dialogues = HttpDialogues(self.address)
self.logger = logger
@property
@@ -398,26 +409,33 @@ async def _http_handler(self, http_request: BaseRequest) -> Response:
return Response(status=NOT_FOUND, reason="Request Not Found")
try:
- self.pending_requests[request.id] = Future()
# turn request into envelope
- envelope = request.to_envelope(self.connection_id, self.address)
+ envelope = request.to_envelope_and_set_id(
+ self.connection_id, self.address, dialogues=self._dialogues,
+ )
+
+ self.pending_requests[request.id] = Future()
+
# send the envelope to the agent's inbox (via self.in_queue)
await self._in_queue.put(envelope)
# wait for response envelope within given timeout window (self.timeout_window) to appear in dispatch_ready_envelopes
- response_envelope = await asyncio.wait_for(
- self.pending_requests[request.id], timeout=self.RESPONSE_TIMEOUT
+ response_message = await asyncio.wait_for(
+ self.pending_requests[request.id], timeout=self.RESPONSE_TIMEOUT,
)
- return Response.from_envelope(response_envelope)
+
+ return Response.from_message(response_message)
except asyncio.TimeoutError:
return Response(status=REQUEST_TIMEOUT, reason="Request Timeout")
except BaseException: # pragma: nocover # pylint: disable=broad-except
+ self.logger.exception("Error during handling incoming request")
return Response(
status=SERVER_ERROR, reason="Server Error", text=format_exc()
)
finally:
- self.pending_requests.pop(request.id, None)
+ if request.is_id_set:
+ self.pending_requests.pop(request.id, None)
async def _start_http_server(self) -> None:
"""Start http server."""
@@ -444,16 +462,31 @@ def send(self, envelope: Envelope) -> None:
)
raise ValueError("Cannot send message.")
- future = self.pending_requests.pop(envelope.to, None)
+ http_message = cast(HttpMessage, envelope.message)
+ message = copy.copy(
+ http_message
+ ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ message.is_incoming = True # TODO: fix; should be done by framework
+ message.counterparty = envelope.sender # TODO: fix; should be done by framework
+
+ dialogue = self._dialogues.update(message)
+
+ if dialogue is None:
+ self.logger.warning(
+ "Could not create dialogue for message={}".format(message)
+ )
+ return
+
+ future = self.pending_requests.pop(dialogue.incomplete_dialogue_label, None)
if not future:
self.logger.warning(
- "Dropping envelope for request id {} which has timed out.".format(
- envelope.to
+ "Dropping message={} for incomplete_dialogue_label={} which has timed out.".format(
+ message, dialogue.incomplete_dialogue_label
)
)
else:
- future.set_result(envelope)
+ future.set_result(message)
async def disconnect(self) -> None:
"""
@@ -489,6 +522,7 @@ def __init__(self, **kwargs):
api_spec_path,
connection_id=self.connection_id,
restricted_to_protocols=self.restricted_to_protocols,
+ logger=self.logger,
)
async def connect(self) -> None:
@@ -497,10 +531,15 @@ async def connect(self) -> None:
:return: None
"""
- if not self.connection_status.is_connected:
- self.channel.logger = self.logger
- await self.channel.connect(loop=self.loop)
- self.connection_status.is_connected = not self.channel.is_stopped
+ if self.is_connected:
+ return
+ self._state.set(ConnectionStates.connecting)
+ self.channel.logger = self.logger
+ await self.channel.connect(loop=self.loop)
+ if self.channel.is_stopped:
+ self._state.set(ConnectionStates.disconnected)
+ else:
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""
@@ -508,9 +547,11 @@ async def disconnect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected:
- self.connection_status.is_connected = False
- await self.channel.disconnect()
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
+ await self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: "Envelope") -> None:
"""
@@ -519,7 +560,7 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelop
:return: None
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
@@ -531,7 +572,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
:return: the envelope received, or None.
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
diff --git a/packages/fetchai/connections/http_server/connection.yaml b/packages/fetchai/connections/http_server/connection.yaml
index e020af1227..f04bdc7a94 100644
--- a/packages/fetchai/connections/http_server/connection.yaml
+++ b/packages/fetchai/connections/http_server/connection.yaml
@@ -1,16 +1,17 @@
name: http_server
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The HTTP server connection that wraps http server implementing a RESTful
API specification.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmXjfGyzKJ85U8gYhU24AqV8t6m1jxR7QxrdyzzonZf2JB
__init__.py: Qmb6JEAkJeb5JweqrSGiGoQp1vGXqddjGgb9WMkm2phTgA
- connection.py: QmTDwwg4Qah191WaiFizdhGGDs56jha26NWcjGkmDTDt5q
+ connection.py: QmQQfnyLBpVSnxY1xD1piA5KKAr65GTLhzFSRa4kcREtwi
fingerprint_ignore_patterns: []
protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
class_name: HTTPServerConnection
config:
api_spec_path: ''
@@ -18,7 +19,7 @@ config:
port: 8000
excluded_protocols: []
restricted_to_protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
dependencies:
aiohttp:
version: '>=3.6.2,<3.7'
diff --git a/packages/fetchai/connections/ledger/README.md b/packages/fetchai/connections/ledger/README.md
new file mode 100644
index 0000000000..5120150b1c
--- /dev/null
+++ b/packages/fetchai/connections/ledger/README.md
@@ -0,0 +1,11 @@
+# Ledger connection
+
+The ledger connection wraps the APIs needed to interact with multiple ledgers, including smart contracts deployed on those ledgers.
+
+The AEA communicates with the ledger connection via the `fetchai/ledger_api:0.2.0` and `fetchai/contract_api:0.2.0` protocols.
+
+The connection uses the ledger apis registered in the ledger api registry.
+
+## Usage
+
+First, add the connection to your AEA project (`aea add connection fetchai/ledger:0.3.0`). Optionally, update the `ledger_apis` in `config` of `connection.yaml`.
diff --git a/packages/fetchai/connections/ledger/base.py b/packages/fetchai/connections/ledger/base.py
index a585ba1103..29005b8900 100644
--- a/packages/fetchai/connections/ledger/base.py
+++ b/packages/fetchai/connections/ledger/base.py
@@ -16,24 +16,26 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""This module contains base classes for the ledger API connection."""
import asyncio
+import copy
+import logging
from abc import ABC, abstractmethod
from asyncio import Task
from concurrent.futures._base import Executor
+from logging import Logger
from typing import Any, Callable, Dict, Optional
from aea.configurations.base import PublicId
-from aea.connections.base import ConnectionStatus
from aea.crypto.base import LedgerApi
from aea.crypto.registries import Registry, ledger_apis_registry
+from aea.helpers.async_utils import AsyncState
from aea.helpers.dialogue.base import Dialogue, Dialogues
from aea.mail.base import Envelope
from aea.protocols.base import Message
-CONNECTION_ID = PublicId.from_str("fetchai/ledger:0.2.0")
+CONNECTION_ID = PublicId.from_str("fetchai/ledger:0.3.0")
class RequestDispatcher(ABC):
@@ -44,10 +46,11 @@ class RequestDispatcher(ABC):
def __init__(
self,
- connection_status: ConnectionStatus,
+ connection_state: AsyncState,
loop: Optional[asyncio.AbstractEventLoop] = None,
executor: Optional[Executor] = None,
api_configs: Optional[Dict[str, Dict[str, str]]] = None,
+ logger: Optional[Logger] = None,
):
"""
Initialize the request dispatcher.
@@ -55,10 +58,17 @@ def __init__(
:param loop: the asyncio loop.
:param executor: an executor.
"""
- self.connection_status = connection_status
+ self.connection_state = connection_state
self.loop = loop if loop is not None else asyncio.get_event_loop()
self.executor = executor
self._api_configs = api_configs
+ self.logger = (
+ logger
+ if logger is not None
+ else logging.getLogger(
+ "aea.packages.fetchai.connections.ledger.contract_dispatcher"
+ )
+ )
def api_config(self, ledger_id: str) -> Dict[str, str]:
"""Get api config."""
@@ -97,10 +107,12 @@ def dispatch(self, envelope: Envelope) -> Task:
:return: an awaitable.
"""
assert isinstance(envelope.message, Message)
- message = envelope.message
+ message_original = envelope.message
+ message = copy.copy(message_original)
ledger_id = self.get_ledger_id(message)
api = self.ledger_api_registry.make(ledger_id, **self.api_config(ledger_id))
message.is_incoming = True
+ message.counterparty = message_original.sender
dialogue = self.dialogues.update(message)
assert dialogue is not None, "No dialogue created."
performative = message.performative
diff --git a/packages/fetchai/connections/ledger/connection.py b/packages/fetchai/connections/ledger/connection.py
index 6ffcf8c3ad..380d42bc79 100644
--- a/packages/fetchai/connections/ledger/connection.py
+++ b/packages/fetchai/connections/ledger/connection.py
@@ -23,7 +23,7 @@
from collections import deque
from typing import Deque, Dict, List, Optional, cast
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import Envelope
from aea.protocols.base import Message
@@ -68,18 +68,35 @@ def event_new_receiving_task(self) -> asyncio.Event:
async def connect(self) -> None:
"""Set up the connection."""
+
+ if self.is_connected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.connecting)
+
self._ledger_dispatcher = LedgerApiRequestDispatcher(
- self.connection_status, loop=self.loop, api_configs=self.api_configs
+ self._state,
+ loop=self.loop,
+ api_configs=self.api_configs,
+ logger=self.logger,
)
self._contract_dispatcher = ContractApiRequestDispatcher(
- self.connection_status, loop=self.loop, api_configs=self.api_configs
+ self._state,
+ loop=self.loop,
+ api_configs=self.api_configs,
+ logger=self.logger,
)
self._event_new_receiving_task = asyncio.Event(loop=self.loop)
- self.connection_status.is_connected = True
+
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""Tear down the connection."""
- self.connection_status.is_connected = False
+ if self.is_disconnected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.disconnecting)
+
for task in self.receiving_tasks:
if not task.cancelled(): # pragma: nocover
task.cancel()
@@ -87,6 +104,8 @@ async def disconnect(self) -> None:
self._contract_dispatcher = None
self._event_new_receiving_task = None
+ self._state.set(ConnectionStates.disconnected)
+
async def send(self, envelope: "Envelope") -> None:
"""
Send an envelope.
diff --git a/packages/fetchai/connections/ledger/connection.yaml b/packages/fetchai/connections/ledger/connection.yaml
index dfe2b59f9a..fc748456a2 100644
--- a/packages/fetchai/connections/ledger/connection.yaml
+++ b/packages/fetchai/connections/ledger/connection.yaml
@@ -1,19 +1,20 @@
name: ledger
author: fetchai
-version: 0.2.0
+version: 0.3.0
description: A connection to interact with any ledger API and contract API.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmRJAjD29rx9W7mZfW7M9oxGaN42rXVfQP55xsvian7rb9
__init__.py: QmZvYZ5ECcWwqiNGh8qNTg735wu51HqaLxTSifUxkQ4KGj
- base.py: QmTuJp4ch7gMrhrK9tTDtJ8wtZbaaG2TLqGJTkSojaMLm8
- connection.py: QmTPj9CGkDtPMT7bXXDQi3i8zoRvSJvPVr6fyK2giPjmW1
- contract_dispatcher.py: QmSkA75HLriYkKXd7wcFqchSkrQsP8RxHK1be5qtXTpgwz
- ledger_dispatcher.py: QmaETup4DzFYVkembK2yZL6TfbNDL13fdr6i29CPubG3CN
+ base.py: QmTD7gWtgQiLsUwU2sc4VSmYi8gyxVebLbeGd7XcR4EgX9
+ connection.py: QmXsfh1YGpdzGNCs7zCeEjRvYJHzUKt7Qihk2EgPBpmdiy
+ contract_dispatcher.py: QmURhoVnwcGAZgkHXZQKekXQiNfDNRdk9JW4CstVJmCQhn
+ ledger_dispatcher.py: QmbJMFKojEd2nmBZZcpR9JovsRLQk3swUjzHHkcd8N2qbZ
fingerprint_ignore_patterns: []
protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/ledger_api:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/ledger_api:0.2.0
class_name: LedgerConnection
config:
ledger_apis:
@@ -26,6 +27,6 @@ config:
network: testnet
excluded_protocols: []
restricted_to_protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/ledger_api:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/ledger_api:0.2.0
dependencies: {}
diff --git a/packages/fetchai/connections/ledger/contract_dispatcher.py b/packages/fetchai/connections/ledger/contract_dispatcher.py
index aebdac3b85..08604ae057 100644
--- a/packages/fetchai/connections/ledger/contract_dispatcher.py
+++ b/packages/fetchai/connections/ledger/contract_dispatcher.py
@@ -18,11 +18,13 @@
# ------------------------------------------------------------------------------
"""This module contains the implementation of the contract API request dispatcher."""
-from typing import cast
+import inspect
+from typing import Callable, Optional, cast
-from aea.contracts import contract_registry
+from aea.contracts import Contract, contract_registry
from aea.crypto.base import LedgerApi
from aea.crypto.registries import Registry
+from aea.exceptions import AEAException
from aea.helpers.dialogue.base import (
Dialogue as BaseDialogue,
DialogueLabel as BaseDialogueLabel,
@@ -94,7 +96,7 @@ def dialogues(self) -> BaseDialogues:
return self._contract_api_dialogues
@property
- def contract_registry(self) -> Registry:
+ def contract_registry(self) -> Registry[Contract]:
"""Get the contract registry."""
return contract_registry
@@ -130,126 +132,227 @@ def get_error_message(
dialogue.update(response)
return response
+ def dispatch_request(
+ self,
+ ledger_api: LedgerApi,
+ message: ContractApiMessage,
+ dialogue: ContractApiDialogue,
+ response_builder: Callable[[bytes], ContractApiMessage],
+ ) -> ContractApiMessage:
+ """
+ Dispatch a request to a user-defined contract method.
+
+ :param ledger_api: the ledger apis.
+ :param message: the contract API request message.
+ :param dialogue: the contract API dialogue.
+ :param response_builder: callable that from bytes builds a contract API message.
+ :return: the response message.
+ """
+ contract = self.contract_registry.make(message.contract_id)
+ try:
+ data = self._get_data(ledger_api, message, contract)
+ response = response_builder(data)
+ response.counterparty = message.counterparty
+ dialogue.update(response)
+ except AEAException as e:
+ self.logger.error(str(e))
+ response = self.get_error_message(e, ledger_api, message, dialogue)
+ except Exception as e: # pylint: disable=broad-except # pragma: nocover
+ self.logger.error(
+ f"An error occurred while processing the contract api request: '{str(e)}'."
+ )
+ response = self.get_error_message(e, ledger_api, message, dialogue)
+ return response
+
def get_state(
self,
- api: LedgerApi,
+ ledger_api: LedgerApi,
message: ContractApiMessage,
dialogue: ContractApiDialogue,
) -> ContractApiMessage:
"""
Send the request 'get_state'.
- :param api: the API object.
+ :param ledger_api: the API object.
:param message: the Ledger API message
:param dialogue: the contract API dialogue
:return: None
"""
- contract = self.contract_registry.make(message.contract_id)
- method_to_call = getattr(contract, message.callable)
- try:
- data = method_to_call(api, message.contract_address, **message.kwargs.body)
- response = ContractApiMessage(
+
+ def build_response(data: bytes) -> ContractApiMessage:
+ return ContractApiMessage(
performative=ContractApiMessage.Performative.STATE,
message_id=message.message_id + 1,
target=message.message_id,
dialogue_reference=dialogue.dialogue_label.dialogue_reference,
state=State(message.ledger_id, data),
)
- response.counterparty = message.counterparty
- dialogue.update(response)
- except Exception as e: # pylint: disable=broad-except # pragma: nocover
- response = self.get_error_message(e, api, message, dialogue)
- return response
+
+ return self.dispatch_request(ledger_api, message, dialogue, build_response)
def get_deploy_transaction(
self,
- api: LedgerApi,
+ ledger_api: LedgerApi,
message: ContractApiMessage,
dialogue: ContractApiDialogue,
) -> ContractApiMessage:
"""
Send the request 'get_raw_transaction'.
- :param api: the API object.
+ :param ledger_api: the API object.
:param message: the Ledger API message
:param dialogue: the contract API dialogue
:return: None
"""
- contract = self.contract_registry.make(message.contract_id)
- method_to_call = getattr(contract, message.callable)
- try:
- tx = method_to_call(api, **message.kwargs.body)
- response = ContractApiMessage(
+
+ def build_response(tx: bytes) -> ContractApiMessage:
+ return ContractApiMessage(
performative=ContractApiMessage.Performative.RAW_TRANSACTION,
message_id=message.message_id + 1,
target=message.message_id,
dialogue_reference=dialogue.dialogue_label.dialogue_reference,
raw_transaction=RawTransaction(message.ledger_id, tx),
)
- response.counterparty = message.counterparty
- dialogue.update(response)
- except Exception as e: # pylint: disable=broad-except # pragma: nocover
- response = self.get_error_message(e, api, message, dialogue)
- return response
+
+ return self.dispatch_request(ledger_api, message, dialogue, build_response)
def get_raw_transaction(
self,
- api: LedgerApi,
+ ledger_api: LedgerApi,
message: ContractApiMessage,
dialogue: ContractApiDialogue,
) -> ContractApiMessage:
"""
Send the request 'get_raw_transaction'.
- :param api: the API object.
+ :param ledger_api: the API object.
:param message: the Ledger API message
:param dialogue: the contract API dialogue
:return: None
"""
- contract = self.contract_registry.make(message.contract_id)
- method_to_call = getattr(contract, message.callable)
- try:
- tx = method_to_call(api, message.contract_address, **message.kwargs.body)
- response = ContractApiMessage(
+
+ def build_response(tx: bytes) -> ContractApiMessage:
+ return ContractApiMessage(
performative=ContractApiMessage.Performative.RAW_TRANSACTION,
message_id=message.message_id + 1,
target=message.message_id,
dialogue_reference=dialogue.dialogue_label.dialogue_reference,
raw_transaction=RawTransaction(message.ledger_id, tx),
)
- response.counterparty = message.counterparty
- dialogue.update(response)
- except Exception as e: # pylint: disable=broad-except # pragma: nocover
- response = self.get_error_message(e, api, message, dialogue)
- return response
+
+ return self.dispatch_request(ledger_api, message, dialogue, build_response)
def get_raw_message(
self,
- api: LedgerApi,
+ ledger_api: LedgerApi,
message: ContractApiMessage,
dialogue: ContractApiDialogue,
) -> ContractApiMessage:
"""
Send the request 'get_raw_message'.
- :param api: the API object.
+ :param ledger_api: the ledger API object.
:param message: the Ledger API message
:param dialogue: the contract API dialogue
:return: None
"""
- contract = self.contract_registry.make(message.contract_id)
- method_to_call = getattr(contract, message.callable)
- try:
- rm = method_to_call(api, message.contract_address, **message.kwargs.body)
- response = ContractApiMessage(
+
+ def build_response(rm: bytes) -> ContractApiMessage:
+ return ContractApiMessage(
performative=ContractApiMessage.Performative.RAW_MESSAGE,
message_id=message.message_id + 1,
target=message.message_id,
dialogue_reference=dialogue.dialogue_label.dialogue_reference,
raw_message=RawMessage(message.ledger_id, rm),
)
- response.counterparty = message.counterparty
- dialogue.update(response)
- except Exception as e: # pylint: disable=broad-except # pragma: nocover
- response = self.get_error_message(e, api, message, dialogue)
- return response
+
+ return self.dispatch_request(ledger_api, message, dialogue, build_response)
+
+ def _get_data(
+ self, api: LedgerApi, message: ContractApiMessage, contract: Contract,
+ ) -> bytes:
+ """Get the data from the contract method, either from the stub or
+ from the callable specified by the message."""
+ # first, check if the custom handler for this type of request has been implemented.
+ data = self._call_stub(api, message, contract)
+ if data is not None:
+ return data
+
+ # then, check if there is the handler for the provided callable.
+ data = self._validate_and_call_callable(api, message, contract)
+ return data
+
+ @staticmethod
+ def _call_stub(
+ ledger_api: LedgerApi, message: ContractApiMessage, contract: Contract
+ ) -> Optional[bytes]:
+ """Try to call stub methods associated to the
+ contract API request performative."""
+ try:
+ method: Callable = getattr(contract, message.performative.value)
+ if message.performative in [
+ ContractApiMessage.Performative.GET_STATE,
+ ContractApiMessage.Performative.GET_RAW_MESSAGE,
+ ContractApiMessage.Performative.GET_RAW_TRANSACTION,
+ ]:
+ args, kwargs = (
+ [ledger_api, message.contract_address],
+ message.kwargs.body,
+ )
+ elif message.performative in [ # pragma: nocover
+ ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
+ ]:
+ args, kwargs = [ledger_api], message.kwargs.body
+ else: # pragma: nocover
+ raise AEAException(f"Unexpected performative: {message.performative}")
+ data = method(*args, **kwargs)
+ return data
+ except (AttributeError, NotImplementedError):
+ return None
+
+ @staticmethod
+ def _validate_and_call_callable(
+ api: LedgerApi, message: ContractApiMessage, contract: Contract
+ ):
+ """
+ Validate a Contract callable, given the performative.
+
+ In particular:
+ - if the performative is either 'get_state' or 'get_raw_transaction', the signature
+ must accept ledger api as first argument and contract address as second argument,
+ plus keyword arguments.
+ - if the performative is either 'get_deploy_transaction' or 'get_raw_message', the signature
+ must accept ledger api as first argument, plus keyword arguments.
+
+ :param api: the ledger api object.
+ :param message: the contract api request.
+ :param contract: the contract instance.
+ :return: the data generated by the method.
+ """
+ try:
+ method_to_call = getattr(contract, message.callable)
+ except AttributeError:
+ raise AEAException(
+ f"Cannot find {message.callable} in contract {type(contract)}"
+ )
+ full_args_spec = inspect.getfullargspec(method_to_call)
+ if message.performative in [
+ ContractApiMessage.Performative.GET_STATE,
+ ContractApiMessage.Performative.GET_RAW_MESSAGE,
+ ContractApiMessage.Performative.GET_RAW_TRANSACTION,
+ ]:
+ if len(full_args_spec.args) < 2:
+ raise AEAException(
+ f"Expected two or more positional arguments, got {len(full_args_spec.args)}"
+ )
+ return method_to_call(api, message.contract_address, **message.kwargs.body)
+ elif message.performative in [
+ ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
+ ]:
+ if len(full_args_spec.args) < 1:
+ raise AEAException(
+ f"Expected one or more positional arguments, got {len(full_args_spec.args)}"
+ )
+ return method_to_call(api, **message.kwargs.body)
+ else: # pragma: nocover
+ raise AEAException(f"Unexpected performative: {message.performative}")
diff --git a/packages/fetchai/connections/ledger/ledger_dispatcher.py b/packages/fetchai/connections/ledger/ledger_dispatcher.py
index a5b6566060..0c4832b39b 100644
--- a/packages/fetchai/connections/ledger/ledger_dispatcher.py
+++ b/packages/fetchai/connections/ledger/ledger_dispatcher.py
@@ -16,11 +16,11 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""This module contains the implementation of the ledger API request dispatcher."""
import time
from typing import cast
+from aea.connections.base import ConnectionStates
from aea.crypto.base import LedgerApi
from aea.helpers.dialogue.base import (
Dialogue as BaseDialogue,
@@ -194,7 +194,7 @@ def get_transaction_receipt(
while (
not is_settled
and attempts < self.MAX_ATTEMPTS
- and self.connection_status.is_connected
+ and self.connection_state.get() == ConnectionStates.connected
):
time.sleep(self.TIMEOUT)
transaction_receipt = api.get_transaction_receipt(
@@ -207,7 +207,7 @@ def get_transaction_receipt(
while (
transaction is None
and attempts < self.MAX_ATTEMPTS
- and self.connection_status.is_connected
+ and self.connection_state.get() == ConnectionStates.connected
):
time.sleep(self.TIMEOUT)
transaction = api.get_transaction(message.transaction_digest.body)
diff --git a/packages/fetchai/connections/local/README.md b/packages/fetchai/connections/local/README.md
new file mode 100644
index 0000000000..65e59cbd02
--- /dev/null
+++ b/packages/fetchai/connections/local/README.md
@@ -0,0 +1,7 @@
+# Local connection
+
+OEF compatible local connection for testing purposes only.
+
+## Usage
+
+OEF compatible connection to be used for testing, does not interact with external nodes. Does not preserve state on restart.
diff --git a/packages/fetchai/connections/local/connection.py b/packages/fetchai/connections/local/connection.py
index dc82107b24..949628744a 100644
--- a/packages/fetchai/connections/local/connection.py
+++ b/packages/fetchai/connections/local/connection.py
@@ -16,10 +16,10 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""Extension to the Local Node."""
import asyncio
+import copy
import logging
from asyncio import AbstractEventLoop, Queue
from collections import defaultdict
@@ -27,28 +27,33 @@
from typing import Dict, List, Optional, Tuple, cast
from aea.configurations.base import ProtocolId, PublicId
-from aea.connections.base import Connection
-from aea.helpers.search.models import Description, Query
+from aea.connections.base import Connection, ConnectionStates
+from aea.helpers.search.models import Description
from aea.mail.base import AEAConnectionError, Address, Envelope
from aea.protocols.default.message import DefaultMessage
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue,
+ OefSearchDialogues,
+)
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
-logger = logging.getLogger("aea.packages.fetchai.connections.local")
+_default_logger = logging.getLogger("aea.packages.fetchai.connections.local")
TARGET = 0
MESSAGE_ID = 1
RESPONSE_TARGET = MESSAGE_ID
RESPONSE_MESSAGE_ID = MESSAGE_ID + 1
STUB_DIALOGUE_ID = 0
-DEFAULT_OEF = "default_oef"
-PUBLIC_ID = PublicId.from_str("fetchai/local:0.4.0")
+PUBLIC_ID = PublicId.from_str("fetchai/local:0.5.0")
class LocalNode:
"""A light-weight local implementation of a OEF Node."""
- def __init__(self, loop: AbstractEventLoop = None):
+ def __init__(
+ self, loop: AbstractEventLoop = None, logger: logging.Logger = _default_logger
+ ):
"""
Initialize a local (i.e. non-networked) implementation of an OEF Node.
@@ -63,6 +68,9 @@ def __init__(self, loop: AbstractEventLoop = None):
self._out_queues = {} # type: Dict[str, asyncio.Queue]
self._receiving_loop_task = None # type: Optional[asyncio.Task]
+ self.address: Optional[Address] = None
+ self._dialogues: Optional[OefSearchDialogues] = None
+ self.logger = logger
def __enter__(self):
"""Start the local node."""
@@ -79,10 +87,10 @@ def _run_loop(self):
This method is supposed to be run only in the Multiplexer thread.
"""
- logger.debug("Starting threaded asyncio loop...")
+ self.logger.debug("Starting threaded asyncio loop...")
asyncio.set_event_loop(self._loop)
self._loop.run_forever()
- logger.debug("Asyncio loop has been stopped.")
+ self.logger.debug("Asyncio loop has been stopped.")
async def connect(
self, address: Address, writer: asyncio.Queue
@@ -101,6 +109,10 @@ async def connect(
q = self._in_queue # type: asyncio.Queue
self._out_queues[address] = writer
+ self.address = address
+ self._dialogues = OefSearchDialogues(
+ agent_address=str(OEFLocalConnection.connection_id)
+ )
return q
def start(self):
@@ -110,7 +122,7 @@ def start(self):
self._receiving_loop_task = asyncio.run_coroutine_threadsafe(
self.receiving_loop(), loop=self._loop
)
- logger.debug("Local node has been started.")
+ self.logger.debug("Local node has been started.")
def stop(self):
"""Stop the node."""
@@ -127,9 +139,9 @@ async def receiving_loop(self):
while True:
envelope = await self._in_queue.get()
if envelope is None:
- logger.debug("Receiving loop terminated.")
+ self.logger.debug("Receiving loop terminated.")
return
- logger.debug("Handling envelope: {}".format(envelope))
+ self.logger.debug("Handling envelope: {}".format(envelope))
await self._handle_envelope(envelope)
async def _handle_envelope(self, envelope: Envelope) -> None:
@@ -138,7 +150,7 @@ async def _handle_envelope(self, envelope: Envelope) -> None:
:param envelope: the envelope
:return: None
"""
- if envelope.protocol_id == ProtocolId.from_str("fetchai/oef_search:0.3.0"):
+ if envelope.protocol_id == ProtocolId.from_str("fetchai/oef_search:0.4.0"):
await self._handle_oef_message(envelope)
else:
await self._handle_agent_message(envelope)
@@ -152,20 +164,24 @@ async def _handle_oef_message(self, envelope: Envelope) -> None:
assert isinstance(
envelope.message, OefSearchMessage
), "Message not of type OefSearchMessage"
- oef_message = cast(OefSearchMessage, envelope.message)
- sender = envelope.sender
+ oef_message, dialogue = self._get_message_and_dialogue(envelope)
+
+ if dialogue is None:
+ self.logger.warning(
+ "Could not create dialogue for message={}".format(oef_message)
+ )
+ return
+
if oef_message.performative == OefSearchMessage.Performative.REGISTER_SERVICE:
- await self._register_service(sender, oef_message.service_description)
+ await self._register_service(
+ envelope.sender, oef_message.service_description
+ )
elif (
oef_message.performative == OefSearchMessage.Performative.UNREGISTER_SERVICE
):
- await self._unregister_service(
- sender, oef_message.dialogue_reference, oef_message.service_description
- )
+ await self._unregister_service(oef_message, dialogue)
elif oef_message.performative == OefSearchMessage.Performative.SEARCH_SERVICES:
- await self._search_services(
- sender, oef_message.dialogue_reference, oef_message.query
- )
+ await self._search_services(oef_message, dialogue)
else:
# request not recognized
pass
@@ -191,7 +207,7 @@ async def _handle_agent_message(self, envelope: Envelope) -> None:
)
error_envelope = Envelope(
to=envelope.sender,
- sender=DEFAULT_OEF,
+ sender=str(OEFLocalConnection.connection_id),
protocol_id=DefaultMessage.protocol_id,
message=msg,
)
@@ -214,32 +230,32 @@ async def _register_service(
self.services[address].append(service_description)
async def _unregister_service(
- self,
- address: Address,
- dialogue_reference: Tuple[str, str],
- service_description: Description,
+ self, oef_search_msg: OefSearchMessage, dialogue: OefSearchDialogue,
) -> None:
"""
Unregister a service agent.
- :param address: the address of the service agent to be unregistered.
- :param dialogue_reference: the dialogue_reference.
- :param service_description: the description of the service agent to be unregistered.
+ :param oef_search_msg: the incoming message.
+ :param dialogue: the dialogue.
:return: None
"""
+ service_description = oef_search_msg.service_description
+ address = oef_search_msg.sender
async with self._lock:
if address not in self.services:
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.OEF_ERROR,
- dialogue_reference=(dialogue_reference[0], dialogue_reference[0]),
- target=RESPONSE_TARGET,
- message_id=RESPONSE_MESSAGE_ID,
+ target=oef_search_msg.message_id,
+ message_id=oef_search_msg.message_id + 1,
oef_error_operation=OefSearchMessage.OefErrorOperation.UNREGISTER_SERVICE,
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
)
+ msg.counterparty = oef_search_msg.sender
+ assert dialogue.update(msg)
envelope = Envelope(
- to=address,
- sender=DEFAULT_OEF,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
await self._send(envelope)
@@ -249,7 +265,7 @@ async def _unregister_service(
self.services.pop(address)
async def _search_services(
- self, address: Address, dialogue_reference: Tuple[str, str], query: Query
+ self, oef_search_msg: OefSearchMessage, dialogue: OefSearchDialogue,
) -> None:
"""
Search the agents in the local Service Directory, and send back the result.
@@ -257,11 +273,11 @@ async def _search_services(
This is actually a dummy search, it will return all the registered agents with the specified data model.
If the data model is not specified, it will return all the agents.
- :param address: the source of the search request.
- :param dialogue_reference: the dialogue_reference.
- :param query: the query that constitutes the search.
+ :param oef_search_msg: the message.
+ :param dialogue: the dialogue.
:return: None
"""
+ query = oef_search_msg.query
result = [] # type: List[str]
if query.model is None:
result = list(set(self.services.keys()))
@@ -273,25 +289,50 @@ async def _search_services(
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_RESULT,
- dialogue_reference=(dialogue_reference[0], dialogue_reference[0]),
- target=RESPONSE_TARGET,
- message_id=RESPONSE_MESSAGE_ID,
+ target=oef_search_msg.message_id,
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ message_id=oef_search_msg.message_id + 1,
agents=tuple(sorted(set(result))),
)
+ msg.counterparty = oef_search_msg.sender
+ assert dialogue.update(msg)
+
envelope = Envelope(
- to=address,
- sender=DEFAULT_OEF,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
await self._send(envelope)
+ def _get_message_and_dialogue(
+ self, envelope: Envelope
+ ) -> Tuple[OefSearchMessage, Optional[OefSearchDialogue]]:
+ """
+ Get a message copy and dialogue related to this message.
+
+ :param envelope: incoming envelope
+
+ :return: Tuple[MEssage, Optional[Dialogue]]
+ """
+ assert self._dialogues is not None, "Call connect before!"
+ message_orig = cast(OefSearchMessage, envelope.message)
+ message = copy.copy(
+ message_orig
+ ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ message.is_incoming = True # TODO: fix; should be done by framework
+ message.counterparty = (
+ message_orig.sender
+ ) # TODO: fix; should be done by framework
+ dialogue = cast(OefSearchDialogue, self._dialogues.update(message))
+ return message, dialogue
+
async def _send(self, envelope: Envelope):
"""Send a message."""
destination = envelope.to
destination_queue = self._out_queues[destination]
destination_queue._loop.call_soon_threadsafe(destination_queue.put_nowait, envelope) # type: ignore # pylint: disable=protected-access
- logger.debug("Send envelope {}".format(envelope))
+ self.logger.debug("Send envelope {}".format(envelope))
async def disconnect(self, address: Address) -> None:
"""
@@ -331,24 +372,28 @@ def __init__(self, local_node: Optional[LocalNode] = None, **kwargs):
async def connect(self) -> None:
"""Connect to the local OEF Node."""
assert self._local_node is not None, "No local node set!"
- if not self.connection_status.is_connected:
- self._reader = Queue()
- self._writer = await self._local_node.connect(self.address, self._reader)
- self.connection_status.is_connected = True
+ if self.is_connected:
+ return
+ self._state.set(ConnectionStates.connecting)
+ self._reader = Queue()
+ self._writer = await self._local_node.connect(self.address, self._reader)
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""Disconnect from the local OEF Node."""
assert self._local_node is not None, "No local node set!"
- if self.connection_status.is_connected:
- assert self._reader is not None
- await self._local_node.disconnect(self.address)
- await self._reader.put(None)
- self._reader, self._writer = None, None
- self.connection_status.is_connected = False
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
+ assert self._reader is not None
+ await self._local_node.disconnect(self.address)
+ await self._reader.put(None)
+ self._reader, self._writer = None, None
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: Envelope):
"""Send a message."""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise AEAConnectionError(
"Connection not established yet. Please use 'connect()'."
)
@@ -360,7 +405,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
:return: the envelope received, or None.
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise AEAConnectionError(
"Connection not established yet. Please use 'connect()'."
)
diff --git a/packages/fetchai/connections/local/connection.yaml b/packages/fetchai/connections/local/connection.yaml
index 57c124dd66..10b9dc44ee 100644
--- a/packages/fetchai/connections/local/connection.yaml
+++ b/packages/fetchai/connections/local/connection.yaml
@@ -1,15 +1,16 @@
name: local
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The local connection provides a stub for an OEF node.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmbK7MtyAVqh2LmSh9TY6yBZqfWaAXURP4rQGATyP2hTKC
__init__.py: QmeeoX5E38Ecrb1rLdeFyyxReHLrcJoETnBcPbcNWVbiKG
- connection.py: QmTNcjJSBWRrB5srBTEpjRfbvDuxJtsFcdhYJ1UYsLGqKT
+ connection.py: QmYoRmLSYYS88HdzmT3sQxMDkk5CwCiWudAvfRyArCoQAj
fingerprint_ignore_patterns: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
class_name: OEFLocalConnection
config: {}
excluded_protocols: []
diff --git a/packages/fetchai/connections/oef/README.md b/packages/fetchai/connections/oef/README.md
new file mode 100644
index 0000000000..b8faac57fb
--- /dev/null
+++ b/packages/fetchai/connections/oef/README.md
@@ -0,0 +1,7 @@
+# OEF connection
+
+Connection to interact with an OEF node (https://fetchai.github.io/oef-sdk-python/user/introduction.html).
+
+## Usage
+
+Register/unregister services, perform searches using `fetchai/oef_search:0.4.0` protocol and send messages of any protocol to other agents connected to the same node.
diff --git a/packages/fetchai/connections/oef/connection.py b/packages/fetchai/connections/oef/connection.py
index ecba75c4e5..3c44fe0488 100644
--- a/packages/fetchai/connections/oef/connection.py
+++ b/packages/fetchai/connections/oef/connection.py
@@ -19,6 +19,7 @@
"""Extension to the OEF Python SDK."""
import asyncio
+import copy
import logging
from asyncio import AbstractEventLoop, CancelledError
from concurrent.futures.thread import ThreadPoolExecutor
@@ -31,7 +32,7 @@
from oef.messages import CFP_TYPES, PROPOSE_TYPES
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.helpers.dialogue.base import Dialogue as BaseDialogue
from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
from aea.mail.base import Address, Envelope
@@ -55,7 +56,7 @@
STUB_MESSAGE_ID = 0
STUB_DIALOGUE_ID = 0
DEFAULT_OEF = "oef"
-PUBLIC_ID = PublicId.from_str("fetchai/oef:0.6.0")
+PUBLIC_ID = PublicId.from_str("fetchai/oef:0.7.0")
class OefSearchDialogues(BaseOefSearchDialogues):
@@ -387,7 +388,7 @@ def send(self, envelope: Envelope) -> None:
)
raise ValueError("Cannot send message.")
- if envelope.protocol_id == PublicId.from_str("fetchai/oef_search:0.3.0"):
+ if envelope.protocol_id == PublicId.from_str("fetchai/oef_search:0.4.0"):
self.send_oef_message(envelope)
else:
self.send_default_message(envelope)
@@ -408,7 +409,9 @@ def send_oef_message(self, envelope: Envelope) -> None:
assert isinstance(
envelope.message, OefSearchMessage
), "Message not of type OefSearchMessage"
- oef_message = cast(OefSearchMessage, envelope.message)
+ oef_message_original = cast(OefSearchMessage, envelope.message)
+ oef_message = copy.copy(oef_message_original)
+ oef_message.counterparty = oef_message_original.sender
oef_message.is_incoming = True # TODO: fix
oef_search_dialogue = cast(
OefSearchDialogue, self.oef_search_dialogues.update(oef_message)
@@ -439,7 +442,7 @@ def send_oef_message(self, envelope: Envelope) -> None:
oef_query = OEFObjectTranslator.to_oef_query(query)
self.search_services(self.oef_msg_id, oef_query)
else:
- raise ValueError("OEF request not recognized.")
+ raise ValueError("OEF request not recognized.") # pragma: nocover
def handle_failure( # pylint: disable=no-self-use
self, exception: Exception, conn
@@ -539,20 +542,19 @@ async def connect(self) -> None:
:return: None
:raises Exception if the connection to the OEF fails.
"""
- if self.connection_status.is_connected:
+ if self.is_connected:
return
+ self._state.set(ConnectionStates.connecting)
try:
self.channel.aea_logger = self.logger
- self.connection_status.is_connecting = True
self._loop = asyncio.get_event_loop()
await self.channel.connect()
- self.connection_status.is_connecting = False
- self.connection_status.is_connected = True
self._connection_check_task = self._loop.create_task(
self._connection_check()
)
+ self._state.set(ConnectionStates.connected)
except (CancelledError, Exception) as e: # pragma: no cover
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
raise e
async def _connection_check(self) -> None:
@@ -563,16 +565,15 @@ async def _connection_check(self) -> None:
:return: None
"""
- while self.connection_status.is_connected:
+ while self.is_connected:
await asyncio.sleep(2.0)
if not self.channel.get_state() == "connected": # pragma: no cover
- self.connection_status.is_connected = False
- self.connection_status.is_connecting = True
+ self._state.set(ConnectionStates.connecting)
self.logger.warning(
"Lost connection to OEFChannel. Retrying to connect soon ..."
)
await self.channel.connect()
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
self.logger.warning(
"Successfully re-established connection to OEFChannel."
)
@@ -583,16 +584,16 @@ async def disconnect(self) -> None:
:return: None
"""
- assert (
- self.connection_status.is_connected or self.connection_status.is_connecting
- ), "Call connect before disconnect."
- self.connection_status.is_connected = False
- self.connection_status.is_connecting = False
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
if self._connection_check_task is not None:
self._connection_check_task.cancel()
self._connection_check_task = None
await self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
+
async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
"""
Receive an envelope. Blocking.
@@ -620,5 +621,5 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelope to send.
:return: None
"""
- if self.connection_status.is_connected:
+ if self.is_connected:
self.channel.send(envelope)
diff --git a/packages/fetchai/connections/oef/connection.yaml b/packages/fetchai/connections/oef/connection.yaml
index 9e08dbe7cf..0699f3035d 100644
--- a/packages/fetchai/connections/oef/connection.yaml
+++ b/packages/fetchai/connections/oef/connection.yaml
@@ -1,18 +1,19 @@
name: oef
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The oef connection provides a wrapper around the OEF SDK for connection
with the OEF search and communication node.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmQEMSTNugha3vQg9xbqhvqNbg4yBtzbcaC1MsUyAQvFPD
__init__.py: QmUAen8tmoBHuCerjA3FSGKJRLG6JYyUS3chuWzPxKYzez
- connection.py: QmXutRqmffjc9xL6F8bGQ9dBPkZUP6GRZUtxsKzmdmd8G6
+ connection.py: QmYPvavTKJBL3ZFQRDS86GqdgatEVbkLbV56tvSNZMY71Y
object_translator.py: QmNYd7ikc3nYZMCXjyfen2nENHpNCZws44MNEDbzAsHrGu
fingerprint_ignore_patterns: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/oef_search:0.4.0
class_name: OEFConnection
config:
addr: 127.0.0.1
diff --git a/packages/fetchai/connections/p2p_client/connection.py b/packages/fetchai/connections/p2p_client/connection.py
index abfe90c6f8..4500fb8694 100644
--- a/packages/fetchai/connections/p2p_client/connection.py
+++ b/packages/fetchai/connections/p2p_client/connection.py
@@ -30,7 +30,7 @@
from fetch.p2p.api.http_calls import HTTPCalls
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import AEAConnectionError, Address, Envelope
logger = logging.getLogger("aea.packages.fetchai.connections.p2p_client")
@@ -174,12 +174,14 @@ async def connect(self) -> None:
:return: None
"""
- if not self.connection_status.is_connected:
- self.channel.logger = self.logger
- self.connection_status.is_connected = True
- self.channel.in_queue = asyncio.Queue()
- self.channel.loop = self.loop
- self.channel.connect()
+ if self.is_connected:
+ return
+ self._state.set(ConnectionStates.connecting)
+ self.channel.logger = self.logger
+ self.channel.in_queue = asyncio.Queue()
+ self.channel.loop = self.loop
+ self.channel.connect()
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""
@@ -187,9 +189,11 @@ async def disconnect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected:
- self.connection_status.is_connected = False
- self.channel.disconnect()
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
+ self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: "Envelope") -> None:
"""
@@ -198,7 +202,7 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelop
:return: None
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
@@ -210,7 +214,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
:return: the envelope received, or None.
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
diff --git a/packages/fetchai/connections/p2p_client/connection.yaml b/packages/fetchai/connections/p2p_client/connection.yaml
index 53a561f431..c8b98ea8f4 100644
--- a/packages/fetchai/connections/p2p_client/connection.yaml
+++ b/packages/fetchai/connections/p2p_client/connection.yaml
@@ -7,7 +7,7 @@ license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmdwnPo8iC2uqf9CmB4ocbh6HP2jcgCtuFdS4djuajp6Li
- connection.py: Qmb9Fu43w6GJYJCnAgZm27wNT9fC6EHDZqBYR8SD1QUmV2
+ connection.py: QmbKTiHPPmYXXLttjJiKAFmVtxeuK7HAUaewWnE2zv2tRb
fingerprint_ignore_patterns: []
protocols: []
class_name: PeerToPeerConnection
diff --git a/packages/fetchai/connections/p2p_libp2p/README.md b/packages/fetchai/connections/p2p_libp2p/README.md
new file mode 100644
index 0000000000..5b62432697
--- /dev/null
+++ b/packages/fetchai/connections/p2p_libp2p/README.md
@@ -0,0 +1,16 @@
+# P2P Libp2p Connection
+
+This connection enables point-to-point secure end-to-end encrypted communication between agents in a fully decentralized way.
+The connection deploys a node that collectively maintains a distributed hash table (DHT) along with other nodes in the same network.
+The DHT provides proper messages delivery by mapping agents addresses to their locations.
+
+## Usage
+
+First, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p:0.5.0`.
+
+Next, ensure that the connection is properly configured by setting:
+
+- `local_uri` to the local ip address and port number that the node should use, in format `${ip}:${port}`
+- `public_uri` to the external ip address and port number allocated for the node, can be the same as `local_uri` if running locally
+- `entry_peers` to a list of multiaddresses of already deployed nodes to join their network, should be empty for genesis node
+- `delegate_uri` to the ip address and port number for the delegate service, leave empty to disable the service
diff --git a/packages/fetchai/connections/p2p_libp2p/connection.py b/packages/fetchai/connections/p2p_libp2p/connection.py
index f5c5f9e944..63b9dd1dbb 100644
--- a/packages/fetchai/connections/p2p_libp2p/connection.py
+++ b/packages/fetchai/connections/p2p_libp2p/connection.py
@@ -20,7 +20,6 @@
"""This module contains the p2p libp2p connection."""
import asyncio
-import distutils
import errno
import logging
import os
@@ -29,19 +28,20 @@
import subprocess # nosec
import tempfile
from asyncio import AbstractEventLoop, CancelledError
+from pathlib import Path
from random import randint
from threading import Thread
from typing import IO, List, Optional, Sequence, cast
from aea.configurations.base import PublicId
from aea.configurations.constants import DEFAULT_LEDGER
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.crypto.base import Crypto
from aea.crypto.registries import make_crypto
from aea.exceptions import AEAException
from aea.mail.base import Address, Envelope
-logger = logging.getLogger("aea.packages.fetchai.connections.p2p_libp2p")
+_default_logger = logging.getLogger("aea.packages.fetchai.connections.p2p_libp2p")
LIBP2P_NODE_MODULE = str(os.path.abspath(os.path.dirname(__file__)))
@@ -58,7 +58,7 @@
# TOFIX(LR) not sure is needed
LIBP2P = "libp2p"
-PUBLIC_ID = PublicId.from_str("fetchai/p2p_libp2p:0.5.0")
+PUBLIC_ID = PublicId.from_str("fetchai/p2p_libp2p:0.6.0")
MultiAddr = str
@@ -68,8 +68,8 @@
async def _golang_module_build_async(
path: str,
log_file_desc: IO[str],
- loop: Optional[asyncio.AbstractEventLoop] = None,
timeout: float = LIBP2P_NODE_DEPS_DOWNLOAD_TIMEOUT,
+ logger: logging.Logger = _default_logger,
) -> int:
"""
Builds go module located at `path`, downloads necessary dependencies
@@ -102,7 +102,11 @@ async def _golang_module_build_async(
def _golang_module_run(
- path: str, name: str, args: Sequence[str], log_file_desc: IO[str]
+ path: str,
+ name: str,
+ args: Sequence[str],
+ log_file_desc: IO[str],
+ logger: logging.Logger = _default_logger,
) -> subprocess.Popen:
"""
Runs a built module located at `path`
@@ -222,19 +226,22 @@ def __init__(
entry_peers: Optional[Sequence[MultiAddr]] = None,
log_file: Optional[str] = None,
env_file: Optional[str] = None,
+ logger: logging.Logger = _default_logger,
):
"""
Initialize a p2p libp2p node.
+ :param agent_addr: the agent address.
:param key: secp256k1 curve private key.
- :param source: the source path
+ :param module_path: the module path.
:param clargs: the command line arguments for the libp2p node
:param uri: libp2p node ip address and port number in format ipaddress:port.
:param public_uri: libp2p node public ip address and port number in format ipaddress:port.
- :param delegation_uri: libp2p node delegate service ip address and port number in format ipaddress:port.
+ :param delegate_uri: libp2p node delegate service ip address and port number in format ipaddress:port.
:param entry_peers: libp2p entry peers multiaddresses.
:param log_file: the logfile path for the libp2p node
:param env_file: the env file path for the exchange of environment variables
+ :param logger: the logger.
"""
self.address = agent_addr
@@ -308,8 +315,10 @@ async def start(self) -> None:
# build the node
# TOFIX(LR) fix async version
- logger.info("Downloading golang dependencies. This may take a while...")
- returncode = await _golang_module_build_async(self.source, self._log_file_desc)
+ self.logger.info("Downloading golang dependencies. This may take a while...")
+ returncode = await _golang_module_build_async(
+ self.source, self._log_file_desc, logger=self.logger
+ )
with open(self.log_file, "r") as f:
self.logger.debug(f.read())
node_log = ""
@@ -383,8 +392,9 @@ async def _connect(self) -> None:
"""
if self._connection_attempts == 1:
with open(self.log_file, "r") as f:
- self.logger.debug("Couldn't connect to libp2p p2p process, logs:")
- self.logger.debug(f.read())
+ self.logger.error("Couldn't connect to libp2p p2p process, logs:")
+ self.logger.error(f.read())
+ self.stop()
raise Exception("Couldn't connect to libp2p p2p process")
# TOFIX(LR) use proper exception
self._connection_attempts -= 1
@@ -405,7 +415,7 @@ async def _connect(self) -> None:
)
except OSError as e:
if e.errno == errno.ENXIO:
- logger.debug("Sleeping for {}...".format(self._connection_timeout))
+ self.logger.debug("Sleeping for {}...".format(self._connection_timeout))
await asyncio.sleep(self._connection_timeout)
await self._connect()
return
@@ -429,8 +439,7 @@ async def _connect(self) -> None:
self.multiaddrs = self.get_libp2p_node_multiaddrs()
self.logger.info("My libp2p addresses: {}".format(self.multiaddrs))
- @asyncio.coroutine
- def write(self, data: bytes) -> None:
+ async def write(self, data: bytes) -> None:
"""
Write to the writer stream.
@@ -587,7 +596,7 @@ def __init__(self, **kwargs):
"At least one Entry Peer should be provided when node can not be publically reachable"
)
if delegate_uri is not None: # pragma: no cover
- logger.warning(
+ self.logger.warning(
"Ignoring Delegate Uri configuration as node can not be publically reachable"
)
else:
@@ -599,9 +608,10 @@ def __init__(self, **kwargs):
)
# libp2p local node
- logger.debug("Public key used by libp2p node: {}".format(key.public_key))
- self.libp2p_workdir = tempfile.mkdtemp()
- distutils.dir_util.copy_tree(LIBP2P_NODE_MODULE, self.libp2p_workdir)
+ self.logger.debug("Public key used by libp2p node: {}".format(key.public_key))
+ temp_dir = tempfile.mkdtemp()
+ self.libp2p_workdir = os.path.join(temp_dir, "libp2p_workdir")
+ shutil.copytree(LIBP2P_NODE_MODULE, self.libp2p_workdir)
self.node = Libp2pNode(
self.address,
@@ -614,6 +624,7 @@ def __init__(self, **kwargs):
entry_peers,
log_file,
env_file,
+ self.logger,
)
self._in_queue = None # type: Optional[asyncio.Queue]
@@ -635,23 +646,22 @@ async def connect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected: # pragma: no cover
+ if self.is_connected:
return
+ self._state.set(ConnectionStates.connecting)
try:
# start libp2p node
- self.connection_status.is_connecting = True
+ self._state.set(ConnectionStates.connecting)
self.node.logger = self.logger
await self.node.start()
- self.connection_status.is_connecting = False
- self.connection_status.is_connected = True
-
# starting receiving msgs
self._in_queue = asyncio.Queue()
self._receive_from_node_task = asyncio.ensure_future(
self._receive_from_node(), loop=self._loop
)
+ self._state.set(ConnectionStates.connected)
except (CancelledError, Exception) as e:
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
raise e
async def disconnect(self) -> None:
@@ -660,21 +670,20 @@ async def disconnect(self) -> None:
:return: None
"""
- assert (
- self.connection_status.is_connected or self.connection_status.is_connecting
- ), "Call connect before disconnect."
- self.connection_status.is_connected = False
- self.connection_status.is_connecting = False
+ if self.is_disconnected:
+ return
+ self._state.set(ConnectionStates.disconnecting)
if self._receive_from_node_task is not None:
self._receive_from_node_task.cancel()
self._receive_from_node_task = None
self.node.stop()
if self.libp2p_workdir is not None:
- distutils.dir_util.remove_tree(self.libp2p_workdir)
+ shutil.rmtree(Path(self.libp2p_workdir).parent)
if self._in_queue is not None:
self._in_queue.put_nowait(None)
else:
self.logger.debug("Called disconnect when input queue not initialized.")
+ self._state.set(ConnectionStates.disconnected)
async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
"""
@@ -688,7 +697,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
if data is None:
self.logger.debug("Received None.")
self.node.stop()
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
return None
# TOFIX(LR) attempt restarting the node?
self.logger.debug("Received data: {}".format(data))
diff --git a/packages/fetchai/connections/p2p_libp2p/connection.yaml b/packages/fetchai/connections/p2p_libp2p/connection.yaml
index e627ed343e..930cb63bd9 100644
--- a/packages/fetchai/connections/p2p_libp2p/connection.yaml
+++ b/packages/fetchai/connections/p2p_libp2p/connection.yaml
@@ -1,18 +1,19 @@
name: p2p_libp2p
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The p2p libp2p connection implements an interface to standalone golang
go-libp2p node that can exchange aea envelopes with other agents connected to the
same DHT.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmPvrvhRUQEt2hruwoY73xwwdNdQyssBuxK9XNACSjvQRS
__init__.py: QmYQuLNyQ8WTjgRYAoKAzoJEb7ocKXvM2hTyK4hsGch5D6
aea/api.go: QmW5fUpVZmV3pxgoakm3RvsvCGC6FwT2XprcqXHM8rBXP5
aea/envelope.pb.go: QmRfUNGpCeVJfsW3H1MzCN4pwDWgumfyWufVFp6xvUjjug
aea/envelope.proto: QmSC8EGCKiNFR2vf5bSWymSzYDFMipQW9aQVMwPzQoKb4n
- connection.py: QmPMUYiH5PocuLfUt3zTz4cfn17KfxZTLMpNtBRtDdx4bp
- dht/dhtclient/dhtclient.go: QmNnU1pVCUtj8zJ1Pz5eMk9sznsjPFSJ9qDkzbrNwzEecV
+ connection.py: QmRDSgAPjY9D2CZVnGth3xKsncAtaBH8kob42Teu6zbnd4
+ dht/dhtclient/dhtclient.go: QmasA3GrgswTnUJoffBzeeqxeT3GjLu6foN6PHJhWNpMMa
dht/dhtclient/dhtclient_test.go: QmPfnHSHXtbaW5VYuq1QsKQWey64pUEvLEaKKkT9eAcmws
dht/dhtclient/options.go: QmPorj38wNrxGrzsbFe5wwLmiHzxbTJ2VsgvSd8tLDYS8s
dht/dhtnode/dhtnode.go: QmbyhgbCSAbQ1QsDw7FM7Nt5sZcvhbupA1jv5faxutbV7N
@@ -24,7 +25,7 @@ fingerprint:
go.mod: QmacqAAxC3dkydmfbEyVWVkMDmZECTWKZcBoPyRSnheQzD
go.sum: Qmbu57aSPSqanJ1xHNmMHAqLL8nvCV61URknizsKJDvenG
libp2p_node.go: QmZQoa9RGdVkcE8Hu9kVAdSh3jRUveScDhG84UkSY6N3vz
- utils/utils.go: QmUsNceCQKYfaLqJN8YhTkPoB7aD2ahn6gvFG1iHKeimax
+ utils/utils.go: QmSdLqVNwtupDKxvE2qbCEEoACCaRG2ccNPq6p34YtrDqA
fingerprint_ignore_patterns: []
protocols: []
class_name: P2PLibp2pConnection
diff --git a/packages/fetchai/connections/p2p_libp2p/dht/dhtclient/dhtclient.go b/packages/fetchai/connections/p2p_libp2p/dht/dhtclient/dhtclient.go
index e0a23e872c..b9c69c0d39 100644
--- a/packages/fetchai/connections/p2p_libp2p/dht/dhtclient/dhtclient.go
+++ b/packages/fetchai/connections/p2p_libp2p/dht/dhtclient/dhtclient.go
@@ -53,7 +53,8 @@ func ignore(err error) {
}
const (
- newStreamTimeout = 5 * time.Second
+ newStreamTimeout = 5 * 60 * time.Second // includes peer restart
+ sleepTimeIncreaseFactor = 2 // multiplicative increase
)
// DHTClient A restricted libp2p node for the Agents Communication Network
@@ -275,6 +276,22 @@ func (dhtClient *DHTClient) RouteEnvelope(envel *aea.Envelope) error {
ctx, cancel := context.WithTimeout(context.Background(), newStreamTimeout)
defer cancel()
stream, err := dhtClient.routedHost.NewStream(ctx, dhtClient.relayPeer, dhtnode.AeaAddressStream)
+ sleepTime := 200 * time.Millisecond
+ for err != nil {
+ lerror(err).
+ Str("op", "route").
+ Str("target", target).
+ Msgf("couldn't open stream to relay, retrying in %s", sleepTime)
+ select {
+ default:
+ time.Sleep(sleepTime)
+ sleepTime = sleepTime * sleepTimeIncreaseFactor
+ stream, err = dhtClient.routedHost.NewStream(ctx, dhtClient.relayPeer, dhtnode.AeaAddressStream)
+ case <-ctx.Done():
+ break
+ }
+ }
+ err = dhtClient.registerAgentAddress()
if err != nil {
lerror(err).
Str("op", "route").
@@ -355,6 +372,22 @@ func (dhtClient *DHTClient) RouteEnvelope(envel *aea.Envelope) error {
ctx, cancel = context.WithTimeout(context.Background(), newStreamTimeout)
defer cancel()
stream, err = dhtClient.routedHost.NewStream(ctx, peerID, dhtnode.AeaEnvelopeStream)
+ sleepTime = 200 * time.Millisecond
+ for err != nil {
+ lerror(err).
+ Str("op", "route").
+ Str("target", target).
+ Msgf("timeout, couldn't open stream to target %s, retrying in %s", peerID, sleepTime)
+ select {
+ default:
+ time.Sleep(sleepTime)
+ sleepTime = sleepTime * sleepTimeIncreaseFactor
+ stream, err = dhtClient.routedHost.NewStream(ctx, peerID, dhtnode.AeaEnvelopeStream)
+ case <-ctx.Done():
+ break
+ }
+ }
+ err = dhtClient.registerAgentAddress()
if err != nil {
lerror(err).
Str("op", "route").
@@ -453,6 +486,21 @@ func (dhtClient *DHTClient) registerAgentAddress() error {
ctx, cancel := context.WithTimeout(context.Background(), newStreamTimeout)
defer cancel()
stream, err := dhtClient.routedHost.NewStream(ctx, dhtClient.relayPeer, dhtnode.AeaRegisterRelayStream)
+ sleepTime := 200 * time.Millisecond
+ for err != nil {
+ lerror(err).
+ Str("op", "register").
+ Str("addr", dhtClient.myAgentAddress).
+ Msgf("timeout, couldn't open stream to relay peer, retrying in %s", sleepTime)
+ select {
+ default:
+ time.Sleep(sleepTime)
+ sleepTime = sleepTime * sleepTimeIncreaseFactor
+ stream, err = dhtClient.routedHost.NewStream(ctx, dhtClient.relayPeer, dhtnode.AeaRegisterRelayStream)
+ case <-ctx.Done():
+ break
+ }
+ }
if err != nil {
lerror(err).
Str("op", "register").
diff --git a/packages/fetchai/connections/p2p_libp2p/utils/utils.go b/packages/fetchai/connections/p2p_libp2p/utils/utils.go
index cbd2c6ab49..250ed82fa3 100644
--- a/packages/fetchai/connections/p2p_libp2p/utils/utils.go
+++ b/packages/fetchai/connections/p2p_libp2p/utils/utils.go
@@ -233,13 +233,10 @@ func IDFromFetchAIPublicKey(public_key string) (peer.ID, error) {
// WriteBytesConn send bytes to `conn`
func WriteBytesConn(conn net.Conn, data []byte) error {
size := uint32(len(data))
- buf := make([]byte, 4)
+ buf := make([]byte, 4, 4+size)
binary.BigEndian.PutUint32(buf, size)
+ buf = append(buf, data...)
_, err := conn.Write(buf)
- if err != nil {
- return err
- }
- _, err = conn.Write(data)
return err
}
diff --git a/packages/fetchai/connections/p2p_libp2p_client/README.md b/packages/fetchai/connections/p2p_libp2p_client/README.md
new file mode 100644
index 0000000000..489b5d1b22
--- /dev/null
+++ b/packages/fetchai/connections/p2p_libp2p_client/README.md
@@ -0,0 +1,15 @@
+# P2P Libp2p Client Connection
+
+A lightweight tcp connection to a libp2p DHT node.
+
+It allows for using the DHT without having to deploy a node by delegating its communication traffic to an already running DHT node with delegate service enabled.
+
+
+## Usage
+
+First, add the connection to your AEA project: `aea add connection fetchai/p2p_libp2p_client:0.5.0`.
+
+Next, ensure that the connection is properly configured by setting:
+
+- `nodes` to a list of `uri`s, connection will choose the delegate randomly
+- `uri` to the public ip address and port number of the delegate service of a running DHT node, in format `${ip|dns}:${port}`
diff --git a/packages/fetchai/connections/p2p_libp2p_client/connection.py b/packages/fetchai/connections/p2p_libp2p_client/connection.py
index 6d5404c601..2e4c562b18 100644
--- a/packages/fetchai/connections/p2p_libp2p_client/connection.py
+++ b/packages/fetchai/connections/p2p_libp2p_client/connection.py
@@ -29,13 +29,13 @@
from aea.configurations.base import PublicId
from aea.configurations.constants import DEFAULT_LEDGER
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.crypto.registries import make_crypto
from aea.mail.base import Envelope
logger = logging.getLogger("aea.packages.fetchai.connections.p2p_libp2p_client")
-PUBLIC_ID = PublicId.from_str("fetchai/p2p_libp2p_client:0.4.0")
+PUBLIC_ID = PublicId.from_str("fetchai/p2p_libp2p_client:0.5.0")
SUPPORTED_LEDGER_IDS = ["fetchai", "cosmos", "ethereum"]
@@ -156,13 +156,15 @@ async def connect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected: # pragma: no cover
+ if self.is_connected: # pragma: nocover
return
+
+ self._state.set(ConnectionStates.connecting)
+
if self._loop is None:
self._loop = asyncio.get_event_loop()
try:
# connect libp2p client
- self.connection_status.is_connecting = True
# connect the tcp socket
self._reader, self._writer = await asyncio.open_connection(
@@ -174,9 +176,6 @@ async def connect(self) -> None:
# send agent address to node
await self._setup_connection()
- self.connection_status.is_connecting = False
- self.connection_status.is_connected = True
-
self.logger.info(
"Successfully connected to libp2p node {}".format(str(self.node_uri))
)
@@ -186,8 +185,9 @@ async def connect(self) -> None:
self._process_messages_task = asyncio.ensure_future(
self._process_messages(), loop=self._loop
)
+ self._state.set(ConnectionStates.connected)
except (CancelledError, Exception) as e:
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
raise e
async def _setup_connection(self):
@@ -200,15 +200,11 @@ async def disconnect(self) -> None:
:return: None
"""
- assert (
- self.connection_status.is_connected or self.connection_status.is_connecting
- ), "Call connect before disconnect."
- self.connection_status.is_connected = False
- self.connection_status.is_connecting = False
-
+ if self.is_disconnected: # pragma: nocover
+ return
assert self._process_messages_task is not None
assert self._writer is not None
-
+ self._state.set(ConnectionStates.disconnecting)
if self._process_messages_task is not None:
self._process_messages_task.cancel()
# TOFIX(LR) mypy issue https://github.com/python/mypy/issues/8546
@@ -225,6 +221,7 @@ async def disconnect(self) -> None:
self._in_queue.put_nowait(None)
else: # pragma: no cover
self.logger.debug("Called disconnect when input queue not initialized.")
+ self._state.set(ConnectionStates.disconnected)
async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
"""
@@ -237,10 +234,7 @@ async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
data = await self._in_queue.get()
if data is None:
self.logger.debug("Received None.")
- if (
- self._connection_status.is_connected
- or self._connection_status.is_connecting
- ):
+ if not self.is_disconnected:
await self.disconnect()
return None
# TOFIX(LR) attempt restarting the node?
diff --git a/packages/fetchai/connections/p2p_libp2p_client/connection.yaml b/packages/fetchai/connections/p2p_libp2p_client/connection.yaml
index 382d2404d2..457a44f82a 100644
--- a/packages/fetchai/connections/p2p_libp2p_client/connection.yaml
+++ b/packages/fetchai/connections/p2p_libp2p_client/connection.yaml
@@ -1,14 +1,15 @@
name: p2p_libp2p_client
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The libp2p client connection implements a tcp connection to a running
libp2p node as a traffic delegate to send/receive envelopes to/from agents in the
DHT.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: Qmc8eDQRX15bcJZr8J9ty9EZmXMZN8VUtufkkCm35LWU55
__init__.py: QmT1FEHkPGMHV5oiVEfQHHr25N2qdZxydSNRJabJvYiTgf
- connection.py: QmSWqusLpeET9U6zQyVGYppsoLY7MSDkxocAdUNc7HYDtu
+ connection.py: QmPY3yzUkioLkPATZR6K44NwyxCxRXiGf7WHi5j9x5Zg9j
fingerprint_ignore_patterns: []
protocols: []
class_name: P2PLibp2pClientConnection
diff --git a/packages/fetchai/connections/p2p_stub/README.md b/packages/fetchai/connections/p2p_stub/README.md
new file mode 100644
index 0000000000..911f0f5feb
--- /dev/null
+++ b/packages/fetchai/connections/p2p_stub/README.md
@@ -0,0 +1,9 @@
+# p2p stub connection
+
+Simple file based connection to perform interaction between multiple local agents.
+
+## Usage
+
+First, add the connection to your AEA project: `aea add connection fetchai/p2p_stub:0.5.0`.
+
+Optionally, in the `connection.yaml` file under `config` set the `namespace_dir` to the desired file path. The `p2p_stub` connection reads encoded envelopes from its input file and writes encoded envelopes to its output file. Multiple agents can be pointed to the same `namespace_dir` and are then able to exchange envelopes via the file system.
diff --git a/packages/fetchai/connections/p2p_stub/connection.py b/packages/fetchai/connections/p2p_stub/connection.py
index 0b51fd1500..067d2724b1 100644
--- a/packages/fetchai/connections/p2p_stub/connection.py
+++ b/packages/fetchai/connections/p2p_stub/connection.py
@@ -28,7 +28,7 @@
from aea.identity.base import Identity
from aea.mail.base import Envelope
-PUBLIC_ID = PublicId.from_str("fetchai/p2p_stub:0.4.0")
+PUBLIC_ID = PublicId.from_str("fetchai/p2p_stub:0.5.0")
class P2PStubConnection(StubConnection):
diff --git a/packages/fetchai/connections/p2p_stub/connection.yaml b/packages/fetchai/connections/p2p_stub/connection.yaml
index eb5ec4d729..a4921edd5b 100644
--- a/packages/fetchai/connections/p2p_stub/connection.yaml
+++ b/packages/fetchai/connections/p2p_stub/connection.yaml
@@ -1,13 +1,14 @@
name: p2p_stub
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The stub p2p connection implements a local p2p connection allowing agents
to communicate with each other through files created in the namespace directory.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmPqvbK3yBn5w25RGf8X5cZQ6KDBXMYoVUDufGgURe3VKd
__init__.py: QmW9XFKGsea4u3fupkFMcQutgsjqusCMBMyTcTmLLmQ4tR
- connection.py: QmbGLdt5T3aV69HDch74DXv7an5N3nJJnxWQqgfVuHpXif
+ connection.py: QmXoKRBMddf5GzfP4nKER17R76pfbeqgJjU5NjAEydHLum
fingerprint_ignore_patterns: []
protocols: []
class_name: P2PStubConnection
diff --git a/packages/fetchai/connections/soef/README.md b/packages/fetchai/connections/soef/README.md
new file mode 100644
index 0000000000..298fe4b478
--- /dev/null
+++ b/packages/fetchai/connections/soef/README.md
@@ -0,0 +1,9 @@
+# SOEF connection
+
+The SOEF connection is used to connect to an SOEF node. The SOEF provides OEF services of register/unregister and search.
+
+## Usage
+
+First, add the connection to your AEA project: `aea add connection fetchai/soef:0.5.0`. Then ensure the `config` in `connection.yaml` matches your need. In particular, make sure `chain_identifier` matches your `default_ledger`.
+
+To register/unregister services and perform searches use the `fetchai/oef_search:0.4.0` protocol
diff --git a/packages/fetchai/connections/soef/connection.py b/packages/fetchai/connections/soef/connection.py
index c790958c09..76d524ffe7 100644
--- a/packages/fetchai/connections/soef/connection.py
+++ b/packages/fetchai/connections/soef/connection.py
@@ -22,6 +22,7 @@
import copy
import logging
from asyncio import CancelledError
+from concurrent.futures._base import CancelledError as ConcurrentCancelledError
from concurrent.futures.thread import ThreadPoolExecutor
from contextlib import suppress
from typing import Callable, Dict, List, Optional, Set, Union, cast
@@ -33,7 +34,7 @@
import requests
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.helpers.dialogue.base import Dialogue as BaseDialogue
from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
from aea.helpers.search.models import (
@@ -53,9 +54,9 @@
)
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
-logger = logging.getLogger("aea.packages.fetchai.connections.oef")
+_default_logger = logging.getLogger("aea.packages.fetchai.connections.oef")
-PUBLIC_ID = PublicId.from_str("fetchai/soef:0.5.0")
+PUBLIC_ID = PublicId.from_str("fetchai/soef:0.6.0")
NOT_SPECIFIED = object()
@@ -83,28 +84,36 @@ class ModelNames:
class SOEFException(Exception):
- """Soef chanlle expected exception."""
+ """SOEF channel expected exception."""
@classmethod
- def warning(cls, msg: str) -> "SOEFException": # pragma: no cover
+ def warning(
+ cls, msg: str, logger: logging.Logger = _default_logger
+ ) -> "SOEFException": # pragma: no cover
"""Construct exception and write log."""
logger.warning(msg)
return cls(msg)
@classmethod
- def debug(cls, msg: str) -> "SOEFException": # pragma: no cover
+ def debug(
+ cls, msg: str, logger: logging.Logger = _default_logger
+ ) -> "SOEFException": # pragma: no cover
"""Construct exception and write log."""
logger.debug(msg)
return cls(msg)
@classmethod
- def error(cls, msg: str) -> "SOEFException": # pragma: no cover
+ def error(
+ cls, msg: str, logger: logging.Logger = _default_logger
+ ) -> "SOEFException": # pragma: no cover
"""Construct exception and write log."""
logger.error(msg)
return cls(msg)
@classmethod
- def exception(cls, msg: str) -> "SOEFException": # pragma: no cover
+ def exception(
+ cls, msg: str, logger: logging.Logger = _default_logger
+ ) -> "SOEFException": # pragma: no cover
"""Construct exception and write log."""
logger.exception(msg)
return cls(msg)
@@ -164,6 +173,7 @@ class SOEFChannel:
DEFAULT_PERSONALITY_PIECES = ["architecture,agentframework"]
PING_PERIOD = 30 * 60 # 30 minutes
+ FIND_AROUND_ME_REQUEST_DELAY = 2 # seconds
def __init__(
self,
@@ -174,6 +184,7 @@ def __init__(
excluded_protocols: Set[PublicId],
restricted_to_protocols: Set[PublicId],
chain_identifier: Optional[str] = None,
+ logger: logging.Logger = _default_logger,
):
"""
Initialize.
@@ -202,8 +213,6 @@ def __init__(
self.excluded_protocols = excluded_protocols
self.restricted_to_protocols = restricted_to_protocols
self.oef_search_dialogues = OefSearchDialogues()
- self.oef_msg_id = 0
- self.oef_msg_id_to_dialogue = {} # type: Dict[int, OefSearchDialogue]
self.declared_name = uuid4().hex
self.unique_page_address = None # type: Optional[str]
@@ -213,6 +222,33 @@ def __init__(
self.chain_identifier: str = chain_identifier or self.DEFAULT_CHAIN_IDENTIFIER
self._loop = None # type: Optional[asyncio.AbstractEventLoop]
self._ping_periodic_task: Optional[asyncio.Task] = None
+ self._find_around_me_queue: Optional[asyncio.Queue] = None
+ self._find_around_me_processor_task: Optional[asyncio.Task] = None
+ self.logger = logger
+
+ async def _find_around_me_processor(self) -> None:
+ """Process find me around requests in background task."""
+ while self._find_around_me_queue is not None:
+ try:
+ task = await self._find_around_me_queue.get()
+ oef_message, oef_search_dialogue, radius, params = task
+ await self._find_around_me_handle_requet(
+ oef_message, oef_search_dialogue, radius, params
+ )
+ await asyncio.sleep(self.FIND_AROUND_ME_REQUEST_DELAY)
+ except asyncio.CancelledError: # pylint: disable=try-except-raise
+ return
+ except Exception: # pylint: disable=broad-except # pragma: nocover
+ self.logger.exception(
+ "Exception occoured in _find_around_me_processor"
+ )
+ await self._send_error_response(
+ oef_message,
+ oef_search_dialogue,
+ oef_error_operation=OefSearchMessage.OefErrorOperation.OTHER,
+ )
+ finally:
+ self.logger.debug("_find_around_me_processor exited")
@property
def loop(self) -> asyncio.AbstractEventLoop:
@@ -300,7 +336,7 @@ def _check_protocol_valid(self, envelope: Envelope) -> None:
)
if is_in_excluded or not is_in_restricted:
- logger.error(
+ self.logger.error(
"This envelope cannot be sent with the soef connection: protocol_id={}".format(
envelope.protocol_id
)
@@ -337,13 +373,13 @@ async def process_envelope(self, envelope: Envelope) -> None:
assert isinstance(envelope.message, OefSearchMessage), ValueError(
"Message not of type OefSearchMessage"
)
- oef_message = cast(OefSearchMessage, envelope.message)
- oef_message = copy.deepcopy(
- oef_message
+ oef_message_orig = cast(OefSearchMessage, envelope.message)
+ oef_message = copy.copy(
+ oef_message_orig
) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
oef_message.is_incoming = True # TODO: fix; should be done by framework
oef_message.counterparty = (
- envelope.sender
+ oef_message_orig.sender
) # TODO: fix; should be done by framework
oef_search_dialogue = cast(
OefSearchDialogue, self.oef_search_dialogues.update(oef_message)
@@ -387,8 +423,10 @@ async def process_envelope(self, envelope: Envelope) -> None:
oef_search_dialogue,
oef_error_operation=oef_error_operation,
)
+ except (asyncio.CancelledError, ConcurrentCancelledError): # pragma: nocover
+ pass
except Exception: # pylint: disable=broad-except # pragma: nocover
- logger.exception("Exception during envelope processing")
+ self.logger.exception("Exception during envelope processing")
await self._send_error_response(
oef_message,
oef_search_dialogue,
@@ -454,7 +492,7 @@ async def _ping_periodic(self, period: float = 30 * 60) -> None:
except asyncio.CancelledError: # pylint: disable=try-except-raise
raise
except Exception: # pylint: disable=broad-except
- logger.exception("Error on periodic ping command!")
+ self.logger.exception("Error on periodic ping command!")
await asyncio.sleep(period)
async def _set_service_key_handler(self, service_description: Description) -> None:
@@ -484,7 +522,7 @@ async def _generic_oef_command(
:return: response text
"""
params = params or {}
- logger.debug(f"Perform `{command}` with {params}")
+ self.logger.debug(f"Perform `{command}` with {params}")
url = parse.urljoin(
self.base_url, unique_page_address or self.unique_page_address
)
@@ -498,7 +536,7 @@ async def _generic_oef_command(
el = root.find("./success")
assert el is not None, "No success element"
assert str(el.text).strip() == "1", "Success is not 1"
- logger.debug(f"`{command}` SUCCESS!")
+ self.logger.debug(f"`{command}` SUCCESS!")
return response_text
except Exception as e:
raise SOEFException.error(f"`{command}` error: {response_text}: {[e]}")
@@ -633,7 +671,7 @@ async def _register_agent(self) -> None:
:return: None
"""
- logger.debug("Applying to SOEF lobby with address={}".format(self.address))
+ self.logger.debug("Applying to SOEF lobby with address={}".format(self.address))
url = parse.urljoin(self.base_url, "register")
params = {
"api_key": self.api_key,
@@ -643,11 +681,11 @@ async def _register_agent(self) -> None:
}
response_text = await self._request_text("get", url=url, params=params)
root = ET.fromstring(response_text)
- logger.debug("Root tag: {}".format(root.tag))
+ self.logger.debug("Root tag: {}".format(root.tag))
unique_page_address = ""
unique_token = "" # nosec
for child in root:
- logger.debug(
+ self.logger.debug(
"Child tag={}, child attrib={}, child text={}".format(
child.tag, child.attrib, child.text
)
@@ -660,7 +698,7 @@ async def _register_agent(self) -> None:
raise SOEFException.error(
"Agent registration error - page address or token not received"
)
- logger.debug("Registering agent")
+ self.logger.debug("Registering agent")
params = {"token": unique_token}
await self._generic_oef_command(
"acknowledge", params, unique_page_address=unique_page_address
@@ -697,10 +735,7 @@ async def _send_error_response(
message_id=oef_search_message.message_id + 1,
)
message.counterparty = oef_search_message.counterparty
- oef_search_dialogue.update(message)
- message = copy.deepcopy(
- message
- ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ assert oef_search_dialogue.update(message)
envelope = Envelope(
to=message.counterparty,
sender=SOEFConnection.connection_id.latest,
@@ -727,7 +762,7 @@ async def unregister_service(
} # type: Dict[str, Callable]
data_model_name = service_description.data_model.name
- if data_model_name not in data_model_handlers:
+ if data_model_name not in data_model_handlers: # pragma: nocover
raise SOEFException.error(
f'Data model name: {data_model_name} is not supported. Valid models are: {", ".join(data_model_handlers.keys())}'
)
@@ -746,7 +781,7 @@ async def _unregister_agent(self) -> None:
"""
await self._stop_periodic_ping_task()
if self.unique_page_address is None: # pragma: nocover
- logger.debug(
+ self.logger.debug(
"The service is not registered to the simple OEF. Cannot unregister."
)
return
@@ -768,7 +803,11 @@ async def connect(self) -> None:
"""Connect channel set queues and executor pool."""
self._loop = asyncio.get_event_loop()
self.in_queue = asyncio.Queue()
+ self._find_around_me_queue = asyncio.Queue()
self._executor_pool = ThreadPoolExecutor(max_workers=10)
+ self._find_around_me_processor_task = self._loop.create_task(
+ self._find_around_me_processor()
+ )
async def disconnect(self) -> None:
"""
@@ -780,7 +819,14 @@ async def disconnect(self) -> None:
assert self.in_queue, ValueError("Queue is not set, use connect first!")
await self._unregister_agent()
+
+ if self._find_around_me_processor_task:
+ if not self._find_around_me_processor_task.done():
+ self._find_around_me_processor_task.cancel()
+ await self._find_around_me_processor_task
+
await self.in_queue.put(None)
+ self._find_around_me_queue = None
async def search_services(
self, oef_message: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
@@ -820,6 +866,7 @@ async def search_services(
if self.agent_location is None or self.agent_location != service_location:
# we update the location to match the query.
await self._set_location(service_location) # pragma: nocover
+
await self._find_around_me(oef_message, oef_search_dialogue, radius, params)
async def _find_around_me(
@@ -828,6 +875,28 @@ async def _find_around_me(
oef_search_dialogue: OefSearchDialogue,
radius: float,
params: Dict[str, List[str]],
+ ) -> None:
+ """
+ Add find agent task to queue to process in dedictated loop respectful to timeouts.
+
+ :param oef_message: OefSearchMessage
+ :param oef_search_dialogue: OefSearchDialogue
+ :param radius: the radius in which to search
+ :param params: the parameters for the query
+ :return: None
+ """
+ if not self._find_around_me_queue:
+ raise ValueError("SOEFChannel not started.") # pragma: nocover
+ await self._find_around_me_queue.put(
+ (oef_message, oef_search_dialogue, radius, params)
+ )
+
+ async def _find_around_me_handle_requet(
+ self,
+ oef_message: OefSearchMessage,
+ oef_search_dialogue: OefSearchDialogue,
+ radius: float,
+ params: Dict[str, List[str]],
) -> None:
"""
Find agents around me.
@@ -839,7 +908,7 @@ async def _find_around_me(
:return: None
"""
assert self.in_queue is not None, "Inqueue not set!"
- logger.debug("Searching in radius={} of myself".format(radius))
+ self.logger.debug("Searching in radius={} of myself".format(radius))
response_text = await self._generic_oef_command(
"find_around_me", {"range_in_km": [str(radius)], **params}
@@ -873,10 +942,7 @@ async def _find_around_me(
message_id=oef_message.message_id + 1,
)
message.counterparty = oef_message.counterparty
- oef_search_dialogue.update(message)
- message = copy.deepcopy(
- message
- ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ assert oef_search_dialogue.update(message)
envelope = Envelope(
to=message.counterparty,
sender=SOEFConnection.connection_id.latest,
@@ -896,7 +962,7 @@ def __init__(self, **kwargs):
if kwargs.get("configuration") is None: # pragma: nocover
kwargs["excluded_protocols"] = kwargs.get("excluded_protocols") or []
kwargs["restricted_to_protocols"] = kwargs.get("excluded_protocols") or [
- PublicId.from_str("fetchai/oef_search:0.3.0")
+ PublicId.from_str("fetchai/oef_search:0.4.0")
]
super().__init__(**kwargs)
@@ -928,15 +994,15 @@ async def connect(self) -> None:
:return: None
:raises Exception if the connection to the OEF fails.
"""
- if self.connection_status.is_connected: # pragma: no cover
+ if self.is_connected: # pragma: nocover
return
+
+ self._state.set(ConnectionStates.connecting)
try:
- self.connection_status.is_connecting = True
await self.channel.connect()
- self.connection_status.is_connecting = False
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
except (CancelledError, Exception) as e: # pragma: no cover
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
raise e
@property
@@ -950,13 +1016,12 @@ async def disconnect(self) -> None:
:return: None
"""
- assert (
- self.connection_status.is_connected or self.connection_status.is_connecting
- ), "Call connect before disconnect."
+ if self.is_disconnected: # pragma: nocover
+ return
assert self.in_queue is not None
+ self._state.set(ConnectionStates.disconnecting)
await self.channel.disconnect()
- self.connection_status.is_connected = False
- self.connection_status.is_connecting = False
+ self._state.set(ConnectionStates.disconnected)
async def receive(self, *args, **kwargs) -> Optional["Envelope"]:
"""
@@ -986,5 +1051,5 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelope to send.
:return: None
"""
- if self.connection_status.is_connected:
+ if self.is_connected:
await self.channel.send(envelope)
diff --git a/packages/fetchai/connections/soef/connection.yaml b/packages/fetchai/connections/soef/connection.yaml
index c8efbd8c45..c5eef8186f 100644
--- a/packages/fetchai/connections/soef/connection.yaml
+++ b/packages/fetchai/connections/soef/connection.yaml
@@ -1,15 +1,16 @@
name: soef
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The soef connection provides a connection api to the simple OEF.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmUaLTefPhGVDn3SZ5oK461JASpUALPBj4x9HmyJV39iqG
__init__.py: Qmd5VBGFJHXFe1H45XoUh5mMSYBwvLSViJuGFeMgbPdQts
- connection.py: QmdwV3H3zaaZTNcEfr5YBFuaUdjwK5vyNQHAtFPRLWmuH9
+ connection.py: QmXJZTroYKyQEcruGGWhDesjDhn8WVDmEMgrtH6vEQSa38
fingerprint_ignore_patterns: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
class_name: SOEFConnection
config:
api_key: TwiCIriSl0mLahw17pyqoA
@@ -18,6 +19,6 @@ config:
soef_port: 9002
excluded_protocols: []
restricted_to_protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
dependencies:
defusedxml: {}
diff --git a/packages/fetchai/connections/tcp/README.md b/packages/fetchai/connections/tcp/README.md
new file mode 100644
index 0000000000..431d3459f6
--- /dev/null
+++ b/packages/fetchai/connections/tcp/README.md
@@ -0,0 +1,7 @@
+# TCP client connection
+
+A simple TCP client/server connection to use the TCP protocol for sending and receiving envelopes.
+
+## Usage
+
+Add the connection to your AEA project: `aea add connection fetchai/tcp:0.6.0`.
diff --git a/packages/fetchai/connections/tcp/base.py b/packages/fetchai/connections/tcp/base.py
index 0866411ae4..ca364fb84f 100644
--- a/packages/fetchai/connections/tcp/base.py
+++ b/packages/fetchai/connections/tcp/base.py
@@ -25,12 +25,12 @@
from typing import Optional
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import Envelope
logger = logging.getLogger("aea.packages.fetchai.connections.tcp")
-PUBLIC_ID = PublicId.from_str("fetchai/tcp:0.5.0")
+PUBLIC_ID = PublicId.from_str("fetchai/tcp:0.6.0")
class TCPConnection(Connection, ABC):
@@ -75,16 +75,17 @@ async def connect(self):
:return: A queue or None.
:raises ConnectionError: if a problem occurred during the connection.
"""
- if self.connection_status.is_connected:
+ if self.is_connected: # pragma: nocover
self.logger.warning("Connection already set up.")
return
+ self._state.set(ConnectionStates.connecting)
try:
await self.setup()
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
except Exception as e: # pragma: nocover # pylint: disable=broad-except
self.logger.error(str(e))
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
async def disconnect(self) -> None:
"""
@@ -92,17 +93,19 @@ async def disconnect(self) -> None:
:return: None.
"""
- if not self.connection_status.is_connected:
+
+ if self.is_disconnected: # pragma: nocover
self.logger.warning("Connection already disconnected.")
return
+ self._state.set(ConnectionStates.disconnecting)
await self.teardown()
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
async def _recv(self, reader: StreamReader) -> Optional[bytes]:
"""Receive bytes."""
data = await reader.read(len(struct.pack("I", 0)))
- if not self.connection_status.is_connected:
+ if not self.is_connected:
return None
nbytes = struct.unpack("I", data)[0]
nbytes_read = 0
diff --git a/packages/fetchai/connections/tcp/connection.yaml b/packages/fetchai/connections/tcp/connection.yaml
index d81a997b57..119f4a92d4 100644
--- a/packages/fetchai/connections/tcp/connection.yaml
+++ b/packages/fetchai/connections/tcp/connection.yaml
@@ -1,12 +1,13 @@
name: tcp
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The tcp connection implements a tcp server and client.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: Qma4uDSzQ57JWfiUShXMXYzmfMyjXYVEdqrpfMnwX6EaV7
__init__.py: QmTxAtQ9ffraStxxLAkvmWxyGhoV3jE16Sw6SJ9xzTthLb
- base.py: QmNoodDEsFfPUSmayxqqUSdAaxbXQ1gof7jTsLvMdEoAek
+ base.py: QmRwaGZS51WTDWh7TvfNEw4MtuzNH5yqT22HRVmGMrzwZ8
connection.py: QmTFkiw3JLmhEM6CKRpKjv9Y32nuCQevZ2gVKoQ4gExeW9
tcp_client.py: QmTXs6z3rvxB59FmGuu46CeY1eHRPBNQ4CPZm1y7hRpusp
tcp_server.py: QmPLTPEzeWPGU2Bt4kCaTXXKTqNNffHX5dr3LG75YQ249z
diff --git a/packages/fetchai/connections/webhook/README.md b/packages/fetchai/connections/webhook/README.md
new file mode 100644
index 0000000000..6ab7ae7a9b
--- /dev/null
+++ b/packages/fetchai/connections/webhook/README.md
@@ -0,0 +1,7 @@
+# Webhook connection
+
+An HTTP webhook connection which registers a webhook and waits for incoming requests. It generates messages based on webhook requests received and forwards them to the agent.
+
+## Usage
+
+First, add the connection to your AEA project: `aea add connection fetchai/webhook:0.5.0`. Then ensure the `config` in `connection.yaml` matches your need. In particular, set `webhook_address`, `webhook_port` and `webhook_url_path` appropriately.
diff --git a/packages/fetchai/connections/webhook/connection.py b/packages/fetchai/connections/webhook/connection.py
index e646187c68..3b3d8f5224 100644
--- a/packages/fetchai/connections/webhook/connection.py
+++ b/packages/fetchai/connections/webhook/connection.py
@@ -16,7 +16,6 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""Webhook connection and channel."""
import asyncio
@@ -28,18 +27,19 @@
from aiohttp import web # type: ignore
from aea.configurations.base import PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.mail.base import Address, Envelope, EnvelopeContext, URI
+from packages.fetchai.protocols.http.dialogues import HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
SUCCESS = 200
NOT_FOUND = 404
REQUEST_TIMEOUT = 408
SERVER_ERROR = 500
-PUBLIC_ID = PublicId.from_str("fetchai/webhook:0.4.0")
+PUBLIC_ID = PublicId.from_str("fetchai/webhook:0.5.0")
-logger = logging.getLogger("aea.packages.fetchai.connections.webhook")
+_default_logger = logging.getLogger("aea.packages.fetchai.connections.webhook")
RequestId = str
@@ -54,6 +54,7 @@ def __init__(
webhook_port: int,
webhook_url_path: str,
connection_id: PublicId,
+ logger: logging.Logger = _default_logger,
):
"""
Initialize a webhook channel.
@@ -80,6 +81,7 @@ def __init__(
self.in_queue = None # type: Optional[asyncio.Queue] # pragma: no cover
self.logger = logger
self.logger.info("Initialised a webhook channel")
+ self._dialogues = HttpDialogues(str(WebhookConnection.connection_id))
async def connect(self) -> None:
"""
@@ -121,7 +123,7 @@ async def disconnect(self) -> None:
await self.runner.cleanup()
await self.app.shutdown()
await self.app.cleanup()
- logger.info("Webhook app is shutdown.")
+ self.logger.info("Webhook app is shutdown.")
self.is_stopped = True
async def _receive_webhook(self, request: web.Request) -> web.Response:
@@ -145,7 +147,7 @@ async def send(self, envelope: Envelope) -> None:
:param envelope: the envelope
"""
- logger.warning(
+ self.logger.warning(
"Dropping envelope={} as sending via the webhook is not possible!".format(
envelope
)
@@ -169,11 +171,15 @@ async def to_envelope(self, request: web.Request) -> Envelope:
version=version,
headers=json.dumps(dict(request.headers)),
bodyy=payload_bytes if payload_bytes is not None else b"",
+ dialogue_reference=self._dialogues.new_self_initiated_dialogue_reference(),
)
+ http_message.counterparty = self.agent_address
+ http_dialogue = self._dialogues.update(http_message)
+ assert http_dialogue is not None, "Could not create dialogue."
envelope = Envelope(
- to=self.agent_address,
- sender=request.remote,
- protocol_id=PublicId.from_str("fetchai/http:0.3.0"),
+ to=http_message.counterparty,
+ sender=http_message.sender,
+ protocol_id=http_message.protocol_id,
context=context,
message=http_message,
)
@@ -202,6 +208,7 @@ def __init__(self, **kwargs):
webhook_port=webhook_port,
webhook_url_path=webhook_url_path,
connection_id=self.connection_id,
+ logger=self.logger,
)
async def connect(self) -> None:
@@ -210,11 +217,14 @@ async def connect(self) -> None:
:return: None
"""
- if not self.connection_status.is_connected:
- self.connection_status.is_connected = True
- self.channel.logger = self.logger
- self.channel.in_queue = asyncio.Queue()
- await self.channel.connect()
+ if self.is_connected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.connecting)
+ self.channel.logger = self.logger
+ self.channel.in_queue = asyncio.Queue()
+ await self.channel.connect()
+ self._state.set(ConnectionStates.connected)
async def disconnect(self) -> None:
"""
@@ -222,9 +232,12 @@ async def disconnect(self) -> None:
:return: None
"""
- if self.connection_status.is_connected:
- self.connection_status.is_connected = False
- await self.channel.disconnect()
+ if self.is_disconnected: # pragma: nocover
+ return
+
+ self._state.set(ConnectionStates.disconnecting)
+ await self.channel.disconnect()
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: "Envelope") -> None:
"""
@@ -233,7 +246,7 @@ async def send(self, envelope: "Envelope") -> None:
:param envelope: the envelop
:return: None
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
@@ -246,7 +259,7 @@ async def receive(self, *args, **kwargs) -> Optional[Union["Envelope", None]]:
:return: the envelope received, or None.
"""
- if not self.connection_status.is_connected:
+ if not self.is_connected:
raise ConnectionError(
"Connection not established yet. Please use 'connect()'."
) # pragma: no cover
diff --git a/packages/fetchai/connections/webhook/connection.yaml b/packages/fetchai/connections/webhook/connection.yaml
index 62245d007a..81340ceeab 100644
--- a/packages/fetchai/connections/webhook/connection.yaml
+++ b/packages/fetchai/connections/webhook/connection.yaml
@@ -1,15 +1,16 @@
name: webhook
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The webhook connection that wraps a webhook functionality.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmU79DgcrbrZkZzxV14HrYXwrsGuqPGnDBYPxeZFM9EwhF
__init__.py: QmWUKSmXaBgGMvKgdmzKmMjCx43BnrfW6og2n3afNoAALq
- connection.py: QmeGqgig7Ab95znNf2kBHukAjbsaofFX24SYRaDreEwn9V
+ connection.py: QmVgBgXsAz82disfpUMZQueNEezi12w3sWxWWwpgERNf3X
fingerprint_ignore_patterns: []
protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
class_name: WebhookConnection
config:
webhook_address: 127.0.0.1
@@ -17,7 +18,7 @@ config:
webhook_url_path: /some/url/path
excluded_protocols: []
restricted_to_protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
dependencies:
aiohttp:
version: ==3.6.2
diff --git a/packages/fetchai/contracts/erc1155/contract.py b/packages/fetchai/contracts/erc1155/contract.py
index 897ace4f28..43f35a5de3 100644
--- a/packages/fetchai/contracts/erc1155/contract.py
+++ b/packages/fetchai/contracts/erc1155/contract.py
@@ -68,7 +68,7 @@ def _generate_id(index: int, token_type: int) -> int:
return token_id
@classmethod
- def get_deploy_transaction(
+ def get_deploy_transaction( # type: ignore
cls,
ledger_api: LedgerApi,
deployer_address: Address,
diff --git a/packages/fetchai/contracts/erc1155/contract.yaml b/packages/fetchai/contracts/erc1155/contract.yaml
index 34cba4e2ae..c594050bcd 100644
--- a/packages/fetchai/contracts/erc1155/contract.yaml
+++ b/packages/fetchai/contracts/erc1155/contract.yaml
@@ -1,6 +1,6 @@
name: erc1155
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The erc1155 contract implements an ERC1155 contract package.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -8,7 +8,7 @@ fingerprint:
__init__.py: QmVadErLF2u6xuTP4tnTGcMCvhh34V9VDZm53r7Z4Uts9Z
build/Migrations.json: QmfFYYWoq1L1Ni6YPBWWoRPvCZKBLZ7qzN3UDX537mCeuE
build/erc1155.json: Qma5n7au2NDCg1nLwYfYnmFNwWChFuXtu65w5DV7wAZRvw
- contract.py: QmTLSEcNMGXK3H5hjYYxTPADzLtErgXi8znzm7a3Mfim4M
+ contract.py: QmVp2X1dLHpkR9uvZZxjvPNgs9sQSLLiCJRobEyqTnMnNV
contracts/Migrations.sol: QmbW34mYrj3uLteyHf3S46pnp9bnwovtCXHbdBHfzMkSZx
contracts/erc1155.vy: QmXwob8G1uX7fDvtuuKW139LALWtQmGw2vvaTRBVAWRxTx
migrations/1_initial_migration.js: QmcxaWKQ2yPkQBmnpXmcuxPZQUMuUudmPmX3We8Z9vtAf7
diff --git a/examples/protocol_specification_ex/contract_api.yaml b/packages/fetchai/protocols/contract_api/README.md
similarity index 82%
rename from examples/protocol_specification_ex/contract_api.yaml
rename to packages/fetchai/protocols/contract_api/README.md
index 0b02f144ef..4001a89852 100644
--- a/examples/protocol_specification_ex/contract_api.yaml
+++ b/packages/fetchai/protocols/contract_api/README.md
@@ -1,7 +1,26 @@
+# Contract API Protocol
+
+**Name:** contract_api
+
+**Author**: fetchai
+
+**Version**: 0.2.0
+
+**Short Description**: A protocol for contract APIs' requests and responses.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for contract APIs' requests and responses.
+
+## Specification
+
+```yaml
---
name: contract_api
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for contract APIs requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -65,3 +84,6 @@ termination: [state, raw_transaction, raw_message]
roles: {agent, ledger}
end_states: [successful, failed]
...
+```
+
+## Links
diff --git a/packages/fetchai/protocols/contract_api/custom_types.py b/packages/fetchai/protocols/contract_api/custom_types.py
index 241f7a281d..b8a682e2a5 100644
--- a/packages/fetchai/protocols/contract_api/custom_types.py
+++ b/packages/fetchai/protocols/contract_api/custom_types.py
@@ -44,9 +44,9 @@ def __init__(
def _check_consistency(self) -> None:
"""Check consistency of the object."""
assert self._body is not None, "body must not be None"
- assert isinstance(self._body, dict) and [
- isinstance(key, str) for key in self._body.keys()
- ]
+ assert isinstance(self._body, dict) and all(
+ [isinstance(key, str) for key in self._body.keys()]
+ )
@property
def body(self) -> Dict[str, Any]:
@@ -58,7 +58,7 @@ def encode(kwargs_protobuf_object, kwargs_object: "Kwargs") -> None:
"""
Encode an instance of this class into the protocol buffer object.
- The protocol buffer object in the kwargs_protobuf_object argument must be matched with the instance of this class in the 'kwargs_object' argument.
+ The protocol buffer object in the kwargs_protobuf_object argument is matched with the instance of this class in the 'kwargs_object' argument.
:param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.
:param kwargs_object: an instance of this class to be encoded in the protocol buffer object.
@@ -72,10 +72,10 @@ def decode(cls, kwargs_protobuf_object) -> "Kwargs":
"""
Decode a protocol buffer object that corresponds with this class into an instance of this class.
- A new instance of this class must be created that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.
+ A new instance of this class is created that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.
- :param raw_transaction_protobuf_object: the protocol buffer object whose type corresponds with this class.
- :return: A new instance of this class that matches the protocol buffer object in the 'raw_transaction_protobuf_object' argument.
+ :param kwargs_protobuf_object: the protocol buffer object whose type corresponds with this class.
+ :return: A new instance of this class that matches the protocol buffer object in the 'kwargs_protobuf_object' argument.
"""
kwargs = pickle.loads(kwargs_protobuf_object.kwargs_bytes) # nosec
return kwargs
diff --git a/packages/fetchai/protocols/contract_api/dialogues.py b/packages/fetchai/protocols/contract_api/dialogues.py
index 6a4cc668ae..87230d4b57 100644
--- a/packages/fetchai/protocols/contract_api/dialogues.py
+++ b/packages/fetchai/protocols/contract_api/dialogues.py
@@ -161,7 +161,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> ContractApiDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of contract_api dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/contract_api/message.py b/packages/fetchai/protocols/contract_api/message.py
index c561e3fa70..af799232ae 100644
--- a/packages/fetchai/protocols/contract_api/message.py
+++ b/packages/fetchai/protocols/contract_api/message.py
@@ -43,7 +43,7 @@
class ContractApiMessage(Message):
"""A protocol for contract APIs requests and responses."""
- protocol_id = ProtocolId("fetchai", "contract_api", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/contract_api:0.2.0")
Kwargs = CustomKwargs
diff --git a/packages/fetchai/protocols/contract_api/protocol.yaml b/packages/fetchai/protocols/contract_api/protocol.yaml
index dc4a21921c..836741f16a 100644
--- a/packages/fetchai/protocols/contract_api/protocol.yaml
+++ b/packages/fetchai/protocols/contract_api/protocol.yaml
@@ -1,16 +1,17 @@
name: contract_api
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for contract APIs requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmYgqZHPmrEL78eNbryWGSKowpLGv6EbyPcG49jU4pomni
__init__.py: QmZodYjNqoMgGAGKfkCU4zU9t1Cx9MAownqSy4wyVdwaHF
contract_api.proto: QmNwngtcYFSuqL8yeTGVXmrHjfebCybdUa9BnTDKXn8odk
contract_api_pb2.py: QmVT6Fv53KyFhshNFEo38seHypd7Y62psBaF8NszV8iRHK
- custom_types.py: QmRVz9wCrLeTaF8iJsG1NdLuDGXzUEy6UXJ6opP71wrd7e
- dialogues.py: QmYnc1GDhQ9p79LwzvKo49Xx4RiVtVwekskNniG5Rw9zoa
- message.py: QmTgkpQYgZHqBdJaBdS5hrcZ5B8D1JPCyAcNiPFkVydznN
+ custom_types.py: QmZsFfRJNQ9grP5FpNeY8683uDGNTAL97Wfcx7VaLR1cSe
+ dialogues.py: Qmf6dpmyEbHrvzMhEzDZ6SnbxHRMNNkgPinjB8Ptsz1k1U
+ message.py: QmZNEBb21xwomsn6bovewjm1WvxdGm9x9dc4LcL6S2BrX3
serialization.py: QmdJZ6GBrURgzJCfYSZzLhWirfm5bDJxumz7ieAELC9juw
fingerprint_ignore_patterns: []
dependencies:
diff --git a/examples/protocol_specification_ex/fipa.yaml b/packages/fetchai/protocols/fipa/README.md
similarity index 74%
rename from examples/protocol_specification_ex/fipa.yaml
rename to packages/fetchai/protocols/fipa/README.md
index a774647101..ebe80c17e8 100644
--- a/examples/protocol_specification_ex/fipa.yaml
+++ b/packages/fetchai/protocols/fipa/README.md
@@ -1,7 +1,26 @@
+# Fipa Protocol
+
+**Name:** fipa
+
+**Author**: fetchai
+
+**Version**: 0.5.0
+
+**Short Description**: A protocol for FIPA ACL.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for two agents to negotiate over a fixed set of resources.
+
+## Specification
+
+```yaml
---
name: fipa
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: A protocol for FIPA ACL.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -46,4 +65,9 @@ reply:
termination: [decline, match_accept, match_accept_w_inform, inform]
roles: {seller, buyer}
end_states: [successful, declined_cfp, declined_propose, declined_accept]
-...
\ No newline at end of file
+...
+```
+
+## Links
+
+* FIPA Foundation
\ No newline at end of file
diff --git a/packages/fetchai/protocols/fipa/message.py b/packages/fetchai/protocols/fipa/message.py
index 237481fcb7..4c637a072e 100644
--- a/packages/fetchai/protocols/fipa/message.py
+++ b/packages/fetchai/protocols/fipa/message.py
@@ -39,7 +39,7 @@
class FipaMessage(Message):
"""A protocol for FIPA ACL."""
- protocol_id = ProtocolId("fetchai", "fipa", "0.4.0")
+ protocol_id = ProtocolId.from_str("fetchai/fipa:0.5.0")
Description = CustomDescription
diff --git a/packages/fetchai/protocols/fipa/protocol.yaml b/packages/fetchai/protocols/fipa/protocol.yaml
index 32fa579a7f..cfa31e43a2 100644
--- a/packages/fetchai/protocols/fipa/protocol.yaml
+++ b/packages/fetchai/protocols/fipa/protocol.yaml
@@ -1,16 +1,17 @@
name: fipa
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: A protocol for FIPA ACL.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmQknY2SSJqEHU6K4Wzm8NQovtCCkJ78DuNLg2wWNq18hB
__init__.py: QmZuv8RGegxunYaJ7sHLwj2oLLCFCAGF139b8DxEY68MRT
custom_types.py: Qmb7bzEUAW74ZeSFqL7sTccNCjudStV63K4CFNZtibKUHB
dialogues.py: QmYcgipy556vUs74sC9CsckBbPCYSMsiR36Z8TCPVkEkpq
fipa.proto: QmP7JqnuQSQ9BDcKkscrTydKEX4wFBoyFaY1bkzGkamcit
fipa_pb2.py: QmZMkefJLrb3zJKoimb6a9tdpxDBhc8rR2ghimqg7gZ471
- message.py: QmeQiZadU2g6T4hw4mXkNLLBirVdPmJUQjTwA6wVv9hrbn
+ message.py: QmZYMvPcDogeZPkhx7YPjAEJRX8VNGSF1jetdXcQmYnT6R
serialization.py: QmU6Xj55eaRxCYAeyR1difC769NHLB8kciorajvkLZCwDR
fingerprint_ignore_patterns: []
dependencies:
diff --git a/examples/protocol_specification_ex/gym.yaml b/packages/fetchai/protocols/gym/README.md
similarity index 64%
rename from examples/protocol_specification_ex/gym.yaml
rename to packages/fetchai/protocols/gym/README.md
index 6235bcf067..cced15fa91 100644
--- a/examples/protocol_specification_ex/gym.yaml
+++ b/packages/fetchai/protocols/gym/README.md
@@ -1,7 +1,26 @@
+# Gym Protocol
+
+**Name:** gym
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: A protocol for interacting with a gym connection.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for interacting with a gym connection.
+
+## Specification
+
+```yaml
---
name: gym
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for interacting with a gym connection.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -36,3 +55,8 @@ termination: [close]
roles: {agent, environment}
end_states: [successful]
...
+```
+
+## Links
+
+* OpenAI Gym
\ No newline at end of file
diff --git a/packages/fetchai/protocols/gym/dialogues.py b/packages/fetchai/protocols/gym/dialogues.py
index f21f745b90..6268d341f5 100644
--- a/packages/fetchai/protocols/gym/dialogues.py
+++ b/packages/fetchai/protocols/gym/dialogues.py
@@ -134,7 +134,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> GymDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of gym dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/gym/message.py b/packages/fetchai/protocols/gym/message.py
index 906971a0e7..07d9776ba3 100644
--- a/packages/fetchai/protocols/gym/message.py
+++ b/packages/fetchai/protocols/gym/message.py
@@ -36,7 +36,7 @@
class GymMessage(Message):
"""A protocol for interacting with a gym connection."""
- protocol_id = ProtocolId("fetchai", "gym", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/gym:0.4.0")
AnyObject = CustomAnyObject
diff --git a/packages/fetchai/protocols/gym/protocol.yaml b/packages/fetchai/protocols/gym/protocol.yaml
index bb5aa7f9a3..ace1311bc5 100644
--- a/packages/fetchai/protocols/gym/protocol.yaml
+++ b/packages/fetchai/protocols/gym/protocol.yaml
@@ -1,16 +1,17 @@
name: gym
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for interacting with a gym connection.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmPcnBEUW1NfTBRwMvpPQJ8NTP6MG3CueUjjHQJ1sf77uQ
__init__.py: QmWBvruqGuU2BVCq8cuP1S3mgvuC78yrG4TdtSvKhCT8qX
custom_types.py: QmfDaswopanUqsETQXMatKfwwDSSo7q2Edz9MXGimT5jbf
- dialogues.py: QmWJv1gRNvqkFGyx9FGkhhorymD5javXuBA8HwQ6z9BLPw
+ dialogues.py: Qmd7n1c7wWacCkTx1kxsuo73QhxN6e4uufPYmF775cYqVx
gym.proto: QmQGF9Xz4Z93wmhdKoztzxjo5pS4SsAWe2TQdvZCLuzdGC
gym_pb2.py: QmSTz7xrL8ryqzR1Sgu1NpR6PmW7GUhBGnN2qYc8m8NCcN
- message.py: QmaiYJbphafhurv7cYCLfJLY4hHCTzyqWz2r8YRJngkpq4
+ message.py: QmYr1qpXRTh8xMWmKBQoBfdTsms4YExioQxD3RyxY9JZVm
serialization.py: QmaZd7YMHrHZvbeMMb1JfnkUZRHk7zKy45M7kDvG5wbY9C
fingerprint_ignore_patterns: []
dependencies:
diff --git a/examples/protocol_specification_ex/http.yaml b/packages/fetchai/protocols/http/README.md
similarity index 55%
rename from examples/protocol_specification_ex/http.yaml
rename to packages/fetchai/protocols/http/README.md
index 19ee91c45a..0ea3d8648f 100644
--- a/examples/protocol_specification_ex/http.yaml
+++ b/packages/fetchai/protocols/http/README.md
@@ -1,7 +1,26 @@
+# HTTP Protocol
+
+**Name:** http
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: A protocol for HTTP requests and responses.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for interacting with a client/server via HTTP requests and responses.
+
+## Specification
+
+```yaml
---
name: http
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for HTTP requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -28,3 +47,8 @@ termination: [response]
roles: {client, server}
end_states: [successful]
...
+```
+
+## Links
+
+* HTTP Specification
\ No newline at end of file
diff --git a/packages/fetchai/protocols/http/dialogues.py b/packages/fetchai/protocols/http/dialogues.py
index a6d3ae9f6c..abbd0d05b4 100644
--- a/packages/fetchai/protocols/http/dialogues.py
+++ b/packages/fetchai/protocols/http/dialogues.py
@@ -121,7 +121,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> HttpDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of http dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/http/message.py b/packages/fetchai/protocols/http/message.py
index 250ceba044..699e9422df 100644
--- a/packages/fetchai/protocols/http/message.py
+++ b/packages/fetchai/protocols/http/message.py
@@ -34,7 +34,7 @@
class HttpMessage(Message):
"""A protocol for HTTP requests and responses."""
- protocol_id = ProtocolId("fetchai", "http", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/http:0.4.0")
class Performative(Enum):
"""Performatives for the http protocol."""
diff --git a/packages/fetchai/protocols/http/protocol.yaml b/packages/fetchai/protocols/http/protocol.yaml
index caaca49edf..32585f1a6b 100644
--- a/packages/fetchai/protocols/http/protocol.yaml
+++ b/packages/fetchai/protocols/http/protocol.yaml
@@ -1,15 +1,16 @@
name: http
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for HTTP requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmP8ATR4x159fe1363orvdFj7JTJJHWmSdFEVVW62USGyC
__init__.py: QmRWie4QPiFJE8nK4fFJ6prqoG3u36cPo7st5JUZAGpVWv
- dialogues.py: QmYXrUN76rptudYbvdZwzf4DRPN2HkuG67mkxvzznLBvao
+ dialogues.py: QmbhfvfdniejPAUT9dZD8AGv6vZNkVRRy9spi8aCU1kJb5
http.proto: QmdTUTvvxGxMxSTB67AXjMUSDLdsxBYiSuJNVxHuLKB1jS
http_pb2.py: QmYYKqdwiueq54EveL9WXn216FXLSQ6XGJJHoiJxwJjzHC
- message.py: QmX1rFsvggjpHcujLhB3AZRJpUWpEsf9gG6M2A2qdg6FVY
+ message.py: QmTMEru7pjE4RQXPbTcMm6fNSwyCu9xdpZvQapjqd22ypG
serialization.py: QmUgo5BtLYDyy7syHBd6brd8zAXivNR2UEiBckryCwg6hk
fingerprint_ignore_patterns: []
dependencies:
diff --git a/examples/protocol_specification_ex/ledger_api.yaml b/packages/fetchai/protocols/ledger_api/README.md
similarity index 81%
rename from examples/protocol_specification_ex/ledger_api.yaml
rename to packages/fetchai/protocols/ledger_api/README.md
index eb39a555fe..692a7ae6d1 100644
--- a/examples/protocol_specification_ex/ledger_api.yaml
+++ b/packages/fetchai/protocols/ledger_api/README.md
@@ -1,7 +1,26 @@
+# Ledger API Protocol
+
+**Name:** ledger_api
+
+**Author**: fetchai
+
+**Version**: 0.2.0
+
+**Short Description**: A protocol for ledger APIs' requests and responses.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for interacting with ledger APIs.
+
+## Specification
+
+```yaml
---
name: ledger_api
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for ledger APIs requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -42,7 +61,7 @@ ct:TransactionReceipt: |
bytes transaction_receipt = 1;
...
---
-initiation: [get_balance, get_raw_transaction, send_signed_transaction]
+initiation: [get_balance, get_raw_transaction, send_signed_transaction, get_transaction_receipt]
reply:
get_balance: [balance]
balance: []
@@ -56,4 +75,7 @@ reply:
termination: [balance, transaction_receipt]
roles: {agent, ledger}
end_states: [successful]
-...
\ No newline at end of file
+...
+```
+
+## Links
diff --git a/packages/fetchai/protocols/ledger_api/dialogues.py b/packages/fetchai/protocols/ledger_api/dialogues.py
index d9ba38ddac..11ce182a86 100644
--- a/packages/fetchai/protocols/ledger_api/dialogues.py
+++ b/packages/fetchai/protocols/ledger_api/dialogues.py
@@ -42,6 +42,7 @@ class LedgerApiDialogue(Dialogue):
LedgerApiMessage.Performative.GET_BALANCE,
LedgerApiMessage.Performative.GET_RAW_TRANSACTION,
LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,
+ LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,
}
)
TERMINAL_PERFORMATIVES = frozenset(
@@ -158,7 +159,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> LedgerApiDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of ledger_api dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/ledger_api/message.py b/packages/fetchai/protocols/ledger_api/message.py
index a18d83b613..54d418f28f 100644
--- a/packages/fetchai/protocols/ledger_api/message.py
+++ b/packages/fetchai/protocols/ledger_api/message.py
@@ -48,7 +48,7 @@
class LedgerApiMessage(Message):
"""A protocol for ledger APIs requests and responses."""
- protocol_id = ProtocolId("fetchai", "ledger_api", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/ledger_api:0.2.0")
RawTransaction = CustomRawTransaction
diff --git a/packages/fetchai/protocols/ledger_api/protocol.yaml b/packages/fetchai/protocols/ledger_api/protocol.yaml
index 489723c3ea..06b32a9639 100644
--- a/packages/fetchai/protocols/ledger_api/protocol.yaml
+++ b/packages/fetchai/protocols/ledger_api/protocol.yaml
@@ -1,16 +1,17 @@
name: ledger_api
author: fetchai
-version: 0.1.0
+version: 0.2.0
description: A protocol for ledger APIs requests and responses.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmdSwpA6Z5p93mwxJdA6go8Fs3H7pHVx8yBa2Qm6QDoKXa
__init__.py: Qmct8jVx6ndWwaa5HXJAJgMraVuZ8kMeyx6rnEeHAYHwDJ
custom_types.py: QmWRrvFStMhVJy8P2WD6qjDgk14ZnxErN7XymxUtof7HQo
- dialogues.py: QmdXcqQQAMZQWscKkgi61JtzMAsucFKjSimnephhxyWaPp
+ dialogues.py: QmW93kSNv6sETs2zZTcPVqoVnEADSHotu9vLP9QFQV7zrP
ledger_api.proto: QmfLcv7jJcGJ1gAdCMqsyxJcRud7RaTWteSXHL5NvGuViP
ledger_api_pb2.py: QmQhM848REJTDKDoiqxkTniChW8bNNm66EtwMRkvVdbMry
- message.py: QmNPKh6Pdb9Eryc2mFxkzeiZZt1wESrvKBGriqeszUAGSj
+ message.py: QmTvJcttBx5Z2hNbJVHNFPyL9vXQYRkvmriCRDEeJnVVqq
serialization.py: QmUvysZKkt5xLKLVHAyaZQ3jsRDkPn5bJURdsTDHgkE3HS
fingerprint_ignore_patterns: []
dependencies:
diff --git a/examples/protocol_specification_ex/ml_trade.yaml b/packages/fetchai/protocols/ml_trade/README.md
similarity index 66%
rename from examples/protocol_specification_ex/ml_trade.yaml
rename to packages/fetchai/protocols/ml_trade/README.md
index 44098d5bf6..45e7ee2637 100644
--- a/examples/protocol_specification_ex/ml_trade.yaml
+++ b/packages/fetchai/protocols/ml_trade/README.md
@@ -1,7 +1,26 @@
+# ML Trade Protocol
+
+**Name:** ml_trade
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: A protocol for trading data for training and prediction purposes.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for trading data for training and prediction purposes.
+
+## Specification
+
+```yaml
---
name: ml_trade
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for trading data for training and prediction purposes.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -39,4 +58,7 @@ reply:
termination: [data]
roles: {seller, buyer}
end_states: [successful]
-...
\ No newline at end of file
+...
+```
+
+## Links
diff --git a/packages/fetchai/protocols/ml_trade/dialogues.py b/packages/fetchai/protocols/ml_trade/dialogues.py
index 263794b3c9..6c18244170 100644
--- a/packages/fetchai/protocols/ml_trade/dialogues.py
+++ b/packages/fetchai/protocols/ml_trade/dialogues.py
@@ -125,7 +125,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> MlTradeDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of ml_trade dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/ml_trade/message.py b/packages/fetchai/protocols/ml_trade/message.py
index 72cedcd1d0..7161f68c3b 100644
--- a/packages/fetchai/protocols/ml_trade/message.py
+++ b/packages/fetchai/protocols/ml_trade/message.py
@@ -39,7 +39,7 @@
class MlTradeMessage(Message):
"""A protocol for trading data for training and prediction purposes."""
- protocol_id = ProtocolId("fetchai", "ml_trade", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/ml_trade:0.4.0")
Description = CustomDescription
diff --git a/packages/fetchai/protocols/ml_trade/protocol.yaml b/packages/fetchai/protocols/ml_trade/protocol.yaml
index ab17b5299b..f44b46a106 100644
--- a/packages/fetchai/protocols/ml_trade/protocol.yaml
+++ b/packages/fetchai/protocols/ml_trade/protocol.yaml
@@ -1,14 +1,15 @@
name: ml_trade
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for trading data for training and prediction purposes.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmPtJwd9ApR8N6pYdC5ddetPF7tEn6EPmnqiU1NZNmz5EU
__init__.py: QmXZMVdsBXUJxLZvwwhWBx58xfxMSyoGxdYp5Aeqmzqhzt
custom_types.py: QmPa6mxbN8WShsniQxJACfzAPRjGzYLbUFGoVU4N9DewUw
- dialogues.py: QmZFztFu4LxHdsJZpSHizELFStHtz2ZGfQBx9cnP7gHHWf
- message.py: QmdCpkebeDrFZk4R7S2mrX2KMCDgo8JV78Hj6jb6sA5EL4
+ dialogues.py: QmUV1KiKgdAak1UHe3me7kRUNonhZY1FC57SLnpSCgYpvX
+ message.py: QmNaZ6tFMcux7K374dDCGeKx6FMVQSrog2ruSxnprPnFEv
ml_trade.proto: QmeB21MQduEGQCrtiYZQzPpRqHL4CWEkvvcaKZ9GsfE8f6
ml_trade_pb2.py: QmZVvugPysR1og6kWCJkvo3af2s9pQRHfuj4BptE7gU1EU
serialization.py: QmSHywy12uQkzakU1RHnnkaPuTzaFTALsKisyYF8dPc8ns
diff --git a/examples/protocol_specification_ex/oef_search.yaml b/packages/fetchai/protocols/oef_search/README.md
similarity index 62%
rename from examples/protocol_specification_ex/oef_search.yaml
rename to packages/fetchai/protocols/oef_search/README.md
index 2ec88ba6ea..c3e11c95c6 100644
--- a/examples/protocol_specification_ex/oef_search.yaml
+++ b/packages/fetchai/protocols/oef_search/README.md
@@ -1,3 +1,23 @@
+# OEF Search Protocol
+
+**Name:** oef_search
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: A protocol for interacting with an OEF search service.
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for interacting with an OEF search service.
+It allows for registering of agents and services, and searching of agents and services using a query language.
+
+## Specification
+
+```yaml
---
name: oef_search
author: fetchai
@@ -14,8 +34,7 @@ speech_acts:
query: ct:Query
search_result:
agents: pt:list[pt:str]
- success: {}
- error:
+ oef_error:
oef_error_operation: ct:OefErrorOperation
...
---
@@ -41,13 +60,16 @@ ct:OefErrorOperation: |
---
initiation: [register_service, unregister_service, search_services]
reply:
- register_service: [success, error]
- unregister_service: [success, error]
- search_services: [search_result, error]
+ register_service: [oef_error]
+ unregister_service: [oef_error]
+ search_services: [search_result, oef_error]
success: []
search_result: []
- error: []
-termination: [success, error, search_result]
+ oef_error: []
+termination: [oef_error, search_result]
roles: {agent, oef_node}
end_states: [successful, failed]
-...
\ No newline at end of file
+...
+```
+
+## Links
diff --git a/packages/fetchai/protocols/oef_search/dialogues.py b/packages/fetchai/protocols/oef_search/dialogues.py
index 90daad5cef..d69507a40a 100644
--- a/packages/fetchai/protocols/oef_search/dialogues.py
+++ b/packages/fetchai/protocols/oef_search/dialogues.py
@@ -145,7 +145,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> OefSearchDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of oef_search dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/oef_search/message.py b/packages/fetchai/protocols/oef_search/message.py
index 44162b200a..b1dbadac49 100644
--- a/packages/fetchai/protocols/oef_search/message.py
+++ b/packages/fetchai/protocols/oef_search/message.py
@@ -42,7 +42,7 @@
class OefSearchMessage(Message):
"""A protocol for interacting with an OEF search service."""
- protocol_id = ProtocolId("fetchai", "oef_search", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/oef_search:0.4.0")
Description = CustomDescription
diff --git a/packages/fetchai/protocols/oef_search/protocol.yaml b/packages/fetchai/protocols/oef_search/protocol.yaml
index dfa8095446..1efc074c8d 100644
--- a/packages/fetchai/protocols/oef_search/protocol.yaml
+++ b/packages/fetchai/protocols/oef_search/protocol.yaml
@@ -1,14 +1,15 @@
name: oef_search
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: A protocol for interacting with an OEF search service.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmWKpDy8H5V6vXkejyH8XQuQCA4aScTNvnDtM1gpLgFiC6
__init__.py: QmRvTtynKcd7shmzgf8aZdcA5witjNL5cL2a7WPgscp7wq
custom_types.py: QmR4TS6KhXpRtGqq78B8mXMiiFXcFe7JEkxB7jHvqPVkgD
- dialogues.py: QmQyUVWzX8uMq48sWU6pUBazk7UiTMhydLDVLWQs9djY6v
- message.py: QmY5qSJawsgmcKZ3dDBij9s4hN41BpnhbzTtVkRaQdT6QU
+ dialogues.py: QmUYiDwidkEiwGh7xqTuBcZ44CTtu5wdCCUZqpEmQkDWha
+ message.py: QmV8AFX5pQjC4u3ZDfkyy2DzJsTHd9zE5b6GNteKuenAs6
oef_search.proto: QmRg28H6bNo1PcyJiKLYjHe6FCwtE6nJ43DeJ4RFTcHm68
oef_search_pb2.py: Qmd6S94v2GuZ2ffDupTa5ESBx4exF9dgoV8KcYtJVL6KhN
serialization.py: QmfXX9HJsQvNfeffGxPeUBw7cMznSjojDYe6TZ6jHpphQ4
diff --git a/examples/protocol_specification_ex/tac.yaml b/packages/fetchai/protocols/tac/README.md
similarity index 69%
rename from examples/protocol_specification_ex/tac.yaml
rename to packages/fetchai/protocols/tac/README.md
index 0aa87c1ec7..fbcfa8bb8c 100644
--- a/examples/protocol_specification_ex/tac.yaml
+++ b/packages/fetchai/protocols/tac/README.md
@@ -1,7 +1,26 @@
+# TAC Protocol
+
+**Name:** tac
+
+**Author**: fetchai
+
+**Version**: 0.4.0
+
+**Short Description**: The tac protocol implements the messages an AEA needs to participate in a Trading Agent Competition (TAC).
+
+**License**: Apache-2.0
+
+## Description
+
+This is a protocol for participating in a Trading Agent Competition (TAC).
+
+## Specification
+
+```yaml
---
name: tac
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The tac protocol implements the messages an AEA needs to participate
in the TAC.
license: Apache-2.0
@@ -11,30 +30,30 @@ speech_acts:
agent_name: pt:str
unregister: {}
transaction:
- tx_id: pt:str
- tx_sender_addr: pt:str
- tx_counterparty_addr: pt:str
+ transaction_id: pt:str
+ ledger_id: pt:str
+ sender_address: pt:str
+ counterparty_address: pt:str
amount_by_currency_id: pt:dict[pt:str, pt:int]
- tx_sender_fee: pt:int
- tx_counterparty_fee: pt:int
+ fee_by_currency_id: pt:dict[pt:str, pt:int]
quantities_by_good_id: pt:dict[pt:str, pt:int]
- tx_nonce: pt:int
- tx_sender_signature: pt:str
- tx_counterparty_signature: pt:str
+ nonce: pt:str
+ sender_signature: pt:str
+ counterparty_signature: pt:str
cancelled: {}
game_data:
amount_by_currency_id: pt:dict[pt:str, pt:int]
exchange_params_by_currency_id: pt:dict[pt:str, pt:float]
quantities_by_good_id: pt:dict[pt:str, pt:int]
utility_params_by_good_id: pt:dict[pt:str, pt:float]
- tx_fee: pt:int
+ fee_by_currency_id: pt:dict[pt:str, pt:int]
agent_addr_to_name: pt:dict[pt:str, pt:str]
currency_id_to_name: pt:dict[pt:str, pt:str]
good_id_to_name: pt:dict[pt:str, pt:str]
version_id: pt:str
info: pt:optional[pt:dict[pt:str, pt:str]]
transaction_confirmation:
- tx_id: pt:str
+ transaction_id: pt:str
amount_by_currency_id: pt:dict[pt:str, pt:int]
quantities_by_good_id: pt:dict[pt:str, pt:int]
tac_error:
@@ -71,3 +90,8 @@ termination: [cancelled, tac_error]
roles: {participant, controller}
end_states: [successful, failed]
...
+```
+
+## Links
+
+* TAC skill in the AEA framework
\ No newline at end of file
diff --git a/packages/fetchai/protocols/tac/dialogues.py b/packages/fetchai/protocols/tac/dialogues.py
index e26f2853ae..37c63d6d36 100644
--- a/packages/fetchai/protocols/tac/dialogues.py
+++ b/packages/fetchai/protocols/tac/dialogues.py
@@ -146,7 +146,7 @@ def create_dialogue(
self, dialogue_label: DialogueLabel, role: Dialogue.Role,
) -> TacDialogue:
"""
- Create an instance of fipa dialogue.
+ Create an instance of tac dialogue.
:param dialogue_label: the identifier of the dialogue
:param role: the role of the agent this dialogue is maintained for
diff --git a/packages/fetchai/protocols/tac/message.py b/packages/fetchai/protocols/tac/message.py
index 257dc705b2..6d032cb2b4 100644
--- a/packages/fetchai/protocols/tac/message.py
+++ b/packages/fetchai/protocols/tac/message.py
@@ -36,7 +36,7 @@
class TacMessage(Message):
"""The tac protocol implements the messages an AEA needs to participate in the TAC."""
- protocol_id = ProtocolId("fetchai", "tac", "0.3.0")
+ protocol_id = ProtocolId.from_str("fetchai/tac:0.4.0")
ErrorCode = CustomErrorCode
@@ -139,6 +139,22 @@ def amount_by_currency_id(self) -> Dict[str, int]:
), "'amount_by_currency_id' content is not set."
return cast(Dict[str, int], self.get("amount_by_currency_id"))
+ @property
+ def counterparty_address(self) -> str:
+ """Get the 'counterparty_address' content from the message."""
+ assert self.is_set(
+ "counterparty_address"
+ ), "'counterparty_address' content is not set."
+ return cast(str, self.get("counterparty_address"))
+
+ @property
+ def counterparty_signature(self) -> str:
+ """Get the 'counterparty_signature' content from the message."""
+ assert self.is_set(
+ "counterparty_signature"
+ ), "'counterparty_signature' content is not set."
+ return cast(str, self.get("counterparty_signature"))
+
@property
def currency_id_to_name(self) -> Dict[str, str]:
"""Get the 'currency_id_to_name' content from the message."""
@@ -161,6 +177,14 @@ def exchange_params_by_currency_id(self) -> Dict[str, float]:
), "'exchange_params_by_currency_id' content is not set."
return cast(Dict[str, float], self.get("exchange_params_by_currency_id"))
+ @property
+ def fee_by_currency_id(self) -> Dict[str, int]:
+ """Get the 'fee_by_currency_id' content from the message."""
+ assert self.is_set(
+ "fee_by_currency_id"
+ ), "'fee_by_currency_id' content is not set."
+ return cast(Dict[str, int], self.get("fee_by_currency_id"))
+
@property
def good_id_to_name(self) -> Dict[str, str]:
"""Get the 'good_id_to_name' content from the message."""
@@ -172,6 +196,18 @@ def info(self) -> Optional[Dict[str, str]]:
"""Get the 'info' content from the message."""
return cast(Optional[Dict[str, str]], self.get("info"))
+ @property
+ def ledger_id(self) -> str:
+ """Get the 'ledger_id' content from the message."""
+ assert self.is_set("ledger_id"), "'ledger_id' content is not set."
+ return cast(str, self.get("ledger_id"))
+
+ @property
+ def nonce(self) -> str:
+ """Get the 'nonce' content from the message."""
+ assert self.is_set("nonce"), "'nonce' content is not set."
+ return cast(str, self.get("nonce"))
+
@property
def quantities_by_good_id(self) -> Dict[str, int]:
"""Get the 'quantities_by_good_id' content from the message."""
@@ -181,66 +217,22 @@ def quantities_by_good_id(self) -> Dict[str, int]:
return cast(Dict[str, int], self.get("quantities_by_good_id"))
@property
- def tx_counterparty_addr(self) -> str:
- """Get the 'tx_counterparty_addr' content from the message."""
- assert self.is_set(
- "tx_counterparty_addr"
- ), "'tx_counterparty_addr' content is not set."
- return cast(str, self.get("tx_counterparty_addr"))
-
- @property
- def tx_counterparty_fee(self) -> int:
- """Get the 'tx_counterparty_fee' content from the message."""
- assert self.is_set(
- "tx_counterparty_fee"
- ), "'tx_counterparty_fee' content is not set."
- return cast(int, self.get("tx_counterparty_fee"))
-
- @property
- def tx_counterparty_signature(self) -> str:
- """Get the 'tx_counterparty_signature' content from the message."""
- assert self.is_set(
- "tx_counterparty_signature"
- ), "'tx_counterparty_signature' content is not set."
- return cast(str, self.get("tx_counterparty_signature"))
-
- @property
- def tx_fee(self) -> int:
- """Get the 'tx_fee' content from the message."""
- assert self.is_set("tx_fee"), "'tx_fee' content is not set."
- return cast(int, self.get("tx_fee"))
+ def sender_address(self) -> str:
+ """Get the 'sender_address' content from the message."""
+ assert self.is_set("sender_address"), "'sender_address' content is not set."
+ return cast(str, self.get("sender_address"))
@property
- def tx_id(self) -> str:
- """Get the 'tx_id' content from the message."""
- assert self.is_set("tx_id"), "'tx_id' content is not set."
- return cast(str, self.get("tx_id"))
+ def sender_signature(self) -> str:
+ """Get the 'sender_signature' content from the message."""
+ assert self.is_set("sender_signature"), "'sender_signature' content is not set."
+ return cast(str, self.get("sender_signature"))
@property
- def tx_nonce(self) -> int:
- """Get the 'tx_nonce' content from the message."""
- assert self.is_set("tx_nonce"), "'tx_nonce' content is not set."
- return cast(int, self.get("tx_nonce"))
-
- @property
- def tx_sender_addr(self) -> str:
- """Get the 'tx_sender_addr' content from the message."""
- assert self.is_set("tx_sender_addr"), "'tx_sender_addr' content is not set."
- return cast(str, self.get("tx_sender_addr"))
-
- @property
- def tx_sender_fee(self) -> int:
- """Get the 'tx_sender_fee' content from the message."""
- assert self.is_set("tx_sender_fee"), "'tx_sender_fee' content is not set."
- return cast(int, self.get("tx_sender_fee"))
-
- @property
- def tx_sender_signature(self) -> str:
- """Get the 'tx_sender_signature' content from the message."""
- assert self.is_set(
- "tx_sender_signature"
- ), "'tx_sender_signature' content is not set."
- return cast(str, self.get("tx_sender_signature"))
+ def transaction_id(self) -> str:
+ """Get the 'transaction_id' content from the message."""
+ assert self.is_set("transaction_id"), "'transaction_id' content is not set."
+ return cast(str, self.get("transaction_id"))
@property
def utility_params_by_good_id(self) -> Dict[str, float]:
@@ -308,19 +300,24 @@ def _is_consistent(self) -> bool:
elif self.performative == TacMessage.Performative.TRANSACTION:
expected_nb_of_contents = 10
assert (
- type(self.tx_id) == str
- ), "Invalid type for content 'tx_id'. Expected 'str'. Found '{}'.".format(
- type(self.tx_id)
+ type(self.transaction_id) == str
+ ), "Invalid type for content 'transaction_id'. Expected 'str'. Found '{}'.".format(
+ type(self.transaction_id)
+ )
+ assert (
+ type(self.ledger_id) == str
+ ), "Invalid type for content 'ledger_id'. Expected 'str'. Found '{}'.".format(
+ type(self.ledger_id)
)
assert (
- type(self.tx_sender_addr) == str
- ), "Invalid type for content 'tx_sender_addr'. Expected 'str'. Found '{}'.".format(
- type(self.tx_sender_addr)
+ type(self.sender_address) == str
+ ), "Invalid type for content 'sender_address'. Expected 'str'. Found '{}'.".format(
+ type(self.sender_address)
)
assert (
- type(self.tx_counterparty_addr) == str
- ), "Invalid type for content 'tx_counterparty_addr'. Expected 'str'. Found '{}'.".format(
- type(self.tx_counterparty_addr)
+ type(self.counterparty_address) == str
+ ), "Invalid type for content 'counterparty_address'. Expected 'str'. Found '{}'.".format(
+ type(self.counterparty_address)
)
assert (
type(self.amount_by_currency_id) == dict
@@ -342,15 +339,24 @@ def _is_consistent(self) -> bool:
type(value_of_amount_by_currency_id)
)
assert (
- type(self.tx_sender_fee) == int
- ), "Invalid type for content 'tx_sender_fee'. Expected 'int'. Found '{}'.".format(
- type(self.tx_sender_fee)
- )
- assert (
- type(self.tx_counterparty_fee) == int
- ), "Invalid type for content 'tx_counterparty_fee'. Expected 'int'. Found '{}'.".format(
- type(self.tx_counterparty_fee)
+ type(self.fee_by_currency_id) == dict
+ ), "Invalid type for content 'fee_by_currency_id'. Expected 'dict'. Found '{}'.".format(
+ type(self.fee_by_currency_id)
)
+ for (
+ key_of_fee_by_currency_id,
+ value_of_fee_by_currency_id,
+ ) in self.fee_by_currency_id.items():
+ assert (
+ type(key_of_fee_by_currency_id) == str
+ ), "Invalid type for dictionary keys in content 'fee_by_currency_id'. Expected 'str'. Found '{}'.".format(
+ type(key_of_fee_by_currency_id)
+ )
+ assert (
+ type(value_of_fee_by_currency_id) == int
+ ), "Invalid type for dictionary values in content 'fee_by_currency_id'. Expected 'int'. Found '{}'.".format(
+ type(value_of_fee_by_currency_id)
+ )
assert (
type(self.quantities_by_good_id) == dict
), "Invalid type for content 'quantities_by_good_id'. Expected 'dict'. Found '{}'.".format(
@@ -371,19 +377,19 @@ def _is_consistent(self) -> bool:
type(value_of_quantities_by_good_id)
)
assert (
- type(self.tx_nonce) == int
- ), "Invalid type for content 'tx_nonce'. Expected 'int'. Found '{}'.".format(
- type(self.tx_nonce)
+ type(self.nonce) == str
+ ), "Invalid type for content 'nonce'. Expected 'str'. Found '{}'.".format(
+ type(self.nonce)
)
assert (
- type(self.tx_sender_signature) == str
- ), "Invalid type for content 'tx_sender_signature'. Expected 'str'. Found '{}'.".format(
- type(self.tx_sender_signature)
+ type(self.sender_signature) == str
+ ), "Invalid type for content 'sender_signature'. Expected 'str'. Found '{}'.".format(
+ type(self.sender_signature)
)
assert (
- type(self.tx_counterparty_signature) == str
- ), "Invalid type for content 'tx_counterparty_signature'. Expected 'str'. Found '{}'.".format(
- type(self.tx_counterparty_signature)
+ type(self.counterparty_signature) == str
+ ), "Invalid type for content 'counterparty_signature'. Expected 'str'. Found '{}'.".format(
+ type(self.counterparty_signature)
)
elif self.performative == TacMessage.Performative.CANCELLED:
expected_nb_of_contents = 0
@@ -466,10 +472,24 @@ def _is_consistent(self) -> bool:
type(value_of_utility_params_by_good_id)
)
assert (
- type(self.tx_fee) == int
- ), "Invalid type for content 'tx_fee'. Expected 'int'. Found '{}'.".format(
- type(self.tx_fee)
+ type(self.fee_by_currency_id) == dict
+ ), "Invalid type for content 'fee_by_currency_id'. Expected 'dict'. Found '{}'.".format(
+ type(self.fee_by_currency_id)
)
+ for (
+ key_of_fee_by_currency_id,
+ value_of_fee_by_currency_id,
+ ) in self.fee_by_currency_id.items():
+ assert (
+ type(key_of_fee_by_currency_id) == str
+ ), "Invalid type for dictionary keys in content 'fee_by_currency_id'. Expected 'str'. Found '{}'.".format(
+ type(key_of_fee_by_currency_id)
+ )
+ assert (
+ type(value_of_fee_by_currency_id) == int
+ ), "Invalid type for dictionary values in content 'fee_by_currency_id'. Expected 'int'. Found '{}'.".format(
+ type(value_of_fee_by_currency_id)
+ )
assert (
type(self.agent_addr_to_name) == dict
), "Invalid type for content 'agent_addr_to_name'. Expected 'dict'. Found '{}'.".format(
@@ -554,9 +574,9 @@ def _is_consistent(self) -> bool:
elif self.performative == TacMessage.Performative.TRANSACTION_CONFIRMATION:
expected_nb_of_contents = 3
assert (
- type(self.tx_id) == str
- ), "Invalid type for content 'tx_id'. Expected 'str'. Found '{}'.".format(
- type(self.tx_id)
+ type(self.transaction_id) == str
+ ), "Invalid type for content 'transaction_id'. Expected 'str'. Found '{}'.".format(
+ type(self.transaction_id)
)
assert (
type(self.amount_by_currency_id) == dict
diff --git a/packages/fetchai/protocols/tac/protocol.yaml b/packages/fetchai/protocols/tac/protocol.yaml
index 2fafda3710..4c89e6ec3b 100644
--- a/packages/fetchai/protocols/tac/protocol.yaml
+++ b/packages/fetchai/protocols/tac/protocol.yaml
@@ -1,18 +1,19 @@
name: tac
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The tac protocol implements the messages an AEA needs to participate
in the TAC.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
+ README.md: QmTbC6jKYdPHMRp8KfFo5m7gvk7tDUVts8PGHaPSkK5cTw
__init__.py: QmZYdAjm3o44drRiY3MT4RtG2fFLxtaL8h898DmjoJwJzV
custom_types.py: QmXQATfnvuCpt4FicF4QcqCcLj9PQNsSHjCBvVQknWpyaN
- dialogues.py: QmPgpHYgGMvhs11j1mwfMLyBwY8njfMkFNa11JVvyUnb8V
- message.py: QmSwTV913SRq1AcJP6NTwkBRx6JS6Jt89LNJFwHB7dpo6m
- serialization.py: QmYfsDQXv8j3CyQgQqv77CYLfu9WeNFSGgfhhVzLcPbJpj
- tac.proto: QmedPvKHu387gAsdxTDLWgGcCucYXEfCaTiLJbTJPRqDkR
- tac_pb2.py: QmbjMx3iSHq1FY2kGQR4tJfnS1HQiRCQRrnyv7dFUxEi2V
+ dialogues.py: QmTEK2XKfH3wQ728K7ex6zW15vjzmxT93eN147HeFoBPeV
+ message.py: QmW6AYgm62sRfrVXYeduc7BYRm7wWvUUfn3JJWr2awTVZc
+ serialization.py: QmfZMesx1EFVYx1pj5SBn3eF7A2fz5a8cnBKzhBmVha31U
+ tac.proto: QmdpPZNhUW593qVNVoSTWZgd9R69bmBbw6Y9xjzYpvuDvV
+ tac_pb2.py: QmUwW3kixKwD2o1RRdq4NoNoihPb5BXKKRngWXztq32fea
fingerprint_ignore_patterns: []
dependencies:
protobuf: {}
diff --git a/packages/fetchai/protocols/tac/serialization.py b/packages/fetchai/protocols/tac/serialization.py
index 694acb3d5b..d709b5cee0 100644
--- a/packages/fetchai/protocols/tac/serialization.py
+++ b/packages/fetchai/protocols/tac/serialization.py
@@ -59,26 +59,26 @@ def encode(msg: Message) -> bytes:
tac_msg.unregister.CopyFrom(performative)
elif performative_id == TacMessage.Performative.TRANSACTION:
performative = tac_pb2.TacMessage.Transaction_Performative() # type: ignore
- tx_id = msg.tx_id
- performative.tx_id = tx_id
- tx_sender_addr = msg.tx_sender_addr
- performative.tx_sender_addr = tx_sender_addr
- tx_counterparty_addr = msg.tx_counterparty_addr
- performative.tx_counterparty_addr = tx_counterparty_addr
+ transaction_id = msg.transaction_id
+ performative.transaction_id = transaction_id
+ ledger_id = msg.ledger_id
+ performative.ledger_id = ledger_id
+ sender_address = msg.sender_address
+ performative.sender_address = sender_address
+ counterparty_address = msg.counterparty_address
+ performative.counterparty_address = counterparty_address
amount_by_currency_id = msg.amount_by_currency_id
performative.amount_by_currency_id.update(amount_by_currency_id)
- tx_sender_fee = msg.tx_sender_fee
- performative.tx_sender_fee = tx_sender_fee
- tx_counterparty_fee = msg.tx_counterparty_fee
- performative.tx_counterparty_fee = tx_counterparty_fee
+ fee_by_currency_id = msg.fee_by_currency_id
+ performative.fee_by_currency_id.update(fee_by_currency_id)
quantities_by_good_id = msg.quantities_by_good_id
performative.quantities_by_good_id.update(quantities_by_good_id)
- tx_nonce = msg.tx_nonce
- performative.tx_nonce = tx_nonce
- tx_sender_signature = msg.tx_sender_signature
- performative.tx_sender_signature = tx_sender_signature
- tx_counterparty_signature = msg.tx_counterparty_signature
- performative.tx_counterparty_signature = tx_counterparty_signature
+ nonce = msg.nonce
+ performative.nonce = nonce
+ sender_signature = msg.sender_signature
+ performative.sender_signature = sender_signature
+ counterparty_signature = msg.counterparty_signature
+ performative.counterparty_signature = counterparty_signature
tac_msg.transaction.CopyFrom(performative)
elif performative_id == TacMessage.Performative.CANCELLED:
performative = tac_pb2.TacMessage.Cancelled_Performative() # type: ignore
@@ -95,8 +95,8 @@ def encode(msg: Message) -> bytes:
performative.quantities_by_good_id.update(quantities_by_good_id)
utility_params_by_good_id = msg.utility_params_by_good_id
performative.utility_params_by_good_id.update(utility_params_by_good_id)
- tx_fee = msg.tx_fee
- performative.tx_fee = tx_fee
+ fee_by_currency_id = msg.fee_by_currency_id
+ performative.fee_by_currency_id.update(fee_by_currency_id)
agent_addr_to_name = msg.agent_addr_to_name
performative.agent_addr_to_name.update(agent_addr_to_name)
currency_id_to_name = msg.currency_id_to_name
@@ -112,8 +112,8 @@ def encode(msg: Message) -> bytes:
tac_msg.game_data.CopyFrom(performative)
elif performative_id == TacMessage.Performative.TRANSACTION_CONFIRMATION:
performative = tac_pb2.TacMessage.Transaction_Confirmation_Performative() # type: ignore
- tx_id = msg.tx_id
- performative.tx_id = tx_id
+ transaction_id = msg.transaction_id
+ performative.transaction_id = transaction_id
amount_by_currency_id = msg.amount_by_currency_id
performative.amount_by_currency_id.update(amount_by_currency_id)
quantities_by_good_id = msg.quantities_by_good_id
@@ -160,30 +160,29 @@ def decode(obj: bytes) -> Message:
elif performative_id == TacMessage.Performative.UNREGISTER:
pass
elif performative_id == TacMessage.Performative.TRANSACTION:
- tx_id = tac_pb.transaction.tx_id
- performative_content["tx_id"] = tx_id
- tx_sender_addr = tac_pb.transaction.tx_sender_addr
- performative_content["tx_sender_addr"] = tx_sender_addr
- tx_counterparty_addr = tac_pb.transaction.tx_counterparty_addr
- performative_content["tx_counterparty_addr"] = tx_counterparty_addr
+ transaction_id = tac_pb.transaction.transaction_id
+ performative_content["transaction_id"] = transaction_id
+ ledger_id = tac_pb.transaction.ledger_id
+ performative_content["ledger_id"] = ledger_id
+ sender_address = tac_pb.transaction.sender_address
+ performative_content["sender_address"] = sender_address
+ counterparty_address = tac_pb.transaction.counterparty_address
+ performative_content["counterparty_address"] = counterparty_address
amount_by_currency_id = tac_pb.transaction.amount_by_currency_id
amount_by_currency_id_dict = dict(amount_by_currency_id)
performative_content["amount_by_currency_id"] = amount_by_currency_id_dict
- tx_sender_fee = tac_pb.transaction.tx_sender_fee
- performative_content["tx_sender_fee"] = tx_sender_fee
- tx_counterparty_fee = tac_pb.transaction.tx_counterparty_fee
- performative_content["tx_counterparty_fee"] = tx_counterparty_fee
+ fee_by_currency_id = tac_pb.transaction.fee_by_currency_id
+ fee_by_currency_id_dict = dict(fee_by_currency_id)
+ performative_content["fee_by_currency_id"] = fee_by_currency_id_dict
quantities_by_good_id = tac_pb.transaction.quantities_by_good_id
quantities_by_good_id_dict = dict(quantities_by_good_id)
performative_content["quantities_by_good_id"] = quantities_by_good_id_dict
- tx_nonce = tac_pb.transaction.tx_nonce
- performative_content["tx_nonce"] = tx_nonce
- tx_sender_signature = tac_pb.transaction.tx_sender_signature
- performative_content["tx_sender_signature"] = tx_sender_signature
- tx_counterparty_signature = tac_pb.transaction.tx_counterparty_signature
- performative_content[
- "tx_counterparty_signature"
- ] = tx_counterparty_signature
+ nonce = tac_pb.transaction.nonce
+ performative_content["nonce"] = nonce
+ sender_signature = tac_pb.transaction.sender_signature
+ performative_content["sender_signature"] = sender_signature
+ counterparty_signature = tac_pb.transaction.counterparty_signature
+ performative_content["counterparty_signature"] = counterparty_signature
elif performative_id == TacMessage.Performative.CANCELLED:
pass
elif performative_id == TacMessage.Performative.GAME_DATA:
@@ -205,8 +204,9 @@ def decode(obj: bytes) -> Message:
performative_content[
"utility_params_by_good_id"
] = utility_params_by_good_id_dict
- tx_fee = tac_pb.game_data.tx_fee
- performative_content["tx_fee"] = tx_fee
+ fee_by_currency_id = tac_pb.game_data.fee_by_currency_id
+ fee_by_currency_id_dict = dict(fee_by_currency_id)
+ performative_content["fee_by_currency_id"] = fee_by_currency_id_dict
agent_addr_to_name = tac_pb.game_data.agent_addr_to_name
agent_addr_to_name_dict = dict(agent_addr_to_name)
performative_content["agent_addr_to_name"] = agent_addr_to_name_dict
@@ -223,8 +223,8 @@ def decode(obj: bytes) -> Message:
info_dict = dict(info)
performative_content["info"] = info_dict
elif performative_id == TacMessage.Performative.TRANSACTION_CONFIRMATION:
- tx_id = tac_pb.transaction_confirmation.tx_id
- performative_content["tx_id"] = tx_id
+ transaction_id = tac_pb.transaction_confirmation.transaction_id
+ performative_content["transaction_id"] = transaction_id
amount_by_currency_id = (
tac_pb.transaction_confirmation.amount_by_currency_id
)
diff --git a/packages/fetchai/protocols/tac/tac.proto b/packages/fetchai/protocols/tac/tac.proto
index f81404142c..ce16512417 100644
--- a/packages/fetchai/protocols/tac/tac.proto
+++ b/packages/fetchai/protocols/tac/tac.proto
@@ -30,16 +30,16 @@ message TacMessage{
message Unregister_Performative{}
message Transaction_Performative{
- string tx_id = 1;
- string tx_sender_addr = 2;
- string tx_counterparty_addr = 3;
- map amount_by_currency_id = 4;
- int32 tx_sender_fee = 5;
- int32 tx_counterparty_fee = 6;
+ string transaction_id = 1;
+ string ledger_id = 2;
+ string sender_address = 3;
+ string counterparty_address = 4;
+ map amount_by_currency_id = 5;
+ map fee_by_currency_id = 6;
map quantities_by_good_id = 7;
- int32 tx_nonce = 8;
- string tx_sender_signature = 9;
- string tx_counterparty_signature = 10;
+ string nonce = 8;
+ string sender_signature = 9;
+ string counterparty_signature = 10;
}
message Cancelled_Performative{}
@@ -49,7 +49,7 @@ message TacMessage{
map exchange_params_by_currency_id = 2;
map quantities_by_good_id = 3;
map utility_params_by_good_id = 4;
- int32 tx_fee = 5;
+ map fee_by_currency_id = 5;
map agent_addr_to_name = 6;
map currency_id_to_name = 7;
map good_id_to_name = 8;
@@ -59,7 +59,7 @@ message TacMessage{
}
message Transaction_Confirmation_Performative{
- string tx_id = 1;
+ string transaction_id = 1;
map amount_by_currency_id = 2;
map quantities_by_good_id = 3;
}
diff --git a/packages/fetchai/protocols/tac/tac_pb2.py b/packages/fetchai/protocols/tac/tac_pb2.py
index 3e55f37fa7..cedae73bc1 100644
--- a/packages/fetchai/protocols/tac/tac_pb2.py
+++ b/packages/fetchai/protocols/tac/tac_pb2.py
@@ -17,7 +17,7 @@
package="fetch.aea.Tac",
syntax="proto3",
serialized_options=None,
- serialized_pb=b'\n\ttac.proto\x12\rfetch.aea.Tac"\xfe\x1c\n\nTacMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12\x45\n\tcancelled\x18\x05 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Cancelled_PerformativeH\x00\x12\x45\n\tgame_data\x18\x06 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Game_Data_PerformativeH\x00\x12\x43\n\x08register\x18\x07 \x01(\x0b\x32/.fetch.aea.Tac.TacMessage.Register_PerformativeH\x00\x12\x45\n\ttac_error\x18\x08 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Tac_Error_PerformativeH\x00\x12I\n\x0btransaction\x18\t \x01(\x0b\x32\x32.fetch.aea.Tac.TacMessage.Transaction_PerformativeH\x00\x12\x63\n\x18transaction_confirmation\x18\n \x01(\x0b\x32?.fetch.aea.Tac.TacMessage.Transaction_Confirmation_PerformativeH\x00\x12G\n\nunregister\x18\x0b \x01(\x0b\x32\x31.fetch.aea.Tac.TacMessage.Unregister_PerformativeH\x00\x1a\x80\x03\n\tErrorCode\x12\x45\n\nerror_code\x18\x01 \x01(\x0e\x32\x31.fetch.aea.Tac.TacMessage.ErrorCode.ErrorCodeEnum"\xab\x02\n\rErrorCodeEnum\x12\x11\n\rGENERIC_ERROR\x10\x00\x12\x15\n\x11REQUEST_NOT_VALID\x10\x01\x12!\n\x1d\x41GENT_ADDR_ALREADY_REGISTERED\x10\x02\x12!\n\x1d\x41GENT_NAME_ALREADY_REGISTERED\x10\x03\x12\x18\n\x14\x41GENT_NOT_REGISTERED\x10\x04\x12\x19\n\x15TRANSACTION_NOT_VALID\x10\x05\x12\x1c\n\x18TRANSACTION_NOT_MATCHING\x10\x06\x12\x1f\n\x1b\x41GENT_NAME_NOT_IN_WHITELIST\x10\x07\x12\x1b\n\x17\x43OMPETITION_NOT_RUNNING\x10\x08\x12\x19\n\x15\x44IALOGUE_INCONSISTENT\x10\t\x1a+\n\x15Register_Performative\x12\x12\n\nagent_name\x18\x01 \x01(\t\x1a\x19\n\x17Unregister_Performative\x1a\xb1\x04\n\x18Transaction_Performative\x12\r\n\x05tx_id\x18\x01 \x01(\t\x12\x16\n\x0etx_sender_addr\x18\x02 \x01(\t\x12\x1c\n\x14tx_counterparty_addr\x18\x03 \x01(\t\x12i\n\x15\x61mount_by_currency_id\x18\x04 \x03(\x0b\x32J.fetch.aea.Tac.TacMessage.Transaction_Performative.AmountByCurrencyIdEntry\x12\x15\n\rtx_sender_fee\x18\x05 \x01(\x05\x12\x1b\n\x13tx_counterparty_fee\x18\x06 \x01(\x05\x12i\n\x15quantities_by_good_id\x18\x07 \x03(\x0b\x32J.fetch.aea.Tac.TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry\x12\x10\n\x08tx_nonce\x18\x08 \x01(\x05\x12\x1b\n\x13tx_sender_signature\x18\t \x01(\t\x12!\n\x19tx_counterparty_signature\x18\n \x01(\t\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x18\n\x16\x43\x61ncelled_Performative\x1a\xc6\n\n\x16Game_Data_Performative\x12g\n\x15\x61mount_by_currency_id\x18\x01 \x03(\x0b\x32H.fetch.aea.Tac.TacMessage.Game_Data_Performative.AmountByCurrencyIdEntry\x12x\n\x1e\x65xchange_params_by_currency_id\x18\x02 \x03(\x0b\x32P.fetch.aea.Tac.TacMessage.Game_Data_Performative.ExchangeParamsByCurrencyIdEntry\x12g\n\x15quantities_by_good_id\x18\x03 \x03(\x0b\x32H.fetch.aea.Tac.TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry\x12n\n\x19utility_params_by_good_id\x18\x04 \x03(\x0b\x32K.fetch.aea.Tac.TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry\x12\x0e\n\x06tx_fee\x18\x05 \x01(\x05\x12\x61\n\x12\x61gent_addr_to_name\x18\x06 \x03(\x0b\x32\x45.fetch.aea.Tac.TacMessage.Game_Data_Performative.AgentAddrToNameEntry\x12\x63\n\x13\x63urrency_id_to_name\x18\x07 \x03(\x0b\x32\x46.fetch.aea.Tac.TacMessage.Game_Data_Performative.CurrencyIdToNameEntry\x12[\n\x0fgood_id_to_name\x18\x08 \x03(\x0b\x32\x42.fetch.aea.Tac.TacMessage.Game_Data_Performative.GoodIdToNameEntry\x12\x12\n\nversion_id\x18\t \x01(\t\x12H\n\x04info\x18\n \x03(\x0b\x32:.fetch.aea.Tac.TacMessage.Game_Data_Performative.InfoEntry\x12\x13\n\x0binfo_is_set\x18\x0b \x01(\x08\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x41\n\x1f\x45xchangeParamsByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a<\n\x1aUtilityParamsByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x36\n\x14\x41gentAddrToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x37\n\x15\x43urrencyIdToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11GoodIdToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a+\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x9c\x03\n%Transaction_Confirmation_Performative\x12\r\n\x05tx_id\x18\x01 \x01(\t\x12v\n\x15\x61mount_by_currency_id\x18\x02 \x03(\x0b\x32W.fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.AmountByCurrencyIdEntry\x12v\n\x15quantities_by_good_id\x18\x03 \x03(\x0b\x32W.fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.QuantitiesByGoodIdEntry\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\xdd\x01\n\x16Tac_Error_Performative\x12\x37\n\nerror_code\x18\x01 \x01(\x0b\x32#.fetch.aea.Tac.TacMessage.ErrorCode\x12H\n\x04info\x18\x02 \x03(\x0b\x32:.fetch.aea.Tac.TacMessage.Tac_Error_Performative.InfoEntry\x12\x13\n\x0binfo_is_set\x18\x03 \x01(\x08\x1a+\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0e\n\x0cperformativeb\x06proto3',
+ serialized_pb=b'\n\ttac.proto\x12\rfetch.aea.Tac"\x8e\x1f\n\nTacMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12\x45\n\tcancelled\x18\x05 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Cancelled_PerformativeH\x00\x12\x45\n\tgame_data\x18\x06 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Game_Data_PerformativeH\x00\x12\x43\n\x08register\x18\x07 \x01(\x0b\x32/.fetch.aea.Tac.TacMessage.Register_PerformativeH\x00\x12\x45\n\ttac_error\x18\x08 \x01(\x0b\x32\x30.fetch.aea.Tac.TacMessage.Tac_Error_PerformativeH\x00\x12I\n\x0btransaction\x18\t \x01(\x0b\x32\x32.fetch.aea.Tac.TacMessage.Transaction_PerformativeH\x00\x12\x63\n\x18transaction_confirmation\x18\n \x01(\x0b\x32?.fetch.aea.Tac.TacMessage.Transaction_Confirmation_PerformativeH\x00\x12G\n\nunregister\x18\x0b \x01(\x0b\x32\x31.fetch.aea.Tac.TacMessage.Unregister_PerformativeH\x00\x1a\x80\x03\n\tErrorCode\x12\x45\n\nerror_code\x18\x01 \x01(\x0e\x32\x31.fetch.aea.Tac.TacMessage.ErrorCode.ErrorCodeEnum"\xab\x02\n\rErrorCodeEnum\x12\x11\n\rGENERIC_ERROR\x10\x00\x12\x15\n\x11REQUEST_NOT_VALID\x10\x01\x12!\n\x1d\x41GENT_ADDR_ALREADY_REGISTERED\x10\x02\x12!\n\x1d\x41GENT_NAME_ALREADY_REGISTERED\x10\x03\x12\x18\n\x14\x41GENT_NOT_REGISTERED\x10\x04\x12\x19\n\x15TRANSACTION_NOT_VALID\x10\x05\x12\x1c\n\x18TRANSACTION_NOT_MATCHING\x10\x06\x12\x1f\n\x1b\x41GENT_NAME_NOT_IN_WHITELIST\x10\x07\x12\x1b\n\x17\x43OMPETITION_NOT_RUNNING\x10\x08\x12\x19\n\x15\x44IALOGUE_INCONSISTENT\x10\t\x1a+\n\x15Register_Performative\x12\x12\n\nagent_name\x18\x01 \x01(\t\x1a\x19\n\x17Unregister_Performative\x1a\xad\x05\n\x18Transaction_Performative\x12\x16\n\x0etransaction_id\x18\x01 \x01(\t\x12\x11\n\tledger_id\x18\x02 \x01(\t\x12\x16\n\x0esender_address\x18\x03 \x01(\t\x12\x1c\n\x14\x63ounterparty_address\x18\x04 \x01(\t\x12i\n\x15\x61mount_by_currency_id\x18\x05 \x03(\x0b\x32J.fetch.aea.Tac.TacMessage.Transaction_Performative.AmountByCurrencyIdEntry\x12\x63\n\x12\x66\x65\x65_by_currency_id\x18\x06 \x03(\x0b\x32G.fetch.aea.Tac.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry\x12i\n\x15quantities_by_good_id\x18\x07 \x03(\x0b\x32J.fetch.aea.Tac.TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry\x12\r\n\x05nonce\x18\x08 \x01(\t\x12\x18\n\x10sender_signature\x18\t \x01(\t\x12\x1e\n\x16\x63ounterparty_signature\x18\n \x01(\t\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x36\n\x14\x46\x65\x65\x42yCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x18\n\x16\x43\x61ncelled_Performative\x1a\xd1\x0b\n\x16Game_Data_Performative\x12g\n\x15\x61mount_by_currency_id\x18\x01 \x03(\x0b\x32H.fetch.aea.Tac.TacMessage.Game_Data_Performative.AmountByCurrencyIdEntry\x12x\n\x1e\x65xchange_params_by_currency_id\x18\x02 \x03(\x0b\x32P.fetch.aea.Tac.TacMessage.Game_Data_Performative.ExchangeParamsByCurrencyIdEntry\x12g\n\x15quantities_by_good_id\x18\x03 \x03(\x0b\x32H.fetch.aea.Tac.TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry\x12n\n\x19utility_params_by_good_id\x18\x04 \x03(\x0b\x32K.fetch.aea.Tac.TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry\x12\x61\n\x12\x66\x65\x65_by_currency_id\x18\x05 \x03(\x0b\x32\x45.fetch.aea.Tac.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry\x12\x61\n\x12\x61gent_addr_to_name\x18\x06 \x03(\x0b\x32\x45.fetch.aea.Tac.TacMessage.Game_Data_Performative.AgentAddrToNameEntry\x12\x63\n\x13\x63urrency_id_to_name\x18\x07 \x03(\x0b\x32\x46.fetch.aea.Tac.TacMessage.Game_Data_Performative.CurrencyIdToNameEntry\x12[\n\x0fgood_id_to_name\x18\x08 \x03(\x0b\x32\x42.fetch.aea.Tac.TacMessage.Game_Data_Performative.GoodIdToNameEntry\x12\x12\n\nversion_id\x18\t \x01(\t\x12H\n\x04info\x18\n \x03(\x0b\x32:.fetch.aea.Tac.TacMessage.Game_Data_Performative.InfoEntry\x12\x13\n\x0binfo_is_set\x18\x0b \x01(\x08\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x41\n\x1f\x45xchangeParamsByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a<\n\x1aUtilityParamsByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x36\n\x14\x46\x65\x65\x42yCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x36\n\x14\x41gentAddrToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x37\n\x15\x43urrencyIdToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11GoodIdToNameEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a+\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xa5\x03\n%Transaction_Confirmation_Performative\x12\x16\n\x0etransaction_id\x18\x01 \x01(\t\x12v\n\x15\x61mount_by_currency_id\x18\x02 \x03(\x0b\x32W.fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.AmountByCurrencyIdEntry\x12v\n\x15quantities_by_good_id\x18\x03 \x03(\x0b\x32W.fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.QuantitiesByGoodIdEntry\x1a\x39\n\x17\x41mountByCurrencyIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x39\n\x17QuantitiesByGoodIdEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\xdd\x01\n\x16Tac_Error_Performative\x12\x37\n\nerror_code\x18\x01 \x01(\x0b\x32#.fetch.aea.Tac.TacMessage.ErrorCode\x12H\n\x04info\x18\x02 \x03(\x0b\x32:.fetch.aea.Tac.TacMessage.Tac_Error_Performative.InfoEntry\x12\x13\n\x0binfo_is_set\x18\x03 \x01(\x08\x1a+\n\tInfoEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0e\n\x0cperformativeb\x06proto3',
)
@@ -249,8 +249,64 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1589,
- serialized_end=1646,
+ serialized_start=1657,
+ serialized_end=1714,
+)
+
+_TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY = _descriptor.Descriptor(
+ name="FeeByCurrencyIdEntry",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=1716,
+ serialized_end=1770,
)
_TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = _descriptor.Descriptor(
@@ -305,8 +361,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1648,
- serialized_end=1705,
+ serialized_start=1772,
+ serialized_end=1829,
)
_TACMESSAGE_TRANSACTION_PERFORMATIVE = _descriptor.Descriptor(
@@ -317,8 +373,8 @@
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name="tx_id",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_id",
+ name="transaction_id",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.transaction_id",
index=0,
number=1,
type=9,
@@ -335,8 +391,8 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_sender_addr",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_sender_addr",
+ name="ledger_id",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.ledger_id",
index=1,
number=2,
type=9,
@@ -353,8 +409,8 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_counterparty_addr",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_counterparty_addr",
+ name="sender_address",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.sender_address",
index=2,
number=3,
type=9,
@@ -371,15 +427,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="amount_by_currency_id",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.amount_by_currency_id",
+ name="counterparty_address",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.counterparty_address",
index=3,
number=4,
- type=11,
- cpp_type=10,
- label=3,
+ type=9,
+ cpp_type=9,
+ label=1,
has_default_value=False,
- default_value=[],
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -389,15 +445,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_sender_fee",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_sender_fee",
+ name="amount_by_currency_id",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.amount_by_currency_id",
index=4,
number=5,
- type=5,
- cpp_type=1,
- label=1,
+ type=11,
+ cpp_type=10,
+ label=3,
has_default_value=False,
- default_value=0,
+ default_value=[],
message_type=None,
enum_type=None,
containing_type=None,
@@ -407,15 +463,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_counterparty_fee",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_counterparty_fee",
+ name="fee_by_currency_id",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.fee_by_currency_id",
index=5,
number=6,
- type=5,
- cpp_type=1,
- label=1,
+ type=11,
+ cpp_type=10,
+ label=3,
has_default_value=False,
- default_value=0,
+ default_value=[],
message_type=None,
enum_type=None,
containing_type=None,
@@ -443,15 +499,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_nonce",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_nonce",
+ name="nonce",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.nonce",
index=7,
number=8,
- type=5,
- cpp_type=1,
+ type=9,
+ cpp_type=9,
label=1,
has_default_value=False,
- default_value=0,
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -461,8 +517,8 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_sender_signature",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_sender_signature",
+ name="sender_signature",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.sender_signature",
index=8,
number=9,
type=9,
@@ -479,8 +535,8 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_counterparty_signature",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.tx_counterparty_signature",
+ name="counterparty_signature",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Performative.counterparty_signature",
index=9,
number=10,
type=9,
@@ -500,6 +556,7 @@
extensions=[],
nested_types=[
_TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY,
+ _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY,
_TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,
],
enum_types=[],
@@ -509,7 +566,7 @@
extension_ranges=[],
oneofs=[],
serialized_start=1144,
- serialized_end=1705,
+ serialized_end=1829,
)
_TACMESSAGE_CANCELLED_PERFORMATIVE = _descriptor.Descriptor(
@@ -527,8 +584,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1707,
- serialized_end=1731,
+ serialized_start=1831,
+ serialized_end=1855,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = _descriptor.Descriptor(
@@ -583,8 +640,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1589,
- serialized_end=1646,
+ serialized_start=1657,
+ serialized_end=1714,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY = _descriptor.Descriptor(
@@ -639,8 +696,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2687,
- serialized_end=2752,
+ serialized_start=2894,
+ serialized_end=2959,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = _descriptor.Descriptor(
@@ -695,8 +752,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1648,
- serialized_end=1705,
+ serialized_start=1772,
+ serialized_end=1829,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY = _descriptor.Descriptor(
@@ -751,8 +808,64 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2813,
- serialized_end=2873,
+ serialized_start=3020,
+ serialized_end=3080,
+)
+
+_TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY = _descriptor.Descriptor(
+ name="FeeByCurrencyIdEntry",
+ full_name="fetch.aea.Tac.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.Tac.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.Tac.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=1716,
+ serialized_end=1770,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY = _descriptor.Descriptor(
@@ -807,8 +920,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2875,
- serialized_end=2929,
+ serialized_start=3138,
+ serialized_end=3192,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY = _descriptor.Descriptor(
@@ -863,8 +976,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2931,
- serialized_end=2986,
+ serialized_start=3194,
+ serialized_end=3249,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY = _descriptor.Descriptor(
@@ -919,8 +1032,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2988,
- serialized_end=3039,
+ serialized_start=3251,
+ serialized_end=3302,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_INFOENTRY = _descriptor.Descriptor(
@@ -975,8 +1088,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3041,
- serialized_end=3084,
+ serialized_start=3304,
+ serialized_end=3347,
)
_TACMESSAGE_GAME_DATA_PERFORMATIVE = _descriptor.Descriptor(
@@ -1059,15 +1172,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="tx_fee",
- full_name="fetch.aea.Tac.TacMessage.Game_Data_Performative.tx_fee",
+ name="fee_by_currency_id",
+ full_name="fetch.aea.Tac.TacMessage.Game_Data_Performative.fee_by_currency_id",
index=4,
number=5,
- type=5,
- cpp_type=1,
- label=1,
+ type=11,
+ cpp_type=10,
+ label=3,
has_default_value=False,
- default_value=0,
+ default_value=[],
message_type=None,
enum_type=None,
containing_type=None,
@@ -1191,6 +1304,7 @@
_TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY,
_TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY,
_TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY,
+ _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY,
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY,
_TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY,
_TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY,
@@ -1202,8 +1316,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1734,
- serialized_end=3084,
+ serialized_start=1858,
+ serialized_end=3347,
)
_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY = _descriptor.Descriptor(
@@ -1258,8 +1372,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1589,
- serialized_end=1646,
+ serialized_start=1657,
+ serialized_end=1714,
)
_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY = _descriptor.Descriptor(
@@ -1314,8 +1428,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1648,
- serialized_end=1705,
+ serialized_start=1772,
+ serialized_end=1829,
)
_TACMESSAGE_TRANSACTION_CONFIRMATION_PERFORMATIVE = _descriptor.Descriptor(
@@ -1326,8 +1440,8 @@
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name="tx_id",
- full_name="fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.tx_id",
+ name="transaction_id",
+ full_name="fetch.aea.Tac.TacMessage.Transaction_Confirmation_Performative.transaction_id",
index=0,
number=1,
type=9,
@@ -1391,8 +1505,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3087,
- serialized_end=3499,
+ serialized_start=3350,
+ serialized_end=3771,
)
_TACMESSAGE_TAC_ERROR_PERFORMATIVE_INFOENTRY = _descriptor.Descriptor(
@@ -1447,8 +1561,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3041,
- serialized_end=3084,
+ serialized_start=3304,
+ serialized_end=3347,
)
_TACMESSAGE_TAC_ERROR_PERFORMATIVE = _descriptor.Descriptor(
@@ -1521,8 +1635,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3502,
- serialized_end=3723,
+ serialized_start=3774,
+ serialized_end=3995,
)
_TACMESSAGE = _descriptor.Descriptor(
@@ -1757,7 +1871,7 @@
),
],
serialized_start=29,
- serialized_end=3739,
+ serialized_end=4011,
)
_TACMESSAGE_ERRORCODE.fields_by_name[
@@ -1770,12 +1884,18 @@
_TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY.containing_type = (
_TACMESSAGE_TRANSACTION_PERFORMATIVE
)
+_TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY.containing_type = (
+ _TACMESSAGE_TRANSACTION_PERFORMATIVE
+)
_TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY.containing_type = (
_TACMESSAGE_TRANSACTION_PERFORMATIVE
)
_TACMESSAGE_TRANSACTION_PERFORMATIVE.fields_by_name[
"amount_by_currency_id"
].message_type = _TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY
+_TACMESSAGE_TRANSACTION_PERFORMATIVE.fields_by_name[
+ "fee_by_currency_id"
+].message_type = _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY
_TACMESSAGE_TRANSACTION_PERFORMATIVE.fields_by_name[
"quantities_by_good_id"
].message_type = _TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY
@@ -1793,6 +1913,9 @@
_TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY.containing_type = (
_TACMESSAGE_GAME_DATA_PERFORMATIVE
)
+_TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY.containing_type = (
+ _TACMESSAGE_GAME_DATA_PERFORMATIVE
+)
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY.containing_type = (
_TACMESSAGE_GAME_DATA_PERFORMATIVE
)
@@ -1817,6 +1940,9 @@
_TACMESSAGE_GAME_DATA_PERFORMATIVE.fields_by_name[
"utility_params_by_good_id"
].message_type = _TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY
+_TACMESSAGE_GAME_DATA_PERFORMATIVE.fields_by_name[
+ "fee_by_currency_id"
+].message_type = _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY
_TACMESSAGE_GAME_DATA_PERFORMATIVE.fields_by_name[
"agent_addr_to_name"
].message_type = _TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY
@@ -1965,6 +2091,15 @@
# @@protoc_insertion_point(class_scope:fetch.aea.Tac.TacMessage.Transaction_Performative.AmountByCurrencyIdEntry)
},
),
+ "FeeByCurrencyIdEntry": _reflection.GeneratedProtocolMessageType(
+ "FeeByCurrencyIdEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY,
+ "__module__": "tac_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.Tac.TacMessage.Transaction_Performative.FeeByCurrencyIdEntry)
+ },
+ ),
"QuantitiesByGoodIdEntry": _reflection.GeneratedProtocolMessageType(
"QuantitiesByGoodIdEntry",
(_message.Message,),
@@ -2028,6 +2163,15 @@
# @@protoc_insertion_point(class_scope:fetch.aea.Tac.TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry)
},
),
+ "FeeByCurrencyIdEntry": _reflection.GeneratedProtocolMessageType(
+ "FeeByCurrencyIdEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY,
+ "__module__": "tac_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.Tac.TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry)
+ },
+ ),
"AgentAddrToNameEntry": _reflection.GeneratedProtocolMessageType(
"AgentAddrToNameEntry",
(_message.Message,),
@@ -2125,6 +2269,7 @@
_sym_db.RegisterMessage(TacMessage.Unregister_Performative)
_sym_db.RegisterMessage(TacMessage.Transaction_Performative)
_sym_db.RegisterMessage(TacMessage.Transaction_Performative.AmountByCurrencyIdEntry)
+_sym_db.RegisterMessage(TacMessage.Transaction_Performative.FeeByCurrencyIdEntry)
_sym_db.RegisterMessage(TacMessage.Transaction_Performative.QuantitiesByGoodIdEntry)
_sym_db.RegisterMessage(TacMessage.Cancelled_Performative)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative)
@@ -2134,6 +2279,7 @@
)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.QuantitiesByGoodIdEntry)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.UtilityParamsByGoodIdEntry)
+_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.FeeByCurrencyIdEntry)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.AgentAddrToNameEntry)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.CurrencyIdToNameEntry)
_sym_db.RegisterMessage(TacMessage.Game_Data_Performative.GoodIdToNameEntry)
@@ -2150,11 +2296,13 @@
_TACMESSAGE_TRANSACTION_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None
+_TACMESSAGE_TRANSACTION_PERFORMATIVE_FEEBYCURRENCYIDENTRY._options = None
_TACMESSAGE_TRANSACTION_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AMOUNTBYCURRENCYIDENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_EXCHANGEPARAMSBYCURRENCYIDENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_QUANTITIESBYGOODIDENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_UTILITYPARAMSBYGOODIDENTRY._options = None
+_TACMESSAGE_GAME_DATA_PERFORMATIVE_FEEBYCURRENCYIDENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_AGENTADDRTONAMEENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_CURRENCYIDTONAMEENTRY._options = None
_TACMESSAGE_GAME_DATA_PERFORMATIVE_GOODIDTONAMEENTRY._options = None
diff --git a/packages/fetchai/skills/aries_alice/behaviours.py b/packages/fetchai/skills/aries_alice/behaviours.py
new file mode 100644
index 0000000000..20d7c19e89
--- /dev/null
+++ b/packages/fetchai/skills/aries_alice/behaviours.py
@@ -0,0 +1,185 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 package contains the behaviour of a generic seller AEA."""
+
+from typing import cast
+
+from aea.skills.behaviours import TickerBehaviour
+
+from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from packages.fetchai.skills.aries_alice.dialogues import OefSearchDialogues
+from packages.fetchai.skills.aries_alice.strategy import AliceStrategy
+
+DEFAULT_ADMIN_HOST = "127.0.0.1"
+DEFAULT_ADMIN_PORT = 8031
+
+DEFAULT_SERVICES_INTERVAL = 60.0
+
+
+class AliceBehaviour(TickerBehaviour):
+ """This class implements a behaviour."""
+
+ def __init__(self, **kwargs):
+ """Initialise the behaviour."""
+ self._admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
+ self._admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
+ self._admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
+
+ services_interval = kwargs.pop(
+ "services_interval", DEFAULT_SERVICES_INTERVAL
+ ) # type: int
+ super().__init__(tick_interval=services_interval, **kwargs)
+
+ @property
+ def admin_host(self) -> str:
+ """Get the admin host."""
+ return self._admin_host
+
+ @property
+ def admin_port(self) -> str:
+ """Get the admin port."""
+ return self._admin_port
+
+ @property
+ def admin_url(self) -> str:
+ """Get the admin URL."""
+ return self._admin_url
+
+ def setup(self) -> None:
+ """
+ Implement the setup.
+
+ :return: None
+ """
+ self.context.logger.info("My address is: " + self.context.agent_address)
+ self._register_agent()
+ self._register_service()
+
+ def act(self) -> None:
+ """
+ Implement the act.
+
+ :return: None
+ """
+
+ def teardown(self) -> None:
+ """
+ Implement the task teardown.
+
+ :return: None
+ """
+ self._unregister_service()
+ self._unregister_agent()
+
+ def _register_agent(self) -> None:
+ """
+ Register the agent's location.
+
+ :return: None
+ """
+ strategy = cast(AliceStrategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert (
+ oef_dialogue is not None
+ ), "alice -> behaviour -> _register_agent(): something went wrong when registering Alice on SOEF."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering Alice on SOEF.")
+
+ def _register_service(self) -> None:
+ """
+ Register the agent's service.
+
+ :return: None
+ """
+ strategy = cast(AliceStrategy, self.context.strategy)
+ description = strategy.get_register_service_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert (
+ oef_dialogue is not None
+ ), "alice -> behaviour -> _register_service(): something went wrong when registering Alice service on SOEF."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering Alice service on SOEF.")
+
+ def _unregister_service(self) -> None:
+ """
+ Unregister service from the SOEF.
+
+ :return: None
+ """
+ strategy = cast(AliceStrategy, self.context.strategy)
+ description = strategy.get_unregister_service_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert (
+ oef_dialogue is not None
+ ), "alice -> behaviour -> _unregister_service(): something went wrong when unregistering Alice service on SOEF."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("unregistering service from SOEF.")
+
+ def _unregister_agent(self) -> None:
+ """
+ Unregister agent from the SOEF.
+
+ :return: None
+ """
+ strategy = cast(AliceStrategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert (
+ oef_dialogue is not None
+ ), "alice -> behaviour -> _unregister_agent(): something went wrong when unregistering Alice on SOEF."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("unregistering agent from SOEF.")
diff --git a/packages/fetchai/skills/aries_alice/dialogues.py b/packages/fetchai/skills/aries_alice/dialogues.py
new file mode 100644
index 0000000000..205d233abc
--- /dev/null
+++ b/packages/fetchai/skills/aries_alice/dialogues.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 classes required for dialogue management.
+
+- Dialogue: The dialogue class maintains state of a dialogue and manages it.
+- Dialogues: The dialogues class keeps track of all dialogues.
+"""
+
+from aea.helpers.dialogue.base import Dialogue as BaseDialogue
+from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
+from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.skills.base import Model
+
+from packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue
+from packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue as BaseOefSearchDialogue,
+)
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogues as BaseOefSearchDialogues,
+)
+
+DefaultDialogue = BaseDefaultDialogue
+
+
+class DefaultDialogues(Model, BaseDefaultDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+HttpDialogue = BaseHttpDialogue
+
+
+class HttpDialogues(Model, BaseHttpDialogues):
+ """This class keeps track of all http dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseHttpDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseHttpDialogue.Role.CLIENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> HttpDialogue:
+ """
+ Create an instance of http dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = HttpDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+OefSearchDialogue = BaseOefSearchDialogue
+
+
+class OefSearchDialogues(Model, BaseOefSearchDialogues):
+ """This class keeps track of all oef_search dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseOefSearchDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseOefSearchDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> OefSearchDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = OefSearchDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/packages/fetchai/skills/aries_alice/handlers.py b/packages/fetchai/skills/aries_alice/handlers.py
index bb18596001..46cf0a3728 100644
--- a/packages/fetchai/skills/aries_alice/handlers.py
+++ b/packages/fetchai/skills/aries_alice/handlers.py
@@ -32,32 +32,41 @@
PUBLIC_ID as HTTP_CLIENT_CONNECTION_PUBLIC_ID,
)
from packages.fetchai.protocols.http.message import HttpMessage
-
-DEFAULT_ADMIN_HOST = "127.0.0.1"
-DEFAULT_ADMIN_PORT = 8031
+from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from packages.fetchai.skills.aries_alice.dialogues import (
+ DefaultDialogue,
+ DefaultDialogues,
+ HttpDialogue,
+ HttpDialogues,
+ OefSearchDialogue,
+ OefSearchDialogues,
+)
ADMIN_COMMAND_RECEIVE_INVITE = "/connections/receive-invitation"
+HTTP_COUNTERPARTY = "HTTP Server"
-class DefaultHandler(Handler):
+class AliceDefaultHandler(Handler):
"""This class represents alice's handler for default messages."""
SUPPORTED_PROTOCOL = DefaultMessage.protocol_id # type: Optional[ProtocolId]
def __init__(self, **kwargs):
"""Initialize the handler."""
- self.admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
- self.admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
-
super().__init__(**kwargs)
- self.admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
-
self.handled_message = None
+ @property
+ def admin_url(self) -> str:
+ """Get the admin URL."""
+ return self.context.behaviours.alice.admin_url
+
def _admin_post(self, path: str, content: Dict = None):
# Request message & envelope
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
request_http_message = HttpMessage(
+ dialogue_reference=http_dialogues.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="POST",
url=self.admin_url + path,
@@ -65,7 +74,11 @@ def _admin_post(self, path: str, content: Dict = None):
version="",
bodyy=b"" if content is None else json.dumps(content).encode("utf-8"),
)
- request_http_message.counterparty = self.admin_url
+ request_http_message.counterparty = HTTP_COUNTERPARTY
+ http_dialogue = http_dialogues.update(request_http_message)
+ assert (
+ http_dialogue is not None
+ ), "alice -> default_handler -> _admin_post(): something went wrong when sending a HTTP message."
self.context.outbox.put_message(
message=request_http_message,
context=EnvelopeContext(connection_id=HTTP_CLIENT_CONNECTION_PUBLIC_ID),
@@ -87,8 +100,18 @@ def handle(self, message: Message) -> None:
:return: None
"""
message = cast(DefaultMessage, message)
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
+
self.handled_message = message
if message.performative == DefaultMessage.Performative.BYTES:
+ http_dialogue = cast(
+ Optional[DefaultDialogue], default_dialogues.update(message)
+ )
+ if http_dialogue is None:
+ self.context.logger.exception(
+ "alice -> default_handler -> handle(): something went wrong when adding the incoming HTTP response message to the dialogue."
+ )
+ return
content_bytes = message.content
content = json.loads(content_bytes)
self.context.logger.info("Received message content:" + str(content))
@@ -104,19 +127,15 @@ def teardown(self) -> None:
pass
-class HttpHandler(Handler):
+class AliceHttpHandler(Handler):
"""This class represents alice's handler for HTTP messages."""
SUPPORTED_PROTOCOL = HttpMessage.protocol_id # type: Optional[ProtocolId]
def __init__(self, **kwargs):
"""Initialize the handler."""
- self.admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
- self.admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
-
super().__init__(**kwargs)
- self.admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
self.connection_id = None # type: Optional[str]
self.is_connected_to_Faber = False
@@ -128,7 +147,7 @@ def setup(self) -> None:
:return: None
"""
- self.context.logger.info("My address is: " + self.context.agent_address)
+ pass
def handle(self, message: Message) -> None:
"""
@@ -138,8 +157,16 @@ def handle(self, message: Message) -> None:
:return: None
"""
message = cast(HttpMessage, message)
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
+
self.handled_message = message
if message.performative == HttpMessage.Performative.REQUEST: # webhook
+ http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))
+ if http_dialogue is None:
+ self.context.logger.exception(
+ "alice -> http_handler -> handle() -> REQUEST: something went wrong when adding the incoming HTTP webhook request message to the dialogue."
+ )
+ return
content_bytes = message.bodyy
content = json.loads(content_bytes)
self.context.logger.info("Received webhook message content:" + str(content))
@@ -151,6 +178,12 @@ def handle(self, message: Message) -> None:
elif (
message.performative == HttpMessage.Performative.RESPONSE
): # response to http_client request
+ http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))
+ if http_dialogue is None:
+ self.context.logger.exception(
+ "alice -> http_handler -> handle() -> RESPONSE: something went wrong when adding the incoming HTTP response message to the dialogue."
+ )
+ return
content_bytes = message.bodyy
content = content_bytes.decode("utf-8")
if "Error" in content:
@@ -176,3 +209,91 @@ def teardown(self) -> None:
:return: None
"""
pass
+
+
+class AliceOefSearchHandler(Handler):
+ """This class implements an OEF search handler."""
+
+ SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[ProtocolId]
+
+ def setup(self) -> None:
+ """Call to setup the handler."""
+ pass
+
+ def handle(self, message: Message) -> None:
+ """
+ Implement the reaction to a message.
+
+ :param message: the message
+ :return: None
+ """
+ oef_search_msg = cast(OefSearchMessage, message)
+
+ # recover dialogue
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)
+ )
+ if oef_search_dialogue is None:
+ self._handle_unidentified_dialogue(oef_search_msg)
+ return
+
+ # handle message
+ if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:
+ self._handle_error(oef_search_msg, oef_search_dialogue)
+ else:
+ self._handle_invalid(oef_search_msg, oef_search_dialogue)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
+
+ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param oef_search_msg: the oef search message
+ """
+ self.context.logger.info(
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
+ )
+ )
+
+ def _handle_error(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.info(
+ "received oef_search error message={} in dialogue={}.".format(
+ oef_search_msg, oef_search_dialogue
+ )
+ )
+
+ def _handle_invalid(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
+ )
+ )
diff --git a/packages/fetchai/skills/aries_alice/skill.yaml b/packages/fetchai/skills/aries_alice/skill.yaml
index 6913515f95..c3598ac6f5 100644
--- a/packages/fetchai/skills/aries_alice/skill.yaml
+++ b/packages/fetchai/skills/aries_alice/skill.yaml
@@ -1,30 +1,56 @@
name: aries_alice
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The aries_alice skill implements the alice player in the aries cloud
agent demo
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: Qma8qSTU34ADKWskBwQKQLGNpe3xDKNgjNQ6Q4MxUnKa3Q
- handlers.py: Qmf27rceAx3bwYjm1UXTXHnXratBPz9JwmLb5emqpruqyi
+ behaviours.py: QmZ1hadywhjNUxw56R3r5ZoiZwvoK6EyzGPVHRVtRYXaQ4
+ dialogues.py: QmdPR5nNYj4JJdR9Stfis97M8XfP2pi2KqsVsApUzhD9hH
+ handlers.py: QmVVjSsPPSLTH6gTDSYKqtFn13YdVfhnL9fJnqKEJ6j92M
+ strategy.py: QmPXzDbERHva7wu3yL787JBVWVPxb1RR4VHR16S8GEaJg5
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/http:0.3.0
+- fetchai/default:0.4.0
+- fetchai/http:0.4.0
skills: []
-behaviours: {}
-handlers:
- aries_demo_default:
+behaviours:
+ alice:
args:
admin_host: 127.0.0.1
admin_port: 8031
- class_name: DefaultHandler
- aries_demo_http:
+ services_interval: 20
+ class_name: AliceBehaviour
+handlers:
+ default:
+ args: {}
+ class_name: AliceDefaultHandler
+ http:
+ args: {}
+ class_name: AliceHttpHandler
+ oef_search:
+ args: {}
+ class_name: AliceOefSearchHandler
+models:
+ default_dialogues:
+ args: {}
+ class_name: DefaultDialogues
+ http_dialogues:
+ args: {}
+ class_name: HttpDialogues
+ oef_search_dialogues:
+ args: {}
+ class_name: OefSearchDialogues
+ strategy:
args:
- admin_host: 127.0.0.1
- admin_port: 8031
- class_name: HttpHandler
-models: {}
+ location:
+ latitude: 0.127
+ longitude: 51.5194
+ service_data:
+ key: intro_service
+ value: intro_alice
+ class_name: AliceStrategy
dependencies: {}
diff --git a/packages/fetchai/skills/aries_alice/strategy.py b/packages/fetchai/skills/aries_alice/strategy.py
new file mode 100644
index 0000000000..1d3c373ef2
--- /dev/null
+++ b/packages/fetchai/skills/aries_alice/strategy.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 strategy class."""
+
+from aea.helpers.search.generic import (
+ AGENT_LOCATION_MODEL,
+ AGENT_REMOVE_SERVICE_MODEL,
+ AGENT_SET_SERVICE_MODEL,
+)
+from aea.helpers.search.models import Description, Location
+from aea.skills.base import Model
+
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SERVICE_DATA = {"key": "intro_service", "value": "intro_alice"}
+
+
+class AliceStrategy(Model):
+ """This class defines a strategy for the agent."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize the strategy of the agent.
+
+ :param register_as: determines whether the agent registers as seller, buyer or both
+ :param search_for: determines whether the agent searches for sellers, buyers or both
+
+ :return: None
+ """
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = {
+ "location": Location(location["longitude"], location["latitude"])
+ }
+ self._set_service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA)
+ assert (
+ len(self._set_service_data) == 2
+ and "key" in self._set_service_data
+ and "value" in self._set_service_data
+ ), "service_data must contain keys `key` and `value`"
+ self._remove_service_data = {"key": self._set_service_data["key"]}
+
+ super().__init__(**kwargs)
+
+ def get_location_description(self) -> Description:
+ """
+ Get the location description.
+
+ :return: a description of the agent's location
+ """
+ description = Description(
+ self._agent_location, data_model=AGENT_LOCATION_MODEL,
+ )
+ return description
+
+ def get_register_service_description(self) -> Description:
+ """
+ Get the register service description.
+
+ :return: a description of the offered services
+ """
+ description = Description(
+ self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL,
+ )
+ return description
+
+ def get_unregister_service_description(self) -> Description:
+ """
+ Get the unregister service description.
+
+ :return: a description of the to be removed service
+ """
+ description = Description(
+ self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL,
+ )
+ return description
diff --git a/packages/fetchai/skills/aries_faber/__init__.py b/packages/fetchai/skills/aries_faber/__init__.py
index 6e2baadb91..9113cb0cf5 100644
--- a/packages/fetchai/skills/aries_faber/__init__.py
+++ b/packages/fetchai/skills/aries_faber/__init__.py
@@ -17,4 +17,4 @@
#
# ------------------------------------------------------------------------------
-"""This module contains the implementation of the aries_alice skill."""
+"""This module contains the implementation of the aries_faber skill."""
diff --git a/packages/fetchai/skills/aries_faber/behaviours.py b/packages/fetchai/skills/aries_faber/behaviours.py
index 28d347f719..bf26ba3299 100644
--- a/packages/fetchai/skills/aries_faber/behaviours.py
+++ b/packages/fetchai/skills/aries_faber/behaviours.py
@@ -20,31 +20,66 @@
"""This package contains the behaviour for the aries_faber skill."""
import json
-from typing import Dict
+from typing import Dict, cast
-from aea.skills.behaviours import OneShotBehaviour
+from aea.mail.base import Address
+from aea.skills.behaviours import TickerBehaviour
from packages.fetchai.protocols.http.message import HttpMessage
+from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from packages.fetchai.skills.aries_faber.dialogues import (
+ HttpDialogues,
+ OefSearchDialogues,
+)
+from packages.fetchai.skills.aries_faber.strategy import FaberStrategy
DEFAULT_ADMIN_HOST = "127.0.0.1"
DEFAULT_ADMIN_PORT = 8021
+HTTP_COUNTERPARTY = "HTTP Server"
-ADMIN_COMMAND_STATUS = "/status"
+DEFAULT_SEARCH_INTERVAL = 5.0
-class FaberBehaviour(OneShotBehaviour):
+class FaberBehaviour(TickerBehaviour):
"""This class represents the behaviour of faber."""
def __init__(self, **kwargs):
"""Initialize the handler."""
- self.admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
- self.admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
+ self._admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
+ self._admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
+ self._admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
+ self._alice_address = ""
- super().__init__(**kwargs)
+ search_interval = cast(
+ float, kwargs.pop("search_interval", DEFAULT_SEARCH_INTERVAL)
+ )
+ super().__init__(tick_interval=search_interval, **kwargs)
+
+ @property
+ def admin_host(self) -> str:
+ """Get the admin host."""
+ return self._admin_host
+
+ @property
+ def admin_port(self) -> str:
+ """Get the admin port."""
+ return self._admin_port
+
+ @property
+ def admin_url(self) -> str:
+ """Get the admin URL."""
+ return self._admin_url
- self.admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
+ @property
+ def alice_address(self) -> Address:
+ """Get Alice's address."""
+ return self._alice_address
- def _admin_get(self, path: str, content: Dict = None) -> None:
+ @alice_address.setter
+ def alice_address(self, address: Address) -> None:
+ self._alice_address = address
+
+ def admin_get(self, path: str, content: Dict = None) -> None:
"""
Get from admin.
@@ -53,7 +88,10 @@ def _admin_get(self, path: str, content: Dict = None) -> None:
:return: None
"""
# Request message & envelope
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
+
request_http_message = HttpMessage(
+ dialogue_reference=http_dialogues.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="GET",
url=self.admin_url + path,
@@ -61,7 +99,11 @@ def _admin_get(self, path: str, content: Dict = None) -> None:
version="",
bodyy=b"" if content is None else json.dumps(content).encode("utf-8"),
)
- request_http_message.counterparty = self.admin_url
+ request_http_message.counterparty = HTTP_COUNTERPARTY
+ http_dialogue = http_dialogues.update(request_http_message)
+ assert (
+ http_dialogue is not None
+ ), "faber -> behaviour -> admin_get(): something went wrong when sending a HTTP message."
self.context.outbox.put_message(message=request_http_message)
def setup(self) -> None:
@@ -70,7 +112,8 @@ def setup(self) -> None:
:return: None
"""
- pass
+ strategy = cast(FaberStrategy, self.context.strategy)
+ strategy.is_searching = True
def act(self) -> None:
"""
@@ -78,7 +121,24 @@ def act(self) -> None:
:return: None
"""
- self._admin_get(ADMIN_COMMAND_STATUS)
+ strategy = cast(FaberStrategy, self.context.strategy)
+ if strategy.is_searching:
+ query = strategy.get_location_and_service_query()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ query=query,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert (
+ oef_dialogue is not None
+ ), "faber -> behaviour -> act(): something went wrong when searching for Alice on SOEF."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("Searching for Alice on SOEF...")
def teardown(self) -> None:
"""
diff --git a/packages/fetchai/skills/aries_faber/dialogues.py b/packages/fetchai/skills/aries_faber/dialogues.py
new file mode 100644
index 0000000000..9cf94a3b3a
--- /dev/null
+++ b/packages/fetchai/skills/aries_faber/dialogues.py
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 classes required for dialogue management.
+
+- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef search and manages it.
+- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef search.
+"""
+
+from aea.helpers.dialogue.base import Dialogue as BaseDialogue
+from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
+from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.skills.base import Model
+
+from packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue
+from packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue as BaseOefSearchDialogue,
+)
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogues as BaseOefSearchDialogues,
+)
+
+DefaultDialogue = BaseDefaultDialogue
+
+
+class DefaultDialogues(Model, BaseDefaultDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+HttpDialogue = BaseHttpDialogue
+
+
+class HttpDialogues(Model, BaseHttpDialogues):
+ """This class keeps track of all http dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseHttpDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseHttpDialogue.Role.CLIENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> HttpDialogue:
+ """
+ Create an instance of http dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = HttpDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+OefSearchDialogue = BaseOefSearchDialogue
+
+
+class OefSearchDialogues(Model, BaseOefSearchDialogues):
+ """This class keeps track of all oef_search dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseOefSearchDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseOefSearchDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> OefSearchDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = OefSearchDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/packages/fetchai/skills/aries_faber/handlers.py b/packages/fetchai/skills/aries_faber/handlers.py
index 4317b1dd67..261346f4b6 100644
--- a/packages/fetchai/skills/aries_faber/handlers.py
+++ b/packages/fetchai/skills/aries_faber/handlers.py
@@ -23,45 +23,61 @@
from typing import Dict, Optional, cast
from aea.configurations.base import ProtocolId
-from aea.mail.base import EnvelopeContext
+from aea.mail.base import Address, EnvelopeContext
from aea.protocols.base import Message
from aea.protocols.default.message import DefaultMessage
from aea.skills.base import Handler
-from packages.fetchai.connections.oef.connection import (
- PUBLIC_ID as OEF_CONNECTION_PUBLIC_ID,
+from packages.fetchai.connections.p2p_libp2p.connection import (
+ PUBLIC_ID as P2P_CONNECTION_PUBLIC_ID,
)
from packages.fetchai.protocols.http.message import HttpMessage
+from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from packages.fetchai.skills.aries_faber.dialogues import (
+ DefaultDialogues,
+ HttpDialogue,
+ HttpDialogues,
+ OefSearchDialogue,
+ OefSearchDialogues,
+)
+from packages.fetchai.skills.aries_faber.strategy import FaberStrategy
-DEFAULT_ADMIN_HOST = "127.0.0.1"
-DEFAULT_ADMIN_PORT = 8021
SUPPORT_REVOCATION = False
ADMIN_COMMAND_CREATE_INVITATION = "/connections/create-invitation"
+ADMIN_COMMAND_STATUS = "/status"
+HTTP_COUNTERPARTY = "HTTP Server"
-class HTTPHandler(Handler):
+class FaberHTTPHandler(Handler):
"""This class represents faber's handler for default messages."""
SUPPORTED_PROTOCOL = HttpMessage.protocol_id # type: Optional[ProtocolId]
def __init__(self, **kwargs):
"""Initialize the handler."""
- self.admin_host = kwargs.pop("admin_host", DEFAULT_ADMIN_HOST)
- self.admin_port = kwargs.pop("admin_port", DEFAULT_ADMIN_PORT)
- self.alice_id = kwargs.pop("alice_id")
-
super().__init__(**kwargs)
- self.admin_url = "http://{}:{}".format(self.admin_host, self.admin_port)
self.connection_id = None # type: Optional[str]
self.is_connected_to_Alice = False
self.handled_message = None
+ @property
+ def admin_url(self) -> str:
+ """Get the admin URL."""
+ return self.context.behaviours.faber.admin_url
+
+ @property
+ def alice_address(self) -> Address:
+ """Get Alice's address."""
+ return self.context.behaviours.faber.alice_address
+
def _admin_post(self, path: str, content: Dict = None) -> None:
# Request message & envelope
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
request_http_message = HttpMessage(
+ dialogue_reference=http_dialogues.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="POST",
url=self.admin_url + path,
@@ -69,17 +85,27 @@ def _admin_post(self, path: str, content: Dict = None) -> None:
version="",
bodyy=b"" if content is None else json.dumps(content).encode("utf-8"),
)
- request_http_message.counterparty = self.admin_url
+ request_http_message.counterparty = HTTP_COUNTERPARTY
+ http_dialogue = http_dialogues.update(request_http_message)
+ assert (
+ http_dialogue is not None
+ ), "faber -> http_handler -> _admin_post(): something went wrong when sending a HTTP message."
self.context.outbox.put_message(message=request_http_message)
def _send_message(self, content: Dict) -> None:
# message & envelope
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
message = DefaultMessage(
+ dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),
performative=DefaultMessage.Performative.BYTES,
content=json.dumps(content).encode("utf-8"),
)
- message.counterparty = self.alice_id
- context = EnvelopeContext(connection_id=OEF_CONNECTION_PUBLIC_ID)
+ message.counterparty = self.alice_address
+ context = EnvelopeContext(connection_id=P2P_CONNECTION_PUBLIC_ID)
+ default_dialogue = default_dialogues.update(message)
+ assert (
+ default_dialogue is not None
+ ), "faber -> http_handler -> _send_message(): something went wrong when sending a default message."
self.context.outbox.put_message(message=message, context=context)
def setup(self) -> None:
@@ -98,11 +124,21 @@ def handle(self, message: Message) -> None:
:return: None
"""
message = cast(HttpMessage, message)
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
+
self.handled_message = message
if (
message.performative == HttpMessage.Performative.RESPONSE
and message.status_code == 200
): # response to http request
+ http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))
+ if http_dialogue is None:
+ self.context.logger.exception(
+ "faber -> http_handler -> handle() -> RESPONSE: "
+ "something went wrong when adding the incoming HTTP response message to the dialogue."
+ )
+ return
+
content_bytes = message.bodyy # type: ignore
content = json.loads(content_bytes)
self.context.logger.info("Received message: " + str(content))
@@ -122,6 +158,13 @@ def handle(self, message: Message) -> None:
elif (
message.performative == HttpMessage.Performative.REQUEST
): # webhook request
+ http_dialogue = cast(Optional[HttpDialogue], http_dialogues.update(message))
+ if http_dialogue is None:
+ self.context.logger.exception(
+ "faber -> http_handler -> handle() -> REQUEST: "
+ "something went wrong when adding the incoming HTTP webhook request message to the dialogue."
+ )
+ return
content_bytes = message.bodyy
content = json.loads(content_bytes)
self.context.logger.info("Received webhook message content:" + str(content))
@@ -138,3 +181,124 @@ def teardown(self) -> None:
:return: None
"""
pass
+
+
+class FaberOefSearchHandler(Handler):
+ """This class implements an OEF search handler."""
+
+ SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[ProtocolId]
+
+ def setup(self) -> None:
+ """Call to setup the handler."""
+ pass
+
+ def handle(self, message: Message) -> None:
+ """
+ Implement the reaction to a message.
+
+ :param message: the message
+ :return: None
+ """
+ self.context.logger.info("Handling SOEF message...")
+ oef_search_msg = cast(OefSearchMessage, message)
+
+ # recover dialogue
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)
+ )
+ if oef_search_dialogue is None:
+ self._handle_unidentified_dialogue(oef_search_msg)
+ return
+
+ # handle message
+ if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:
+ self._handle_error(oef_search_msg, oef_search_dialogue)
+ elif oef_search_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:
+ self._handle_search(oef_search_msg)
+ else:
+ self._handle_invalid(oef_search_msg, oef_search_dialogue)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
+
+ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param oef_search_msg: the oef search message to be handled
+ :return: None
+ """
+ self.context.logger.info(
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
+ )
+ )
+
+ def _handle_error(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message to be handled
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.info(
+ "received oef_search error message={} in dialogue={}.".format(
+ oef_search_msg, oef_search_dialogue
+ )
+ )
+
+ def _handle_search(self, oef_search_msg: OefSearchMessage) -> None:
+ """
+ Handle the search response.
+
+ :param oef_search_msg: the oef search message to be handled
+ :return: None
+ """
+ if len(oef_search_msg.agents) != 1:
+ self.context.logger.info(
+ "did not find Alice. found {} agents. continue searching.".format(
+ len(oef_search_msg.agents)
+ )
+ )
+ return
+
+ self.context.logger.info(
+ "found Alice with address {}, stopping search.".format(
+ oef_search_msg.agents[0]
+ )
+ )
+ strategy = cast(FaberStrategy, self.context.strategy)
+ strategy.is_searching = False # stopping search
+
+ # set alice address
+ self.context.behaviours.faber.alice_address = oef_search_msg.agents[0]
+
+ # check ACA is running
+ self.context.behaviours.faber.admin_get(ADMIN_COMMAND_STATUS)
+
+ def _handle_invalid(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
+ )
+ )
diff --git a/packages/fetchai/skills/aries_faber/skill.yaml b/packages/fetchai/skills/aries_faber/skill.yaml
index a88c0a9da5..8b01e5a2f5 100644
--- a/packages/fetchai/skills/aries_faber/skill.yaml
+++ b/packages/fetchai/skills/aries_faber/skill.yaml
@@ -6,25 +6,48 @@ description: The aries_faber skill implements the faber player in the aries clou
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
- __init__.py: Qma8qSTU34ADKWskBwQKQLGNpe3xDKNgjNQ6Q4MxUnKa3Q
- behaviours.py: QmUErSz1FXfsX7VyQU9YcxteS3j7CpDBAELz4yGEdzdEw1
- handlers.py: Qma2xG1pf5o19uumuQuThEEuWutBpMUbKgdPCb1VVxQAvu
+ __init__.py: QmNPVQ6UajvJodqTLWbLvQZkKCfrNn1nYPrQXai3xdj6F7
+ behaviours.py: QmRh5cVZHXzatgDNC16L3eB1L4jr4Qtmb9E3m23Y9CLXWt
+ dialogues.py: QmP9VtJL3tJWcKU5VTPN7ZcUiPw6oDpCq8La7ZtewcwrUE
+ handlers.py: QmU77Fef51oJP7bsDyTPY1sbmhY8Dk6McZAsHgCv3Fgm3C
+ strategy.py: QmWySg1wmunzCjCGkR6qSUFN9RKYX7ejFX8GxyKmNBvDQH
fingerprint_ignore_patterns: []
contracts: []
protocols: []
skills: []
behaviours:
- aries_demo_faber:
+ faber:
args:
admin_host: 127.0.0.1
admin_port: 8021
+ services_interval: 20
class_name: FaberBehaviour
handlers:
- aries_demo_http:
+ http:
+ args: {}
+ class_name: FaberHTTPHandler
+ oef_search:
+ args: {}
+ class_name: FaberOefSearchHandler
+models:
+ default_dialogues:
+ args: {}
+ class_name: DefaultDialogues
+ http_dialogues:
+ args: {}
+ class_name: HttpDialogues
+ oef_search_dialogues:
+ args: {}
+ class_name: OefSearchDialogues
+ strategy:
args:
- admin_host: 127.0.0.1
- admin_port: 8021
- alice_id: alice_identity_address
- class_name: HTTPHandler
-models: {}
+ location:
+ latitude: 0.127
+ longitude: 51.5194
+ search_query:
+ constraint_type: ==
+ search_key: intro_service
+ search_value: intro_alice
+ search_radius: 5.0
+ class_name: FaberStrategy
dependencies: {}
diff --git a/packages/fetchai/skills/aries_faber/strategy.py b/packages/fetchai/skills/aries_faber/strategy.py
new file mode 100644
index 0000000000..72e77f99c7
--- /dev/null
+++ b/packages/fetchai/skills/aries_faber/strategy.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 strategy class."""
+
+from aea.helpers.search.models import (
+ Constraint,
+ ConstraintType,
+ Location,
+ Query,
+)
+from aea.skills.base import Model
+
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SEARCH_QUERY = {
+ "search_key": "intro_service",
+ "search_value": "intro_alice",
+ "constraint_type": "==",
+}
+DEFAULT_SEARCH_RADIUS = 5.0
+
+
+class FaberStrategy(Model):
+ """This class defines a strategy for the agent."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize the strategy of the agent.
+
+ :return: None
+ """
+ self._search_query = kwargs.pop("search_query", DEFAULT_SEARCH_QUERY)
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = Location(location["longitude"], location["latitude"])
+ self._radius = kwargs.pop("search_radius", DEFAULT_SEARCH_RADIUS)
+
+ super().__init__(**kwargs)
+ self._is_searching = False
+
+ @property
+ def is_searching(self) -> bool:
+ """Check if the agent is searching."""
+ return self._is_searching
+
+ @is_searching.setter
+ def is_searching(self, is_searching: bool) -> None:
+ """Check if the agent is searching."""
+ assert isinstance(is_searching, bool), "Can only set bool on is_searching!"
+ self._is_searching = is_searching
+
+ def get_location_and_service_query(self) -> Query:
+ """
+ Get the location and service query of the agent.
+
+ :return: the query
+ """
+ close_to_my_service = Constraint(
+ "location", ConstraintType("distance", (self._agent_location, self._radius))
+ )
+ service_key_filter = Constraint(
+ self._search_query["search_key"],
+ ConstraintType(
+ self._search_query["constraint_type"],
+ self._search_query["search_value"],
+ ),
+ )
+ query = Query([close_to_my_service, service_key_filter],)
+ return query
diff --git a/packages/fetchai/skills/carpark_client/skill.yaml b/packages/fetchai/skills/carpark_client/skill.yaml
index 16169fc7f2..434ad3baac 100644
--- a/packages/fetchai/skills/carpark_client/skill.yaml
+++ b/packages/fetchai/skills/carpark_client/skill.yaml
@@ -1,6 +1,6 @@
name: carpark_client
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The carpark client skill implements the functionality to run a client
for carpark data.
license: Apache-2.0
@@ -14,12 +14,12 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_buyer:0.7.0
+- fetchai/generic_buyer:0.8.0
behaviours:
search:
args:
diff --git a/packages/fetchai/skills/carpark_detection/database.py b/packages/fetchai/skills/carpark_detection/database.py
index 2667c6b056..51702f9af2 100644
--- a/packages/fetchai/skills/carpark_detection/database.py
+++ b/packages/fetchai/skills/carpark_detection/database.py
@@ -23,10 +23,11 @@
import shutil
import sqlite3
import time
+from typing import Optional
import skimage # type: ignore
-logger = logging.getLogger(
+_logger = logging.getLogger(
"aea.packages.fetchai.skills.carpark_detection.detection_database"
)
@@ -34,7 +35,12 @@
class DetectionDatabase:
"""Communicate between the database and the python objects."""
- def __init__(self, temp_dir, create_if_not_present=True):
+ def __init__(
+ self,
+ temp_dir,
+ create_if_not_present=True,
+ logger: Optional[logging.Logger] = None,
+ ):
"""Initialise the Detection Database Communication class."""
self.this_dir = os.path.dirname(__file__)
self.temp_dir = temp_dir
@@ -54,6 +60,8 @@ def __init__(self, temp_dir, create_if_not_present=True):
if create_if_not_present:
self.initialise_backend()
+ self.logger = logger if logger is not None else _logger
+
def is_db_exits(self):
"""Return true if database exixts and is set up."""
if not os.path.isfile(self.database_path):
@@ -65,7 +73,7 @@ def is_db_exits(self):
def reset_database(self):
"""Reset the database and remove all data."""
# If we need to reset the database, then remove the table and any stored images
- logger.info("Database being reset.")
+ self.logger.info("Database being reset.")
# Remove the actual database file
if os.path.isfile(self.database_path):
@@ -76,14 +84,14 @@ def reset_database(self):
shutil.rmtree(self.processed_image_dir)
# Recreate them
- logger.info("Initialising backend ...")
+ self.logger.info("Initialising backend ...")
self.initialise_backend()
- logger.info("Finished initialising backend!")
+ self.logger.info("Finished initialising backend!")
def reset_mask(self):
"""Just reset the detection mask."""
# If we need to reset the database, then remove the table and any stored images
- logger.info("Mask being reset.")
+ self.logger.info("Mask being reset.")
# Remove the actual database file
if os.path.isfile(self.mask_image_path):
@@ -383,7 +391,7 @@ def execute_single_sql(self, command, variables=(), print_exceptions=True):
conn.commit()
except Exception as e: # pragma: nocover # pylint: disable=broad-except
if print_exceptions:
- logger.warning("Exception in database: {}".format(e))
+ self.logger.warning("Exception in database: {}".format(e))
finally:
if conn is not None:
conn.close()
diff --git a/packages/fetchai/skills/carpark_detection/skill.yaml b/packages/fetchai/skills/carpark_detection/skill.yaml
index 74e9f6a7bb..574f97a032 100644
--- a/packages/fetchai/skills/carpark_detection/skill.yaml
+++ b/packages/fetchai/skills/carpark_detection/skill.yaml
@@ -1,6 +1,6 @@
name: carpark_detection
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The carpark detection skill implements the detection and trading functionality
for a carpark agent.
license: Apache-2.0
@@ -8,20 +8,20 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmQoECB7dpCDCG3xCnBsoMy6oqgSdu69CzRcAcuZuyapnQ
behaviours.py: QmTNboU3YH8DehWnpZmoiDUCncpNmqoSVt1Yp4j7NsgY2S
- database.py: QmVUoN2cuAE54UPvSBRFArdGmVzoSuEjrJXiVkGcfwHrvb
+ database.py: QmZqLyAQiZUaNEhf5t34BGwoLzYVcszwwR69HeDDwqR9uV
dialogues.py: QmPXfUWDxnHDaHQqsgtVhJ2v9dEgGWLtvEHKFvvFcDXGms
handlers.py: QmbkmEP9K4Qu2MsRtnkdx3PGNbSW46qi48bCHVCUJHpcQF
- strategy.py: QmUJsWA9GYHxn5cmuXUQTkc9oCLJNJtWbRDJdRy2Yp3pQk
+ strategy.py: Qmc4m4GuTZvW1oTLJZDLeUErgtMCf9eQhMp1gcvihWKZQD
fingerprint_ignore_patterns:
- temp_files_placeholder/*
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_seller:0.8.0
+- fetchai/generic_seller:0.9.0
behaviours:
service_registration:
args:
diff --git a/packages/fetchai/skills/carpark_detection/strategy.py b/packages/fetchai/skills/carpark_detection/strategy.py
index e7417cf334..81f2443875 100644
--- a/packages/fetchai/skills/carpark_detection/strategy.py
+++ b/packages/fetchai/skills/carpark_detection/strategy.py
@@ -52,8 +52,8 @@ def __init__(self, **kwargs) -> None:
if not os.path.isdir(db_dir):
raise ValueError("Database directory does not exist!")
- self.db = DetectionDatabase(db_dir, False)
super().__init__(**kwargs)
+ self.db = DetectionDatabase(db_dir, False, logger=self.context.logger)
self._update_service_data()
def collect_from_data_source(self) -> Dict[str, str]:
diff --git a/packages/fetchai/skills/echo/handlers.py b/packages/fetchai/skills/echo/handlers.py
index e599276437..5b74f4836e 100644
--- a/packages/fetchai/skills/echo/handlers.py
+++ b/packages/fetchai/skills/echo/handlers.py
@@ -43,7 +43,8 @@ def handle(self, message: Message) -> None:
self.context.logger.info(
"Echo Handler: message={}, sender={}".format(message, message.counterparty)
)
- self.context.outbox.put_message(sender=self.context.agent_name, message=message)
+ message.sender = self.context.agent_name
+ self.context.outbox.put_message(message=message)
def teardown(self) -> None:
"""
diff --git a/packages/fetchai/skills/echo/skill.yaml b/packages/fetchai/skills/echo/skill.yaml
index 801d377120..6e4d408c9b 100644
--- a/packages/fetchai/skills/echo/skill.yaml
+++ b/packages/fetchai/skills/echo/skill.yaml
@@ -1,17 +1,17 @@
name: echo
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The echo skill implements simple echo functionality.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmTf1GCgHxu7qq4HvUNYiBwuGEL1DcsHQuWH7N7TB5TtoC
behaviours.py: QmXARXRvJkpzuqnYNhJhv42Sk6J4KzRW2AKvC6FJWLU9JL
- handlers.py: Qmez6kjFaP3BfeD474gDZCt71KL3sEipoh67osf4urzRFM
+ handlers.py: QmQboz43ehKuVWFbMmxHBqi7EwKuPH4CBuVaAi5D8ABg7m
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: []
behaviours:
echo:
diff --git a/packages/fetchai/skills/erc1155_client/behaviours.py b/packages/fetchai/skills/erc1155_client/behaviours.py
index a2f652abb6..b821e04471 100644
--- a/packages/fetchai/skills/erc1155_client/behaviours.py
+++ b/packages/fetchai/skills/erc1155_client/behaviours.py
@@ -32,7 +32,7 @@
from packages.fetchai.skills.erc1155_client.strategy import Strategy
DEFAULT_SEARCH_INTERVAL = 5.0
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class SearchBehaviour(TickerBehaviour):
@@ -69,7 +69,7 @@ def act(self) -> None:
"""
strategy = cast(Strategy, self.context.strategy)
if strategy.is_searching:
- query = strategy.get_service_query()
+ query = strategy.get_location_and_service_query()
oef_search_dialogues = cast(
OefSearchDialogues, self.context.oef_search_dialogues
)
diff --git a/packages/fetchai/skills/erc1155_client/handlers.py b/packages/fetchai/skills/erc1155_client/handlers.py
index 8b5ae4c736..eaa46851e1 100644
--- a/packages/fetchai/skills/erc1155_client/handlers.py
+++ b/packages/fetchai/skills/erc1155_client/handlers.py
@@ -47,7 +47,7 @@
)
from packages.fetchai.skills.erc1155_client.strategy import Strategy
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class FipaHandler(Handler):
@@ -103,7 +103,7 @@ def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:
:return: None
"""
self.context.logger.info(
- "[{}]: unidentified dialogue.".format(self.context.agent_name)
+ "unidentified dialogue for message={}.".format(fipa_msg)
)
default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
default_msg = DefaultMessage(
@@ -143,10 +143,8 @@ def _handle_propose(
):
# accept any proposal with the correct keys
self.context.logger.info(
- "[{}]: received valid PROPOSE from sender={}: proposal={}".format(
- self.context.agent_name,
- fipa_msg.counterparty[-5:],
- fipa_msg.proposal.values,
+ "received valid PROPOSE from sender={}: proposal={}".format(
+ fipa_msg.counterparty[-5:], fipa_msg.proposal.values,
)
)
strategy = cast(Strategy, self.context.strategy)
@@ -157,7 +155,7 @@ def _handle_propose(
performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=strategy.ledger_id,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=fipa_msg.proposal.values["contract_address"],
callable="get_hash_single",
kwargs=ContractApiMessage.Kwargs(
@@ -198,16 +196,12 @@ def _handle_propose(
contract_api_dialogue.associated_fipa_dialogue = fipa_dialogue
self.context.outbox.put_message(message=contract_api_msg)
self.context.logger.info(
- "[{}]: requesting single hash message from contract api...".format(
- self.context.agent_name
- )
+ "requesting single hash message from contract api..."
)
else:
self.context.logger.info(
- "[{}]: received invalid PROPOSE from sender={}: proposal={}".format(
- self.context.agent_name,
- fipa_msg.counterparty[-5:],
- fipa_msg.proposal.values,
+ "received invalid PROPOSE from sender={}: proposal={}".format(
+ fipa_msg.counterparty[-5:], fipa_msg.proposal.values,
)
)
@@ -222,8 +216,8 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle fipa message of performative={} in dialogue={}.".format(
- self.context.agent_name, fipa_msg.performative, fipa_dialogue
+ "cannot handle fipa message of performative={} in dialogue={}.".format(
+ fipa_msg.performative, fipa_dialogue
)
)
@@ -280,8 +274,8 @@ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> Non
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid oef_search message={}, unidentified dialogue.".format(
- self.context.agent_name, oef_search_msg
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
)
)
@@ -296,8 +290,8 @@ def _handle_error(
:return: None
"""
self.context.logger.info(
- "[{}]: received oef_search error message={} in dialogue={}.".format(
- self.context.agent_name, oef_search_msg, oef_search_dialogue
+ "received oef_search error message={} in dialogue={}.".format(
+ oef_search_msg, oef_search_dialogue
)
)
@@ -311,16 +305,11 @@ def _handle_search(
:return: None
"""
if len(oef_search_msg.agents) == 0:
- self.context.logger.info(
- "[{}]: found no agents, continue searching.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("found no agents, continue searching.")
return
self.context.logger.info(
- "[{}]: found agents={}, stopping search.".format(
- self.context.agent_name,
+ "found agents={}, stopping search.".format(
list(map(lambda x: x[-5:], oef_search_msg.agents)),
)
)
@@ -337,9 +326,7 @@ def _handle_search(
cfp_msg.counterparty = opponent_address
fipa_dialogues.update(cfp_msg)
self.context.logger.info(
- "[{}]: sending CFP to agent={}".format(
- self.context.agent_name, opponent_address[-5:]
- )
+ "sending CFP to agent={}".format(opponent_address[-5:])
)
self.context.outbox.put_message(message=cfp_msg)
@@ -354,10 +341,8 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle oef_search message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- oef_search_msg.performative,
- oef_search_dialogue,
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
)
)
@@ -417,8 +402,8 @@ def _handle_unidentified_dialogue(
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid contract_api message={}, unidentified dialogue.".format(
- self.context.agent_name, contract_api_msg
+ "received invalid contract_api message={}, unidentified dialogue.".format(
+ contract_api_msg
)
)
@@ -433,11 +418,7 @@ def _handle_raw_message(
:param contract_api_message: the ledger api message
:param contract_api_dialogue: the ledger api dialogue
"""
- self.context.logger.info(
- "[{}]: received raw message={}".format(
- self.context.agent_name, contract_api_msg
- )
- )
+ self.context.logger.info("received raw message={}".format(contract_api_msg))
signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_MESSAGE,
@@ -459,9 +440,7 @@ def _handle_raw_message(
signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue
self.context.decision_maker_message_queue.put_nowait(signing_msg)
self.context.logger.info(
- "[{}]: proposing the transaction to the decision maker. Waiting for confirmation ...".format(
- self.context.agent_name
- )
+ "proposing the transaction to the decision maker. Waiting for confirmation ..."
)
def _handle_error(
@@ -476,8 +455,8 @@ def _handle_error(
:param contract_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: received ledger_api error message={} in dialogue={}.".format(
- self.context.agent_name, contract_api_msg, contract_api_dialogue
+ "received ledger_api error message={} in dialogue={}.".format(
+ contract_api_msg, contract_api_dialogue
)
)
@@ -493,10 +472,8 @@ def _handle_invalid(
:param contract_api_dialogue: the ledger api dialogue
"""
self.context.logger.warning(
- "[{}]: cannot handle contract_api message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- contract_api_msg.performative,
- contract_api_dialogue,
+ "cannot handle contract_api message of performative={} in dialogue={}.".format(
+ contract_api_msg.performative, contract_api_dialogue,
)
)
@@ -551,8 +528,8 @@ def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid signing message={}, unidentified dialogue.".format(
- self.context.agent_name, signing_msg
+ "received invalid signing message={}, unidentified dialogue.".format(
+ signing_msg
)
)
@@ -580,10 +557,8 @@ def _handle_signed_message(
)
inform_msg.counterparty = last_fipa_msg.counterparty
self.context.logger.info(
- "[{}]: sending ACCEPT_W_INFORM to agent={}: tx_signature={}".format(
- self.context.agent_name,
- last_fipa_msg.counterparty[-5:],
- signing_msg.signed_message,
+ "sending ACCEPT_W_INFORM to agent={}: tx_signature={}".format(
+ last_fipa_msg.counterparty[-5:], signing_msg.signed_message,
)
)
self.context.outbox.put_message(message=inform_msg)
@@ -599,8 +574,8 @@ def _handle_error(
:return: None
"""
self.context.logger.info(
- "[{}]: transaction signing was not successful. Error_code={} in dialogue={}".format(
- self.context.agent_name, signing_msg.error_code, signing_dialogue
+ "transaction signing was not successful. Error_code={} in dialogue={}".format(
+ signing_msg.error_code, signing_dialogue
)
)
@@ -615,8 +590,8 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle signing message of performative={} in dialogue={}.".format(
- self.context.agent_name, signing_msg.performative, signing_dialogue
+ "cannot handle signing message of performative={} in dialogue={}.".format(
+ signing_msg.performative, signing_dialogue
)
)
@@ -673,8 +648,8 @@ def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> Non
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid ledger_api message={}, unidentified dialogue.".format(
- self.context.agent_name, ledger_api_msg
+ "received invalid ledger_api message={}, unidentified dialogue.".format(
+ ledger_api_msg
)
)
@@ -688,10 +663,8 @@ def _handle_balance(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: starting balance on {} ledger={}.".format(
- self.context.agent_name,
- ledger_api_msg.ledger_id,
- ledger_api_msg.balance,
+ "starting balance on {} ledger={}.".format(
+ ledger_api_msg.ledger_id, ledger_api_msg.balance,
)
)
@@ -705,8 +678,8 @@ def _handle_error(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: received ledger_api error message={} in dialogue={}.".format(
- self.context.agent_name, ledger_api_msg, ledger_api_dialogue
+ "received ledger_api error message={} in dialogue={}.".format(
+ ledger_api_msg, ledger_api_dialogue
)
)
@@ -720,9 +693,7 @@ def _handle_invalid(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.warning(
- "[{}]: cannot handle ledger_api message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- ledger_api_msg.performative,
- ledger_api_dialogue,
+ "cannot handle ledger_api message of performative={} in dialogue={}.".format(
+ ledger_api_msg.performative, ledger_api_dialogue,
)
)
diff --git a/packages/fetchai/skills/erc1155_client/skill.yaml b/packages/fetchai/skills/erc1155_client/skill.yaml
index be87217fc7..80f912d298 100644
--- a/packages/fetchai/skills/erc1155_client/skill.yaml
+++ b/packages/fetchai/skills/erc1155_client/skill.yaml
@@ -1,26 +1,26 @@
name: erc1155_client
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: The erc1155 client interacts with the erc1155 deployer to conduct an
atomic swap.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmRXXJsv5bfvb7qsyxQtVzXwn6PMLJKkbm6kg4DNkT1NtW
- behaviours.py: QmNkEycwsuyBQ2Ay7s3zzYJHCQTSGwmcSfS2YQ3km6mg2X
+ behaviours.py: QmToJBBbG2z8FGwWEtxL7tZkXfWuSUDbesxiAsmxRQxmdj
dialogues.py: QmXd6KC9se6qZWaAsoqJpRYNF6BvVPBd5KJBxSKq9xhLLh
- handlers.py: QmcDbeow6ebn5Q9JbxyanVb8MH5hs4imqLGb9b2hvEhuvF
- strategy.py: QmPr8aXdXnAwJ2NKXcV9TULgu1UuxUH29W8YiMc8LMvLj3
+ handlers.py: QmZeKbEaYpStT2p5p9FzpQ3Yd3JZj1DrzfVL9tpTnG3BV4
+ strategy.py: QmNg87LgfLPoPyokFrmvrNghQD7JkWehRNAdRNyB3YogeN
fingerprint_ignore_patterns: []
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
-- fetchai/signing:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
+- fetchai/signing:0.2.0
skills: []
behaviours:
search:
@@ -65,9 +65,13 @@ models:
strategy:
args:
ledger_id: ethereum
+ location:
+ latitude: 0.127
+ longitude: 51.5194
search_query:
constraint_type: ==
- search_term: has_erc1155_contract
- search_value: true
+ search_key: seller_service
+ search_value: erc1155_contract
+ search_radius: 5.0
class_name: Strategy
dependencies: {}
diff --git a/packages/fetchai/skills/erc1155_client/strategy.py b/packages/fetchai/skills/erc1155_client/strategy.py
index 9d82b8afd3..d528a4bb95 100644
--- a/packages/fetchai/skills/erc1155_client/strategy.py
+++ b/packages/fetchai/skills/erc1155_client/strategy.py
@@ -20,14 +20,18 @@
"""This module contains the strategy class."""
from aea.configurations.constants import DEFAULT_LEDGER
-from aea.helpers.search.models import Constraint, ConstraintType, Query
+from aea.helpers.search.generic import SIMPLE_SERVICE_MODEL
+from aea.helpers.search.models import Constraint, ConstraintType, Location, Query
from aea.skills.base import Model
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
DEFAULT_SEARCH_QUERY = {
- "search_term": "has_erc1155_contract",
- "search_value": True,
+ "search_key": "seller_service",
+ "search_value": "erc1155_contract",
"constraint_type": "==",
}
+DEFAULT_SEARCH_RADIUS = 5.0
+
DEFAULT_LEDGER_ID = DEFAULT_LEDGER
@@ -41,12 +45,10 @@ def __init__(self, **kwargs) -> None:
:return: None
"""
self._search_query = kwargs.pop("search_query", DEFAULT_SEARCH_QUERY)
- assert all(
- [
- key in self._search_query
- for key in ["search_term", "constraint_type", "search_value"]
- ]
- ), "Invalid search query data."
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = Location(location["longitude"], location["latitude"])
+ self._radius = kwargs.pop("search_radius", DEFAULT_SEARCH_RADIUS)
+
self._ledger_id = kwargs.pop("ledger_id", DEFAULT_LEDGER_ID)
super().__init__(**kwargs)
self.is_searching = True
@@ -56,22 +58,37 @@ def ledger_id(self) -> str:
"""Get the ledger id."""
return self._ledger_id
+ def get_location_and_service_query(self) -> Query:
+ """
+ Get the location and service query of the agent.
+
+ :return: the query
+ """
+ close_to_my_service = Constraint(
+ "location", ConstraintType("distance", (self._agent_location, self._radius))
+ )
+ service_key_filter = Constraint(
+ self._search_query["search_key"],
+ ConstraintType(
+ self._search_query["constraint_type"],
+ self._search_query["search_value"],
+ ),
+ )
+ query = Query([close_to_my_service, service_key_filter],)
+ return query
+
def get_service_query(self) -> Query:
"""
Get the service query of the agent.
:return: the query
"""
- query = Query(
- [
- Constraint(
- self._search_query["search_term"],
- ConstraintType(
- self._search_query["constraint_type"],
- self._search_query["search_value"],
- ),
- )
- ],
- model=None,
+ service_key_filter = Constraint(
+ self._search_query["search_key"],
+ ConstraintType(
+ self._search_query["constraint_type"],
+ self._search_query["search_value"],
+ ),
)
+ query = Query([service_key_filter], model=SIMPLE_SERVICE_MODEL)
return query
diff --git a/packages/fetchai/skills/erc1155_deploy/behaviours.py b/packages/fetchai/skills/erc1155_deploy/behaviours.py
index 44e009b0ef..adace5ec53 100644
--- a/packages/fetchai/skills/erc1155_deploy/behaviours.py
+++ b/packages/fetchai/skills/erc1155_deploy/behaviours.py
@@ -21,7 +21,6 @@
from typing import Optional, cast
-from aea.helpers.search.models import Description
from aea.skills.behaviours import TickerBehaviour
from packages.fetchai.protocols.contract_api.message import ContractApiMessage
@@ -36,7 +35,7 @@
from packages.fetchai.skills.erc1155_deploy.strategy import Strategy
DEFAULT_SERVICES_INTERVAL = 30.0
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class ServiceRegistrationBehaviour(TickerBehaviour):
@@ -48,7 +47,7 @@ def __init__(self, **kwargs):
"services_interval", DEFAULT_SERVICES_INTERVAL
) # type: int
super().__init__(tick_interval=services_interval, **kwargs)
- self._registered_service_description = None # type: Optional[Description]
+ self.is_service_registered = False
def setup(self) -> None:
"""
@@ -83,9 +82,11 @@ def act(self) -> None:
strategy.is_contract_deployed
and strategy.is_tokens_created
and strategy.is_tokens_minted
+ and not self.is_service_registered
):
- self._unregister_service()
+ self._register_agent()
self._register_service()
+ self.is_service_registered = True
def teardown(self) -> None:
"""
@@ -94,6 +95,7 @@ def teardown(self) -> None:
:return: None
"""
self._unregister_service()
+ self._unregister_agent()
def _request_balance(self) -> None:
"""
@@ -130,7 +132,7 @@ def _request_contract_deploy_transaction(self) -> None:
performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=strategy.ledger_id,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
callable="get_deploy_transaction",
kwargs=ContractApiMessage.Kwargs(
{"deployer_address": self.context.agent_address}
@@ -144,11 +146,7 @@ def _request_contract_deploy_transaction(self) -> None:
assert contract_api_dialogue is not None, "ContractApiDialogue not generated"
contract_api_dialogue.terms = strategy.get_deploy_terms()
self.context.outbox.put_message(message=contract_api_msg)
- self.context.logger.info(
- "[{}]: Requesting contract deployment transaction...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("requesting contract deployment transaction...")
def _request_token_create_transaction(self) -> None:
"""
@@ -165,7 +163,7 @@ def _request_token_create_transaction(self) -> None:
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=strategy.ledger_id,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=strategy.contract_address,
callable="get_create_batch_transaction",
kwargs=ContractApiMessage.Kwargs(
@@ -183,11 +181,7 @@ def _request_token_create_transaction(self) -> None:
assert contract_api_dialogue is not None, "ContractApiDialogue not generated"
contract_api_dialogue.terms = strategy.get_create_token_terms()
self.context.outbox.put_message(message=contract_api_msg)
- self.context.logger.info(
- "[{}]: Requesting create batch transaction...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("requesting create batch transaction...")
def _request_token_mint_transaction(self) -> None:
"""
@@ -204,7 +198,7 @@ def _request_token_mint_transaction(self) -> None:
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=strategy.ledger_id,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=strategy.contract_address,
callable="get_mint_batch_transaction",
kwargs=ContractApiMessage.Kwargs(
@@ -224,19 +218,37 @@ def _request_token_mint_transaction(self) -> None:
assert contract_api_dialogue is not None, "ContractApiDialogue not generated"
contract_api_dialogue.terms = strategy.get_mint_token_terms()
self.context.outbox.put_message(message=contract_api_msg)
- self.context.logger.info(
- "[{}]: Requesting mint batch transaction...".format(self.context.agent_name)
+ self.context.logger.info("requesting mint batch transaction...")
+
+ def _register_agent(self) -> None:
+ """
+ Register the agent's location.
+
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
)
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering agent on SOEF.")
def _register_service(self) -> None:
"""
- Register to the OEF Service Directory.
+ Register the agent's service.
:return: None
"""
strategy = cast(Strategy, self.context.strategy)
- description = strategy.get_service_description()
- self._registered_service_description = description
+ description = strategy.get_register_service_description()
oef_search_dialogues = cast(
OefSearchDialogues, self.context.oef_search_dialogues
)
@@ -248,34 +260,46 @@ def _register_service(self) -> None:
oef_search_msg.counterparty = self.context.search_service_address
oef_search_dialogues.update(oef_search_msg)
self.context.outbox.put_message(message=oef_search_msg)
- self.context.logger.info(
- "[{}]: updating erc1155 service on OEF search node.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("registering service on SOEF.")
def _unregister_service(self) -> None:
"""
- Unregister service from OEF Service Directory.
+ Unregister service from the SOEF.
:return: None
"""
- if self._registered_service_description is None:
- return
+ strategy = cast(Strategy, self.context.strategy)
+ description = strategy.get_unregister_service_description()
oef_search_dialogues = cast(
OefSearchDialogues, self.context.oef_search_dialogues
)
oef_search_msg = OefSearchMessage(
performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
- service_description=self._registered_service_description,
+ service_description=description,
)
oef_search_msg.counterparty = self.context.search_service_address
oef_search_dialogues.update(oef_search_msg)
self.context.outbox.put_message(message=oef_search_msg)
- self.context.logger.info(
- "[{}]: unregistering erc1155 service from OEF search node.".format(
- self.context.agent_name
- )
+ self.context.logger.info("unregistering service from SOEF.")
+
+ def _unregister_agent(self) -> None:
+ """
+ Unregister agent from the SOEF.
+
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
)
- self._registered_service_description = None
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("unregistering agent from SOEF.")
diff --git a/packages/fetchai/skills/erc1155_deploy/handlers.py b/packages/fetchai/skills/erc1155_deploy/handlers.py
index 36ccb83620..6da272c1e8 100644
--- a/packages/fetchai/skills/erc1155_deploy/handlers.py
+++ b/packages/fetchai/skills/erc1155_deploy/handlers.py
@@ -31,6 +31,7 @@
from packages.fetchai.protocols.contract_api.message import ContractApiMessage
from packages.fetchai.protocols.fipa.message import FipaMessage
from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage
+from packages.fetchai.protocols.oef_search.message import OefSearchMessage
from packages.fetchai.skills.erc1155_deploy.dialogues import (
ContractApiDialogue,
ContractApiDialogues,
@@ -39,13 +40,15 @@
FipaDialogues,
LedgerApiDialogue,
LedgerApiDialogues,
+ OefSearchDialogue,
+ OefSearchDialogues,
SigningDialogue,
SigningDialogues,
)
from packages.fetchai.skills.erc1155_deploy.strategy import Strategy
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class FipaHandler(Handler):
@@ -98,7 +101,7 @@ def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:
:return: None
"""
self.context.logger.info(
- "[{}]: unidentified dialogue.".format(self.context.agent_name)
+ "unidentified dialogue for message={}.".format(fipa_msg)
)
default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
default_msg = DefaultMessage(
@@ -124,9 +127,7 @@ def _handle_cfp(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> Non
"""
strategy = cast(Strategy, self.context.strategy)
self.context.logger.info(
- "[{}]: received CFP from sender={}".format(
- self.context.agent_name, fipa_msg.counterparty[-5:]
- )
+ "received CFP from sender={}".format(fipa_msg.counterparty[-5:])
)
if not strategy.is_tokens_minted:
self.context.logger.info("Contract items not minted yet. Try again later.")
@@ -144,10 +145,8 @@ def _handle_cfp(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> Non
proposal_msg.counterparty = fipa_msg.counterparty
fipa_dialogue.update(proposal_msg)
self.context.logger.info(
- "[{}]: Sending PROPOSE to agent={}: proposal={}".format(
- self.context.agent_name,
- fipa_msg.counterparty[-5:],
- fipa_dialogue.proposal.values,
+ "sending PROPOSE to agent={}: proposal={}".format(
+ fipa_msg.counterparty[-5:], fipa_dialogue.proposal.values,
)
)
self.context.outbox.put_message(message=proposal_msg)
@@ -167,8 +166,8 @@ def _handle_accept_w_inform(
tx_signature = fipa_msg.info.get("tx_signature", None)
if tx_signature is not None:
self.context.logger.info(
- "[{}]: received ACCEPT_W_INFORM from sender={}: tx_signature={}".format(
- self.context.agent_name, fipa_msg.counterparty[-5:], tx_signature
+ "received ACCEPT_W_INFORM from sender={}: tx_signature={}".format(
+ fipa_msg.counterparty[-5:], tx_signature
)
)
strategy = cast(Strategy, self.context.strategy)
@@ -179,7 +178,7 @@ def _handle_accept_w_inform(
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=strategy.ledger_id,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=strategy.contract_address,
callable="get_atomic_swap_single_transaction",
kwargs=ContractApiMessage.Kwargs(
@@ -211,15 +210,11 @@ def _handle_accept_w_inform(
fipa_dialogue.proposal, fipa_msg.counterparty
)
self.context.outbox.put_message(message=contract_api_msg)
- self.context.logger.info(
- "[{}]: Requesting single atomic swap transaction...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("requesting single atomic swap transaction...")
else:
self.context.logger.info(
- "[{}]: received ACCEPT_W_INFORM from sender={} with no signature.".format(
- self.context.agent_name, fipa_msg.counterparty[-5:]
+ "received ACCEPT_W_INFORM from sender={} with no signature.".format(
+ fipa_msg.counterparty[-5:]
)
)
@@ -234,8 +229,8 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle fipa message of performative={} in dialogue={}.".format(
- self.context.agent_name, fipa_msg.performative, fipa_dialogue
+ "cannot handle fipa message of performative={} in dialogue={}.".format(
+ fipa_msg.performative, fipa_dialogue
)
)
@@ -302,8 +297,8 @@ def _handle_unidentified_dialogue(self, ledger_api_msg: LedgerApiMessage) -> Non
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid ledger_api message={}, unidentified dialogue.".format(
- self.context.agent_name, ledger_api_msg
+ "received invalid ledger_api message={}, unidentified dialogue.".format(
+ ledger_api_msg
)
)
@@ -317,10 +312,8 @@ def _handle_balance(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: starting balance on {} ledger={}.".format(
- self.context.agent_name,
- ledger_api_msg.ledger_id,
- ledger_api_msg.balance,
+ "starting balance on {} ledger={}.".format(
+ ledger_api_msg.ledger_id, ledger_api_msg.balance,
)
)
@@ -334,8 +327,8 @@ def _handle_transaction_digest(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: transaction was successfully submitted. Transaction digest={}".format(
- self.context.agent_name, ledger_api_msg.transaction_digest
+ "transaction was successfully submitted. Transaction digest={}".format(
+ ledger_api_msg.transaction_digest
)
)
msg = LedgerApiMessage(
@@ -348,9 +341,7 @@ def _handle_transaction_digest(
msg.counterparty = ledger_api_msg.counterparty
ledger_api_dialogue.update(msg)
self.context.outbox.put_message(message=msg)
- self.context.logger.info(
- "[{}]: requesting transaction receipt.".format(self.context.agent_name)
- )
+ self.context.logger.info("requesting transaction receipt.")
def _handle_transaction_receipt(
self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue
@@ -366,8 +357,8 @@ def _handle_transaction_receipt(
)
if is_transaction_successful:
self.context.logger.info(
- "[{}]: transaction was successfully settled. Transaction receipt={}".format(
- self.context.agent_name, ledger_api_msg.transaction_receipt
+ "transaction was successfully settled. Transaction receipt={}".format(
+ ledger_api_msg.transaction_receipt
)
)
strategy = cast(Strategy, self.context.strategy)
@@ -386,19 +377,13 @@ def _handle_transaction_receipt(
strategy.is_behaviour_active = is_transaction_successful
elif strategy.is_tokens_minted:
self.context.is_active = False
- self.context.logger.info(
- "[{}]: Demo finished!".format(self.context.agent_name)
- )
+ self.context.logger.info("demo finished!")
else:
- self.context.logger.error(
- "[{}]: Unexpected transaction receipt!".format(
- self.context.agent_name
- )
- )
+ self.context.logger.error("unexpected transaction receipt!")
else:
self.context.logger.error(
- "[{}]: transaction failed. Transaction receipt={}".format(
- self.context.agent_name, ledger_api_msg.transaction_receipt
+ "transaction failed. Transaction receipt={}".format(
+ ledger_api_msg.transaction_receipt
)
)
@@ -412,8 +397,8 @@ def _handle_error(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: received ledger_api error message={} in dialogue={}.".format(
- self.context.agent_name, ledger_api_msg, ledger_api_dialogue
+ "received ledger_api error message={} in dialogue={}.".format(
+ ledger_api_msg, ledger_api_dialogue
)
)
@@ -427,10 +412,8 @@ def _handle_invalid(
:param ledger_api_dialogue: the ledger api dialogue
"""
self.context.logger.warning(
- "[{}]: cannot handle ledger_api message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- ledger_api_msg.performative,
- ledger_api_dialogue,
+ "cannot handle ledger_api message of performative={} in dialogue={}.".format(
+ ledger_api_msg.performative, ledger_api_dialogue,
)
)
@@ -493,8 +476,8 @@ def _handle_unidentified_dialogue(
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid contract_api message={}, unidentified dialogue.".format(
- self.context.agent_name, contract_api_msg
+ "received invalid contract_api message={}, unidentified dialogue.".format(
+ contract_api_msg
)
)
@@ -509,11 +492,7 @@ def _handle_raw_transaction(
:param contract_api_message: the ledger api message
:param contract_api_dialogue: the ledger api dialogue
"""
- self.context.logger.info(
- "[{}]: received raw transaction={}".format(
- self.context.agent_name, contract_api_msg
- )
- )
+ self.context.logger.info("received raw transaction={}".format(contract_api_msg))
signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_TRANSACTION,
@@ -531,9 +510,7 @@ def _handle_raw_transaction(
signing_dialogue.associated_contract_api_dialogue = contract_api_dialogue
self.context.decision_maker_message_queue.put_nowait(signing_msg)
self.context.logger.info(
- "[{}]: proposing the transaction to the decision maker. Waiting for confirmation ...".format(
- self.context.agent_name
- )
+ "proposing the transaction to the decision maker. Waiting for confirmation ..."
)
def _handle_error(
@@ -548,8 +525,8 @@ def _handle_error(
:param contract_api_dialogue: the ledger api dialogue
"""
self.context.logger.info(
- "[{}]: received ledger_api error message={} in dialogue={}.".format(
- self.context.agent_name, contract_api_msg, contract_api_dialogue
+ "received ledger_api error message={} in dialogue={}.".format(
+ contract_api_msg, contract_api_dialogue
)
)
@@ -565,10 +542,8 @@ def _handle_invalid(
:param contract_api_dialogue: the ledger api dialogue
"""
self.context.logger.warning(
- "[{}]: cannot handle contract_api message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- contract_api_msg.performative,
- contract_api_dialogue,
+ "cannot handle contract_api message of performative={} in dialogue={}.".format(
+ contract_api_msg.performative, contract_api_dialogue,
)
)
@@ -623,8 +598,8 @@ def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:
:param msg: the message
"""
self.context.logger.info(
- "[{}]: received invalid signing message={}, unidentified dialogue.".format(
- self.context.agent_name, signing_msg
+ "received invalid signing message={}, unidentified dialogue.".format(
+ signing_msg
)
)
@@ -638,9 +613,7 @@ def _handle_signed_transaction(
:param signing_dialogue: the dialogue
:return: None
"""
- self.context.logger.info(
- "[{}]: transaction signing was successful.".format(self.context.agent_name)
- )
+ self.context.logger.info("transaction signing was successful.")
ledger_api_dialogues = cast(
LedgerApiDialogues, self.context.ledger_api_dialogues
)
@@ -656,9 +629,7 @@ def _handle_signed_transaction(
assert ledger_api_dialogue is not None, "Error when creating signing dialogue."
ledger_api_dialogue.associated_signing_dialogue = signing_dialogue
self.context.outbox.put_message(message=ledger_api_msg)
- self.context.logger.info(
- "[{}]: sending transaction to ledger.".format(self.context.agent_name)
- )
+ self.context.logger.info("sending transaction to ledger.")
def _handle_error(
self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
@@ -671,8 +642,8 @@ def _handle_error(
:return: None
"""
self.context.logger.info(
- "[{}]: transaction signing was not successful. Error_code={} in dialogue={}".format(
- self.context.agent_name, signing_msg.error_code, signing_dialogue
+ "transaction signing was not successful. Error_code={} in dialogue={}".format(
+ signing_msg.error_code, signing_dialogue
)
)
@@ -687,7 +658,95 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle signing message of performative={} in dialogue={}.".format(
- self.context.agent_name, signing_msg.performative, signing_dialogue
+ "cannot handle signing message of performative={} in dialogue={}.".format(
+ signing_msg.performative, signing_dialogue
+ )
+ )
+
+
+class OefSearchHandler(Handler):
+ """This class implements an OEF search handler."""
+
+ SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[ProtocolId]
+
+ def setup(self) -> None:
+ """Call to setup the handler."""
+ pass
+
+ def handle(self, message: Message) -> None:
+ """
+ Implement the reaction to a message.
+
+ :param message: the message
+ :return: None
+ """
+ oef_search_msg = cast(OefSearchMessage, message)
+
+ # recover dialogue
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)
+ )
+ if oef_search_dialogue is None:
+ self._handle_unidentified_dialogue(oef_search_msg)
+ return
+
+ # handle message
+ if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:
+ self._handle_error(oef_search_msg, oef_search_dialogue)
+ else:
+ self._handle_invalid(oef_search_msg, oef_search_dialogue)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
+
+ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param msg: the message
+ """
+ self.context.logger.info(
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
+ )
+ )
+
+ def _handle_error(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.info(
+ "received oef_search error message={} in dialogue={}.".format(
+ oef_search_msg, oef_search_dialogue
+ )
+ )
+
+ def _handle_invalid(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
)
)
diff --git a/packages/fetchai/skills/erc1155_deploy/skill.yaml b/packages/fetchai/skills/erc1155_deploy/skill.yaml
index f2a116698e..268d5c780f 100644
--- a/packages/fetchai/skills/erc1155_deploy/skill.yaml
+++ b/packages/fetchai/skills/erc1155_deploy/skill.yaml
@@ -1,26 +1,26 @@
name: erc1155_deploy
author: fetchai
-version: 0.9.0
+version: 0.10.0
description: The ERC1155 deploy skill has the ability to deploy and interact with
the smart contract.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: Qmbm3ZtGpfdvvzqykfRqbaReAK9a16mcyK7qweSfeN5pq1
- behaviours.py: Qmejkpw5Ug9nW8Ju4y8Mg3wTgtJTDFGGcQLXYQKCDjbpVP
+ behaviours.py: QmNo9goXkGc5FYEDqWKheLLhq5aNAgAVGhEijbUBB4XsxQ
dialogues.py: QmR6qb8PdmUozHANKMuLaKfLGKxgnx2zFzbkmcgqXq8wgg
- handlers.py: Qmd6U3zTZqapH5EyaLp2rGCABWVRfkx2arHLVHQgdLWvCf
- strategy.py: QmNLnx4zKMgwe18ou5unotaEJj5jMWTKoSL2UT7PtZZjg3
+ handlers.py: QmaK97BKAbBzwKu8nxwQch4PaCdV4ttSEGAY2hzEXtTMZe
+ strategy.py: QmYvu2yH9fh2reqPXuTLFcX82fjeFA5Wm5K9DrTrDduJ49
fingerprint_ignore_patterns: []
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/contract_api:0.1.0
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
-- fetchai/signing:0.1.0
+- fetchai/contract_api:0.2.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
+- fetchai/signing:0.2.0
skills: []
behaviours:
service_registration:
@@ -37,6 +37,9 @@ handlers:
ledger_api:
args: {}
class_name: LedgerApiHandler
+ oef_search:
+ args: {}
+ class_name: OefSearchHandler
signing:
args: {}
class_name: SigningHandler
@@ -61,14 +64,11 @@ models:
class_name: SigningDialogues
strategy:
args:
- data_model:
- attribute_one:
- is_required: true
- name: has_erc1155_contract
- type: bool
- data_model_name: erc1155_deploy
from_supply: 10
ledger_id: ethereum
+ location:
+ latitude: 0.127
+ longitude: 51.5194
mint_quantities:
- 100
- 100
@@ -82,7 +82,8 @@ models:
- 100
nb_tokens: 10
service_data:
- has_erc1155_contract: true
+ key: seller_service
+ value: erc1155_contract
to_supply: 0
token_type: 2
value: 0
diff --git a/packages/fetchai/skills/erc1155_deploy/strategy.py b/packages/fetchai/skills/erc1155_deploy/strategy.py
index c0326855eb..1ba558902b 100644
--- a/packages/fetchai/skills/erc1155_deploy/strategy.py
+++ b/packages/fetchai/skills/erc1155_deploy/strategy.py
@@ -20,11 +20,16 @@
"""This module contains the strategy class."""
import random # nosec
-from typing import Any, Dict, List, Optional
+from typing import List
from aea.configurations.constants import DEFAULT_LEDGER
-from aea.helpers.search.generic import GenericDataModel
-from aea.helpers.search.models import Description
+from aea.helpers.search.generic import (
+ AGENT_LOCATION_MODEL,
+ AGENT_REMOVE_SERVICE_MODEL,
+ AGENT_SET_SERVICE_MODEL,
+ SIMPLE_SERVICE_MODEL,
+)
+from aea.helpers.search.models import Description, Location
from aea.helpers.transaction.base import Terms
from aea.skills.base import Model
@@ -39,15 +44,8 @@
DEFAULT_FROM_SUPPLY = 10
DEFAULT_TO_SUPPLY = 0
DEFAULT_VALUE = 0
-DEFAULT_DATA_MODEL_NAME = "erc1155_deploy"
-DEFAULT_DATA_MODEL = {
- "attribute_one": {
- "name": "has_erc1155_contract",
- "type": "bool",
- "is_required": "True",
- },
-} # type: Optional[Dict[str, Any]]
-DEFAULT_SERVICE_DATA = {"has_erc1155_contract": True}
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SERVICE_DATA = {"key": "seller_service", "value": "erc1155_contract"}
DEFAULT_LEDGER_ID = DEFAULT_LEDGER
@@ -78,9 +76,20 @@ def __init__(self, **kwargs) -> None:
self.to_supply = kwargs.pop("to_supply", DEFAULT_TO_SUPPLY)
self.value = kwargs.pop("value", DEFAULT_VALUE)
- self._service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA)
- self._data_model = kwargs.pop("data_model", DEFAULT_DATA_MODEL)
- self._data_model_name = kwargs.pop("data_model_name", DEFAULT_DATA_MODEL_NAME)
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = {
+ "location": Location(location["longitude"], location["latitude"])
+ }
+ self._set_service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA)
+ assert (
+ len(self._set_service_data) == 2
+ and "key" in self._set_service_data
+ and "value" in self._set_service_data
+ ), "service_data must contain keys `key` and `value`"
+ self._remove_service_data = {"key": self._set_service_data["key"]}
+ self._simple_service_data = {
+ self._set_service_data["key"]: self._set_service_data["value"]
+ }
super().__init__(**kwargs)
@@ -160,15 +169,47 @@ def is_tokens_minted(self, is_tokens_minted: bool) -> None:
), "Only allowed to switch to true."
self._is_tokens_minted = is_tokens_minted
+ def get_location_description(self) -> Description:
+ """
+ Get the location description.
+
+ :return: a description of the agent's location
+ """
+ description = Description(
+ self._agent_location, data_model=AGENT_LOCATION_MODEL,
+ )
+ return description
+
+ def get_register_service_description(self) -> Description:
+ """
+ Get the register service description.
+
+ :return: a description of the offered services
+ """
+ description = Description(
+ self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL,
+ )
+ return description
+
def get_service_description(self) -> Description:
"""
- Get the service description.
+ Get the simple service description.
:return: a description of the offered services
"""
description = Description(
- self._service_data,
- data_model=GenericDataModel(self._data_model_name, self._data_model),
+ self._simple_service_data, data_model=SIMPLE_SERVICE_MODEL,
+ )
+ return description
+
+ def get_unregister_service_description(self) -> Description:
+ """
+ Get the unregister service description.
+
+ :return: a description of the to be removed service
+ """
+ description = Description(
+ self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL,
)
return description
@@ -179,14 +220,12 @@ def get_deploy_terms(self) -> Terms:
:return: terms
"""
terms = Terms(
- self.ledger_id,
- self.context.agent_address,
- self.context.agent_address,
- {},
- {},
- True,
- "",
- {},
+ ledger_id=self.ledger_id,
+ sender_address=self.context.agent_address,
+ counterparty_address=self.context.agent_address,
+ amount_by_currency_id={},
+ quantities_by_good_id={},
+ nonce="",
)
return terms
@@ -197,14 +236,12 @@ def get_create_token_terms(self) -> Terms:
:return: terms
"""
terms = Terms(
- self.ledger_id,
- self.context.agent_address,
- self.context.agent_address,
- {},
- {},
- True,
- "",
- {},
+ ledger_id=self.ledger_id,
+ sender_address=self.context.agent_address,
+ counterparty_address=self.context.agent_address,
+ amount_by_currency_id={},
+ quantities_by_good_id={},
+ nonce="",
)
return terms
@@ -215,14 +252,12 @@ def get_mint_token_terms(self) -> Terms:
:return: terms
"""
terms = Terms(
- self.ledger_id,
- self.context.agent_address,
- self.context.agent_address,
- {},
- {},
- True,
- "",
- {},
+ ledger_id=self.ledger_id,
+ sender_address=self.context.agent_address,
+ counterparty_address=self.context.agent_address,
+ amount_by_currency_id={},
+ quantities_by_good_id={},
+ nonce="",
)
return terms
diff --git a/packages/fetchai/skills/generic_buyer/behaviours.py b/packages/fetchai/skills/generic_buyer/behaviours.py
index 5448efab29..f7789991bf 100644
--- a/packages/fetchai/skills/generic_buyer/behaviours.py
+++ b/packages/fetchai/skills/generic_buyer/behaviours.py
@@ -32,7 +32,7 @@
from packages.fetchai.skills.generic_buyer.strategy import GenericStrategy
DEFAULT_SEARCH_INTERVAL = 5.0
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class GenericSearchBehaviour(TickerBehaviour):
diff --git a/packages/fetchai/skills/generic_buyer/handlers.py b/packages/fetchai/skills/generic_buyer/handlers.py
index dbf2d7d0d6..478ffed7ab 100644
--- a/packages/fetchai/skills/generic_buyer/handlers.py
+++ b/packages/fetchai/skills/generic_buyer/handlers.py
@@ -44,7 +44,7 @@
)
from packages.fetchai.skills.generic_buyer.strategy import GenericStrategy
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class GenericFipaHandler(Handler):
diff --git a/packages/fetchai/skills/generic_buyer/skill.yaml b/packages/fetchai/skills/generic_buyer/skill.yaml
index 27d759f819..44d80c643f 100644
--- a/packages/fetchai/skills/generic_buyer/skill.yaml
+++ b/packages/fetchai/skills/generic_buyer/skill.yaml
@@ -1,22 +1,22 @@
name: generic_buyer
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The weather client skill implements the skill to purchase weather data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmaEDrNJBeHCJpbdFckRUhLSBqCXQ6umdipTMpYhqSKxSG
- behaviours.py: QmUHgMCuvWYyAU382c7hUikNi6R6rfmH1toKUB1K2rcbXQ
+ behaviours.py: QmQjGXY2qPdmSAkPsEkCntE5GiZwERKV35TXoW54P3jn1J
dialogues.py: QmYMR28TDqE56GdUxP9LwerktaJrD9SBkGoeJsoLSMHpx6
- handlers.py: QmYevHGuYJ8bsQUT22ZJcSx2aotUveNTLbdyEMMzCEMw7U
+ handlers.py: QmTFSy4MCPhtrrPCAoFZJJ7WdHPC4EZRd7qey5hwM7ucJF
strategy.py: QmU2gH921MoxvVCCQhnEvcFNbDsgBojeHeTXDEY3ZBMC2A
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
search:
diff --git a/packages/fetchai/skills/generic_seller/behaviours.py b/packages/fetchai/skills/generic_seller/behaviours.py
index f8c8277914..790ca0da03 100644
--- a/packages/fetchai/skills/generic_seller/behaviours.py
+++ b/packages/fetchai/skills/generic_seller/behaviours.py
@@ -33,7 +33,7 @@
DEFAULT_SERVICES_INTERVAL = 60.0
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class GenericServiceRegistrationBehaviour(TickerBehaviour):
diff --git a/packages/fetchai/skills/generic_seller/handlers.py b/packages/fetchai/skills/generic_seller/handlers.py
index 85303f9279..2d91d793e5 100644
--- a/packages/fetchai/skills/generic_seller/handlers.py
+++ b/packages/fetchai/skills/generic_seller/handlers.py
@@ -42,7 +42,7 @@
)
from packages.fetchai.skills.generic_seller.strategy import GenericStrategy
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class GenericFipaHandler(Handler):
diff --git a/packages/fetchai/skills/generic_seller/skill.yaml b/packages/fetchai/skills/generic_seller/skill.yaml
index 27e72fbbea..ecb9807e9a 100644
--- a/packages/fetchai/skills/generic_seller/skill.yaml
+++ b/packages/fetchai/skills/generic_seller/skill.yaml
@@ -1,23 +1,23 @@
name: generic_seller
author: fetchai
-version: 0.8.0
+version: 0.9.0
description: The weather station skill implements the functionality to sell weather
data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmbfkeFnZVKppLEHpBrTXUXBwg2dpPABJWSLND8Lf1cmpG
- behaviours.py: QmZuzEpqCZjW1rAYT1PZXoYRPjCXxKNQ2ZEkL32WQhxtwf
+ behaviours.py: QmPKPmNmmjXHxk2kVmREwNiAoVQjwdBqCHmpyaZ5n8Exap
dialogues.py: QmNf96REY7PiRdStRJrn97fuCRgqTAeQti5uf4sPzgMNau
- handlers.py: QmfFY8HGULapXzCHHLuwWhgADXvBw8NJvfX155pY3qWS1h
+ handlers.py: QmbpmWTst15PTYMoPf2GBnTJvCMyHaToCV2qRtESyQhvWB
strategy.py: QmRVkBtcCUKXf68RAqnHAi6UWqcygesppUNzSm9oceYNHH
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
service_registration:
diff --git a/packages/fetchai/skills/gym/dialogues.py b/packages/fetchai/skills/gym/dialogues.py
new file mode 100644
index 0000000000..01a6c49e5d
--- /dev/null
+++ b/packages/fetchai/skills/gym/dialogues.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 classes required for dialogue management.
+
+- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.
+- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.
+- GymDialogue: The dialogue class maintains state of a dialogue of type gym and manages it.
+- GymDialogues: The dialogues class keeps track of all dialogues of type gym.
+"""
+
+from aea.helpers.dialogue.base import Dialogue as BaseDialogue
+from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
+from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.skills.base import Model
+
+
+from packages.fetchai.protocols.gym.dialogues import GymDialogue as BaseGymDialogue
+from packages.fetchai.protocols.gym.dialogues import GymDialogues as BaseGymDialogues
+
+DefaultDialogue = BaseDefaultDialogue
+
+
+class DefaultDialogues(Model, BaseDefaultDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of default dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+GymDialogue = BaseGymDialogue
+
+
+class GymDialogues(Model, BaseGymDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseGymDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseGymDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> GymDialogue:
+ """
+ Create an instance of gym dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = GymDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/packages/fetchai/skills/gym/handlers.py b/packages/fetchai/skills/gym/handlers.py
index 1a0e654005..06c668e965 100644
--- a/packages/fetchai/skills/gym/handlers.py
+++ b/packages/fetchai/skills/gym/handlers.py
@@ -22,9 +22,15 @@
from typing import cast
from aea.protocols.base import Message
+from aea.protocols.default.message import DefaultMessage
from aea.skills.base import Handler
from packages.fetchai.protocols.gym.message import GymMessage
+from packages.fetchai.skills.gym.dialogues import (
+ DefaultDialogues,
+ GymDialogue,
+ GymDialogues,
+)
from packages.fetchai.skills.gym.rl_agent import DEFAULT_NB_STEPS
from packages.fetchai.skills.gym.tasks import GymTask
@@ -49,18 +55,89 @@ def setup(self) -> None:
def handle(self, message: Message) -> None:
"""
- Handle messages.
+ Implement messages.
:param message: the message
:return: None
"""
gym_msg = cast(GymMessage, message)
+
+ # recover dialogue
+ gym_dialogues = cast(GymDialogues, self.context.gym_dialogues)
+ gym_dialogue = cast(GymDialogue, gym_dialogues.update(gym_msg))
+ if gym_dialogue is None:
+ self._handle_unidentified_dialogue(gym_msg)
+ return
+
+ # handle message
if gym_msg.performative == GymMessage.Performative.PERCEPT:
+ self._handle_percept(gym_msg, gym_dialogue)
+ elif gym_msg.performative == GymMessage.Performative.STATUS:
+ self._handle_status(gym_msg, gym_dialogue)
+ else:
+ self._handle_invalid(gym_msg, gym_dialogue)
+
+ def _handle_unidentified_dialogue(self, gym_msg: GymMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param gym_msg: the message
+ """
+ self.context.logger.info(
+ "received invalid gym message={}, unidentified dialogue.".format(gym_msg)
+ )
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
+ default_msg = DefaultMessage(
+ performative=DefaultMessage.Performative.ERROR,
+ dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),
+ error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
+ error_msg="Invalid dialogue.",
+ error_data={"gym_message": gym_msg.encode()},
+ )
+ default_msg.counterparty = gym_msg.counterparty
+ default_dialogues.update(default_msg)
+ self.context.outbox.put_message(message=default_msg)
+
+ def _handle_percept(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:
+ """
+ Handle messages.
+
+ :param message: the message
+ :return: None
+ """
+ if self.task.proxy_env.active_gym_dialogue == gym_dialogue:
self.task.proxy_env_queue.put(gym_msg)
else:
- raise ValueError(
- "Unexpected performative or no step_id: {}".format(gym_msg.performative)
+ self.context.logger.warning("gym dialogue not active dialogue.")
+
+ def _handle_status(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:
+ """
+ Handle messages.
+
+ :param message: the message
+ :return: None
+ """
+ if (
+ self.task.proxy_env.active_gym_dialogue == gym_dialogue
+ and gym_msg.content.get("reset", "failure") == "success"
+ ):
+ self.task.proxy_env_queue.put(gym_msg)
+ else:
+ self.context.logger.warning("gym dialogue not active dialogue.")
+
+ def _handle_invalid(self, gym_msg: GymMessage, gym_dialogue: GymDialogue) -> None:
+ """
+ Handle an invalid http message.
+
+ :param gym_msg: the gym message
+ :param gym_dialogue: the gym dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle gym message of performative={} in dialogue={}.".format(
+ gym_msg.performative, gym_dialogue
)
+ )
def teardown(self) -> None:
"""
diff --git a/packages/fetchai/skills/gym/helpers.py b/packages/fetchai/skills/gym/helpers.py
index cac620aac1..d5f501d1dd 100644
--- a/packages/fetchai/skills/gym/helpers.py
+++ b/packages/fetchai/skills/gym/helpers.py
@@ -17,11 +17,12 @@
#
# ------------------------------------------------------------------------------
+
"""This module contains the helpers for the 'gym' skill."""
from abc import ABC, abstractmethod
from queue import Queue
-from typing import Any, Tuple, cast
+from typing import Any, Optional, Tuple, cast
import gym
@@ -29,6 +30,7 @@
from aea.skills.base import SkillContext
from packages.fetchai.protocols.gym.message import GymMessage
+from packages.fetchai.skills.gym.dialogues import GymDialogue, GymDialogues
Action = Any
Observation = Any
@@ -56,6 +58,19 @@ def __init__(self, skill_context: SkillContext) -> None:
self._queue = Queue() # type: Queue
self._is_rl_agent_trained = False
self._step_count = 0
+ self._active_dialogue = None # type: Optional[GymDialogue]
+ self.gym_address = "fetchai/gym:0.5.0"
+
+ @property
+ def gym_dialogues(self) -> GymDialogues:
+ """Get the gym dialogues."""
+ return cast(GymDialogues, self._skill_context.gym_dialogues)
+
+ @property
+ def active_gym_dialogue(self) -> GymDialogue:
+ """Get the active gym dialogue."""
+ assert self._active_dialogue is not None, "GymDialogue not set yet."
+ return self._active_dialogue
@property
def queue(self) -> Queue:
@@ -90,6 +105,13 @@ def step(self, action: Action) -> Feedback:
# Wait (blocking!) for the response envelope from the environment
gym_msg = self._queue.get(block=True, timeout=None) # type: GymMessage
+ if gym_msg.performative != GymMessage.Performative.PERCEPT:
+ raise ValueError(
+ "Unexpected performative. Expected={} got={}".format(
+ GymMessage.Performative.PERCEPT, gym_msg.performative
+ )
+ )
+
if gym_msg.step_id == step_id:
observation, reward, done, info = self._message_to_percept(gym_msg)
else:
@@ -117,10 +139,26 @@ def reset(self) -> None:
"""
self._step_count = 0
self._is_rl_agent_trained = False
- gym_msg = GymMessage(performative=GymMessage.Performative.RESET)
- gym_msg.counterparty = DEFAULT_GYM
+ gym_msg = GymMessage(
+ dialogue_reference=self.gym_dialogues.new_self_initiated_dialogue_reference(),
+ performative=GymMessage.Performative.RESET,
+ )
+ gym_msg.counterparty = self.gym_address
+ gym_dialogue = cast(Optional[GymDialogue], self.gym_dialogues.update(gym_msg))
+ assert gym_dialogue is not None
+ self._active_dialogue = gym_dialogue
self._skill_context.outbox.put_message(message=gym_msg)
+ # Wait (blocking!) for the response envelope from the environment
+ response_msg = self._queue.get(block=True, timeout=None) # type: GymMessage
+
+ if response_msg.performative != GymMessage.Performative.STATUS:
+ raise ValueError(
+ "Unexpected performative. Expected={} got={}".format(
+ GymMessage.Performative.PERCEPT, response_msg.performative
+ )
+ )
+
def close(self) -> None:
"""
Close the environment.
@@ -128,8 +166,16 @@ def close(self) -> None:
:return: None
"""
self._is_rl_agent_trained = True
- gym_msg = GymMessage(performative=GymMessage.Performative.CLOSE)
- gym_msg.counterparty = DEFAULT_GYM
+ last_msg = self.active_gym_dialogue.last_message
+ assert last_msg is not None, "Cannot retrieve last message."
+ gym_msg = GymMessage(
+ dialogue_reference=self.active_gym_dialogue.dialogue_label.dialogue_reference,
+ performative=GymMessage.Performative.CLOSE,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
+ )
+ gym_msg.counterparty = self.gym_address
+ assert self.active_gym_dialogue.update(gym_msg)
self._skill_context.outbox.put_message(message=gym_msg)
def _encode_and_send_action(self, action: Action, step_id: int) -> None:
@@ -140,12 +186,18 @@ def _encode_and_send_action(self, action: Action, step_id: int) -> None:
:param step_id: the step id
:return: an envelope
"""
+ last_msg = self.active_gym_dialogue.last_message
+ assert last_msg is not None, "Cannot retrieve last message."
gym_msg = GymMessage(
+ dialogue_reference=self.active_gym_dialogue.dialogue_label.dialogue_reference,
performative=GymMessage.Performative.ACT,
action=GymMessage.AnyObject(action),
step_id=step_id,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
)
- gym_msg.counterparty = DEFAULT_GYM
+ gym_msg.counterparty = self.gym_address
+ assert self.active_gym_dialogue.update(gym_msg)
# Send the message via the proxy agent and to the environment
self._skill_context.outbox.put_message(message=gym_msg)
diff --git a/packages/fetchai/skills/gym/rl_agent.py b/packages/fetchai/skills/gym/rl_agent.py
index 73aa0317de..9e8b3ccca5 100644
--- a/packages/fetchai/skills/gym/rl_agent.py
+++ b/packages/fetchai/skills/gym/rl_agent.py
@@ -30,7 +30,7 @@
DEFAULT_NB_STEPS = 4000
NB_GOODS = 10
-logger = logging.getLogger("aea.packages.fetchai.skills.gym.rl_agent")
+_default_logger = logging.getLogger("aea.packages.fetchai.skills.gym.rl_agent")
class PriceBandit:
@@ -108,16 +108,18 @@ def get_price_expectation(self) -> int:
class MyRLAgent(RLAgent):
"""This class is a reinforcement learning agent that interacts with the agent framework."""
- def __init__(self, nb_goods: int) -> None:
+ def __init__(self, nb_goods: int, logger: logging.Logger = _default_logger) -> None:
"""
Instantiate the RL agent.
:param nb_goods: number of goods
+ :param logger: the logger.
:return: None
"""
self.good_price_models = dict(
(good_id, GoodPriceModel()) for good_id in range(nb_goods)
) # type: Dict[int, GoodPriceModel]
+ self.logger = logger
def _pick_an_action(self) -> Any:
"""
@@ -178,7 +180,7 @@ def fit(self, proxy_env: ProxyEnv, nb_steps: int) -> None:
self._update_model(obs, reward, done, info, action)
action_counter += 1
if action_counter % 10 == 0:
- logger.info(
+ self.logger.info(
"Action: step_id='{}' action='{}' reward='{}'".format(
action_counter, action, reward
)
diff --git a/packages/fetchai/skills/gym/skill.yaml b/packages/fetchai/skills/gym/skill.yaml
index 9b3796c592..dbd1d9c4c9 100644
--- a/packages/fetchai/skills/gym/skill.yaml
+++ b/packages/fetchai/skills/gym/skill.yaml
@@ -1,19 +1,20 @@
name: gym
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The gym skill wraps an RL agent.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmTf1GCgHxu7qq4HvUNYiBwuGEL1DcsHQuWH7N7TB5TtoC
- handlers.py: QmaYf2XGHhGDYQpyud9BDrP7jfENpjRKARr6Y1H2vKM5cQ
- helpers.py: QmQDHWAnBC6kkXWTcizhJFoJy9pNBPNMPp2Xam8s92CRyK
- rl_agent.py: QmVQHRWY4w8Ch8hhCxuzS1qZqG7ZJENiTEWHCGH484FPMP
- tasks.py: QmURSaDncmKj9Ri6JM4eBwWkEg2JEJrMdxMygKiBNiD2cf
+ dialogues.py: Qmek8aEAEFsM8tjofQcst7hckAUdGUpAML9D8aPjLUbq9L
+ handlers.py: QmWqN7TrqZ9Hfh4yVU7JmR7655TsdLPASSkLsVHbTkDEjV
+ helpers.py: QmX9La8CJH3oQDHZKExTABg8omszpSRnXFFKnv568m6Nh1
+ rl_agent.py: QmZQBXQS1nS64irym5y3eKkGzTdE652aQoq8V54ph17D8U
+ tasks.py: QmVf9K7zCkKYduTnS7nS3d8FvUbEVy7s7a26yaCC8Q3rgd
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/gym:0.3.0
+- fetchai/gym:0.4.0
skills: []
behaviours: {}
handlers:
@@ -21,6 +22,12 @@ handlers:
args:
nb_steps: 4000
class_name: GymHandler
-models: {}
+models:
+ default_dialogues:
+ args: {}
+ class_name: DefaultDialogues
+ gym_dialogues:
+ args: {}
+ class_name: GymDialogues
dependencies:
gym: {}
diff --git a/packages/fetchai/skills/gym/tasks.py b/packages/fetchai/skills/gym/tasks.py
index 5aa42a2ca9..0972210c19 100644
--- a/packages/fetchai/skills/gym/tasks.py
+++ b/packages/fetchai/skills/gym/tasks.py
@@ -19,7 +19,6 @@
"""This module contains the tasks for the 'gym' skill."""
-import logging
from queue import Queue
from threading import Thread
@@ -29,17 +28,15 @@
from packages.fetchai.skills.gym.helpers import ProxyEnv
from packages.fetchai.skills.gym.rl_agent import DEFAULT_NB_STEPS, MyRLAgent, NB_GOODS
-logger = logging.getLogger("aea.packages.fetchai.skills.gym.tasks")
-
class GymTask(Task):
"""Gym task."""
def __init__(self, skill_context: SkillContext, nb_steps: int = DEFAULT_NB_STEPS):
"""Initialize the task."""
- logger.debug("GymTask.__init__: arguments: nb_steps={}".format(nb_steps))
- super().__init__()
- self._rl_agent = MyRLAgent(NB_GOODS)
+ super().__init__(logger=skill_context.logger)
+ self.logger.debug("GymTask.__init__: arguments: nb_steps={}".format(nb_steps))
+ self._rl_agent = MyRLAgent(NB_GOODS, self.logger)
self._proxy_env = ProxyEnv(skill_context)
self.nb_steps = nb_steps
self._rl_agent_training_thread = Thread(
@@ -50,7 +47,12 @@ def __init__(self, skill_context: SkillContext, nb_steps: int = DEFAULT_NB_STEPS
def _fit(self, proxy_env: ProxyEnv, nb_steps: int):
"""Fit the RL agent."""
self._rl_agent.fit(proxy_env, nb_steps)
- logger.info("Training finished. You can exit now via CTRL+C.")
+ self.logger.info("Training finished. You can exit now via CTRL+C.")
+
+ @property
+ def proxy_env(self) -> ProxyEnv:
+ """Get the queue."""
+ return self._proxy_env
@property
def proxy_env_queue(self) -> Queue:
@@ -59,7 +61,7 @@ def proxy_env_queue(self) -> Queue:
def setup(self) -> None:
"""Set up the task."""
- logger.info("Gym task: setup method called.")
+ self.logger.info("Gym task: setup method called.")
def execute(self, *args, **kwargs) -> None:
"""Execute the task."""
@@ -70,13 +72,13 @@ def execute(self, *args, **kwargs) -> None:
def teardown(self) -> None:
"""Teardown the task."""
- logger.info("Gym Task: teardown method called.")
+ self.logger.info("Gym Task: teardown method called.")
if self.is_rl_agent_training:
self._stop_training()
def _start_training(self) -> None:
"""Start training the RL agent."""
- logger.info("Training starting ...")
+ self.logger.info("Training starting ...")
self.is_rl_agent_training = True
self._rl_agent_training_thread.start()
diff --git a/packages/fetchai/skills/http_echo/dialogues.py b/packages/fetchai/skills/http_echo/dialogues.py
new file mode 100644
index 0000000000..6b33e9f779
--- /dev/null
+++ b/packages/fetchai/skills/http_echo/dialogues.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 classes required for dialogue management.
+
+- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.
+- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.
+- HttpDialogue: The dialogue class maintains state of a dialogue of type http and manages it.
+- HttpDialogues: The dialogues class keeps track of all dialogues of type http.
+"""
+
+from aea.helpers.dialogue.base import Dialogue as BaseDialogue
+from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
+from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.skills.base import Model
+
+
+from packages.fetchai.protocols.http.dialogues import HttpDialogue as BaseHttpDialogue
+from packages.fetchai.protocols.http.dialogues import HttpDialogues as BaseHttpDialogues
+
+DefaultDialogue = BaseDefaultDialogue
+
+
+class DefaultDialogues(Model, BaseDefaultDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of default dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+HttpDialogue = BaseHttpDialogue
+
+
+class HttpDialogues(Model, BaseHttpDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseHttpDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseHttpDialogue.Role.SERVER
+
+ def create_dialogue(
+ self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
+ ) -> HttpDialogue:
+ """
+ Create an instance of http dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = HttpDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/packages/fetchai/skills/http_echo/handlers.py b/packages/fetchai/skills/http_echo/handlers.py
index 444e0818e1..7ed1c1d0eb 100644
--- a/packages/fetchai/skills/http_echo/handlers.py
+++ b/packages/fetchai/skills/http_echo/handlers.py
@@ -23,9 +23,15 @@
from typing import cast
from aea.protocols.base import Message
+from aea.protocols.default import DefaultMessage
from aea.skills.base import Handler
from packages.fetchai.protocols.http.message import HttpMessage
+from packages.fetchai.skills.http_echo.dialogues import (
+ DefaultDialogues,
+ HttpDialogue,
+ HttpDialogues,
+)
class HttpHandler(Handler):
@@ -49,35 +55,71 @@ def handle(self, message: Message) -> None:
:return: None
"""
http_msg = cast(HttpMessage, message)
+
+ # recover dialogue
+ http_dialogues = cast(HttpDialogues, self.context.http_dialogues)
+ http_dialogue = cast(HttpDialogue, http_dialogues.update(http_msg))
+ if http_dialogue is None:
+ self._handle_unidentified_dialogue(http_msg)
+ return
+
+ # handle message
if http_msg.performative == HttpMessage.Performative.REQUEST:
- self.context.logger.info(
- "[{}] received http request with method={}, url={} and body={!r}".format(
- self.context.agent_name,
- http_msg.method,
- http_msg.url,
- http_msg.bodyy,
- )
- )
- if http_msg.method == "get":
- self._handle_get(http_msg)
- elif http_msg.method == "post":
- self._handle_post(http_msg)
+ self._handle_request(http_msg, http_dialogue)
else:
- self.context.logger.info(
- "[{}] received response ({}) unexpectedly!".format(
- self.context.agent_name, http_msg
- )
+ self._handle_invalid(http_msg, http_dialogue)
+
+ def _handle_unidentified_dialogue(self, http_msg: HttpMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param http_msg: the message
+ """
+ self.context.logger.info(
+ "received invalid http message={}, unidentified dialogue.".format(http_msg)
+ )
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
+ default_msg = DefaultMessage(
+ performative=DefaultMessage.Performative.ERROR,
+ dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),
+ error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
+ error_msg="Invalid dialogue.",
+ error_data={"http_message": http_msg.encode()},
+ )
+ default_msg.counterparty = http_msg.counterparty
+ default_dialogues.update(default_msg)
+ self.context.outbox.put_message(message=default_msg)
+
+ def _handle_request(
+ self, http_msg: HttpMessage, http_dialogue: HttpDialogue
+ ) -> None:
+ """
+ Handle a Http request.
+
+ :param http_msg: the http message
+ :param http_dialogue: the http dialogue
+ :return: None
+ """
+ self.context.logger.info(
+ "received http request with method={}, url={} and body={!r}".format(
+ http_msg.method, http_msg.url, http_msg.bodyy,
)
+ )
+ if http_msg.method == "get":
+ self._handle_get(http_msg, http_dialogue)
+ elif http_msg.method == "post":
+ self._handle_post(http_msg, http_dialogue)
- def _handle_get(self, http_msg: HttpMessage) -> None:
+ def _handle_get(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:
"""
Handle a Http request of verb GET.
:param http_msg: the http message
+ :param http_dialogue: the http dialogue
:return: None
"""
http_response = HttpMessage(
- dialogue_reference=http_msg.dialogue_reference,
+ dialogue_reference=http_dialogue.dialogue_label.dialogue_reference,
target=http_msg.message_id,
message_id=http_msg.message_id + 1,
performative=HttpMessage.Performative.RESPONSE,
@@ -87,21 +129,21 @@ def _handle_get(self, http_msg: HttpMessage) -> None:
headers=http_msg.headers,
bodyy=json.dumps({"tom": {"type": "cat", "age": 10}}).encode("utf-8"),
)
- self.context.logger.info(
- "[{}] responding with: {}".format(self.context.agent_name, http_response)
- )
+ self.context.logger.info("responding with: {}".format(http_response))
http_response.counterparty = http_msg.counterparty
+ assert http_dialogue.update(http_response)
self.context.outbox.put_message(message=http_response)
- def _handle_post(self, http_msg: HttpMessage) -> None:
+ def _handle_post(self, http_msg: HttpMessage, http_dialogue: HttpDialogue) -> None:
"""
Handle a Http request of verb POST.
:param http_msg: the http message
+ :param http_dialogue: the http dialogue
:return: None
"""
http_response = HttpMessage(
- dialogue_reference=http_msg.dialogue_reference,
+ dialogue_reference=http_dialogue.dialogue_label.dialogue_reference,
target=http_msg.message_id,
message_id=http_msg.message_id + 1,
performative=HttpMessage.Performative.RESPONSE,
@@ -111,12 +153,27 @@ def _handle_post(self, http_msg: HttpMessage) -> None:
headers=http_msg.headers,
bodyy=b"",
)
- self.context.logger.info(
- "[{}] responding with: {}".format(self.context.agent_name, http_response)
- )
+ self.context.logger.info("responding with: {}".format(http_response))
http_response.counterparty = http_msg.counterparty
+ assert http_dialogue.update(http_response)
self.context.outbox.put_message(message=http_response)
+ def _handle_invalid(
+ self, http_msg: HttpMessage, http_dialogue: HttpDialogue
+ ) -> None:
+ """
+ Handle an invalid http message.
+
+ :param http_msg: the http message
+ :param http_dialogue: the http dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle http message of performative={} in dialogue={}.".format(
+ http_msg.performative, http_dialogue
+ )
+ )
+
def teardown(self) -> None:
"""
Implement the handler teardown.
diff --git a/packages/fetchai/skills/http_echo/skill.yaml b/packages/fetchai/skills/http_echo/skill.yaml
index 49a7a1e182..69b796c40f 100644
--- a/packages/fetchai/skills/http_echo/skill.yaml
+++ b/packages/fetchai/skills/http_echo/skill.yaml
@@ -1,22 +1,29 @@
name: http_echo
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The http echo skill prints out the content of received http messages
and responds with success.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmaKik9dXg6cajBPG9RTDr6BhVdWk8aoR8QDNfPQgiy1kv
- handlers.py: QmUZsmWggTTWiGj3qWkD6Hv3tin1BtqUaKmQD1a2e3z6J5
+ dialogues.py: QmXWBBSj9U7ZYH3anv9fr3WenKqdD9NqnG9jeoWmxnf5ds
+ handlers.py: QmUzf5DeEgN7B8ZTopSF18A7qLV1dGmvJ1bmYzq5a9ahXr
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/http:0.3.0
+- fetchai/http:0.4.0
skills: []
behaviours: {}
handlers:
http_handler:
args: {}
class_name: HttpHandler
-models: {}
+models:
+ default_dialogues:
+ args: {}
+ class_name: DefaultDialogues
+ http_dialogues:
+ args: {}
+ class_name: HttpDialogues
dependencies: {}
diff --git a/packages/fetchai/skills/ml_data_provider/skill.yaml b/packages/fetchai/skills/ml_data_provider/skill.yaml
index 4940cad544..08da1dd16d 100644
--- a/packages/fetchai/skills/ml_data_provider/skill.yaml
+++ b/packages/fetchai/skills/ml_data_provider/skill.yaml
@@ -1,6 +1,6 @@
name: ml_data_provider
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The ml data provider skill implements a provider for Machine Learning
datasets in order to monetize data.
license: Apache-2.0
@@ -14,12 +14,12 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/ledger_api:0.1.0
-- fetchai/ml_trade:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/ledger_api:0.2.0
+- fetchai/ml_trade:0.4.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_seller:0.8.0
+- fetchai/generic_seller:0.9.0
behaviours:
service_registration:
args:
diff --git a/packages/fetchai/skills/ml_train/handlers.py b/packages/fetchai/skills/ml_train/handlers.py
index 3aa535e435..774791eca1 100644
--- a/packages/fetchai/skills/ml_train/handlers.py
+++ b/packages/fetchai/skills/ml_train/handlers.py
@@ -48,7 +48,7 @@
DUMMY_DIGEST = "dummy_digest"
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class MlTradeHandler(Handler):
diff --git a/packages/fetchai/skills/ml_train/skill.yaml b/packages/fetchai/skills/ml_train/skill.yaml
index 07ccf0f020..d9953c6828 100644
--- a/packages/fetchai/skills/ml_train/skill.yaml
+++ b/packages/fetchai/skills/ml_train/skill.yaml
@@ -1,6 +1,6 @@
name: ml_train
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The ml train and predict skill implements a simple skill which buys training
data, trains a model and sells predictions.
license: Apache-2.0
@@ -9,20 +9,20 @@ fingerprint:
__init__.py: QmbQigh7SV7dD2hLTGv3k9tnvpYWN1otG5yjiM7F3bbGEQ
behaviours.py: QmQiBzKV5rEFpMQbSjfjzAJ7SqwwGmso6TozWkjdytucLR
dialogues.py: QmYnVHVF2EMt3Rfvqpi7T7R6XTEcxaSXhDdim4kjt9a4dL
- handlers.py: QmXRnQXtSSX4KZNm7hPfD2UNJUaPnF6quB73RRnvqLYk2q
+ handlers.py: QmSEsHjwNoF4tpPW377fqXAai5EqNN45kLnnTgj5KdkUBZ
ml_model.py: QmZiJGCarjpczcHKQ4EFYSx1e4mEehfaApnHp2W4VQs1od
model.json: QmdV2tGrRY6VQ5VLgUa4yqAhPDG6X8tYsWecypq8nox9Td
strategy.py: QmPVHfq6okd7Yq9RqA2697L5pnXzBjcJfad97sAXfDUQq9
- tasks.py: QmS5pGbxvMXSh1Vmuvq26e5APnheQJJ3r3BK6GEyUBUpAf
+ tasks.py: QmTb7kCt2UheQ8kwPewkzgfX8m2DF4KtnYCugWdmERJnTU
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/ledger_api:0.1.0
-- fetchai/ml_trade:0.3.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/ledger_api:0.2.0
+- fetchai/ml_trade:0.4.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_buyer:0.7.0
+- fetchai/generic_buyer:0.8.0
behaviours:
search:
args:
diff --git a/packages/fetchai/skills/ml_train/tasks.py b/packages/fetchai/skills/ml_train/tasks.py
index 641e1b417d..72468c0f39 100644
--- a/packages/fetchai/skills/ml_train/tasks.py
+++ b/packages/fetchai/skills/ml_train/tasks.py
@@ -19,30 +19,29 @@
"""This module contains the tasks for the 'ml_train' skill."""
-import logging
from typing import Tuple
import numpy as np
from tensorflow import keras
+from aea.skills.base import SkillContext
from aea.skills.tasks import Task
-logger = logging.getLogger("aea.packages.fetchai.skills.ml_train.tasks")
-
class MLTrainTask(Task):
"""ML train task."""
def __init__(
self,
+ skill_context: SkillContext,
train_data: Tuple[np.ndarray, np.ndarray],
model: keras.Model,
epochs_per_batch: int = 10,
batch_size: int = 32,
):
"""Initialize the task."""
- super().__init__()
+ super().__init__(logger=skill_context.logger)
self.train_x, self.train_y = train_data
self.model = model
@@ -51,16 +50,16 @@ def __init__(
def setup(self) -> None:
"""Set up the task."""
- logger.info("ML Train task: setup method called.")
+ self.logger.info("ML Train task: setup method called.")
def execute(self, *args, **kwargs) -> keras.Model:
"""Execute the task."""
- logger.info("Start training with {} rows".format(self.train_x.shape[0]))
+ self.logger.info("Start training with {} rows".format(self.train_x.shape[0]))
self.model.fit(self.train_x, self.train_y, epochs=self.epochs_per_batch)
loss, acc = self.model.evaluate(self.train_x, self.train_y, verbose=2)
- logger.info("Loss: {}, Acc: {}".format(loss, acc))
+ self.logger.info("Loss: {}, Acc: {}".format(loss, acc))
return self.model
def teardown(self) -> None:
"""Teardown the task."""
- logger.info("ML Train task: teardown method called.")
+ self.logger.info("ML Train task: teardown method called.")
diff --git a/packages/fetchai/skills/simple_service_registration/handlers.py b/packages/fetchai/skills/simple_service_registration/handlers.py
index ef787f4679..1b19883fb8 100644
--- a/packages/fetchai/skills/simple_service_registration/handlers.py
+++ b/packages/fetchai/skills/simple_service_registration/handlers.py
@@ -31,7 +31,7 @@
OefSearchDialogues,
)
-LEDGER_API_ADDRESS = "fetchai/ledger:0.2.0"
+LEDGER_API_ADDRESS = "fetchai/ledger:0.3.0"
class OefSearchHandler(Handler):
diff --git a/packages/fetchai/skills/simple_service_registration/skill.yaml b/packages/fetchai/skills/simple_service_registration/skill.yaml
index 6e355becbf..9edbd7c606 100644
--- a/packages/fetchai/skills/simple_service_registration/skill.yaml
+++ b/packages/fetchai/skills/simple_service_registration/skill.yaml
@@ -1,6 +1,6 @@
name: simple_service_registration
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The simple service registration skills is a skill to register a service.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -8,12 +8,12 @@ fingerprint:
__init__.py: QmNkZAetyctaZCUf6ACxP5onGWsSxu2hjSNoFmJ3ta6Lta
behaviours.py: QmRr1oe3zWKyPcktzKP4BiKqjCqmKjEDdLUQhn1JzNm4nD
dialogues.py: QmayFh6ytPefJng5ENTUg46zsd6guHCZSsG3Cc2sy3xz6y
- handlers.py: QmViyyV5KvR3kkLEMpvDfqH5QtHowTbnpDxRYnKABpVvpC
+ handlers.py: QmVahH8Ck5ukgR2kThaNR58DQYizC9CPp4aUzoe5Q6MHVy
strategy.py: Qmdp6LCPZSnnyfM4EdRDTGZPqwxiJ3A1jsc3oF2Hv4m5Mv
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
service:
diff --git a/packages/fetchai/skills/tac_control/behaviours.py b/packages/fetchai/skills/tac_control/behaviours.py
index 789ba0b725..d6e2828f75 100644
--- a/packages/fetchai/skills/tac_control/behaviours.py
+++ b/packages/fetchai/skills/tac_control/behaviours.py
@@ -22,28 +22,26 @@
import datetime
from typing import Optional, cast
-from aea.helpers.search.models import Attribute, DataModel, Description
+from aea.helpers.search.models import Description
from aea.skills.base import Behaviour
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
from packages.fetchai.protocols.tac.message import TacMessage
+from packages.fetchai.skills.tac_control.dialogues import (
+ OefSearchDialogues,
+ TacDialogues,
+)
from packages.fetchai.skills.tac_control.game import Game, Phase
from packages.fetchai.skills.tac_control.parameters import Parameters
-CONTROLLER_DATAMODEL = DataModel(
- "tac",
- [Attribute("version", str, True, "Version number of the TAC Controller Agent.")],
-)
-
-class TACBehaviour(Behaviour):
+class TacBehaviour(Behaviour):
"""This class implements the TAC control behaviour."""
def __init__(self, **kwargs):
"""Instantiate the behaviour."""
super().__init__(**kwargs)
- self._oef_msg_id = 0
- self._registered_desc = None # type: Optional[Description]
+ self._registered_description = None # type: Optional[Description]
def setup(self) -> None:
"""
@@ -51,7 +49,7 @@ def setup(self) -> None:
:return: None
"""
- pass
+ self._register_agent()
def act(self) -> None:
"""
@@ -69,25 +67,23 @@ def act(self) -> None:
game.phase = Phase.GAME_REGISTRATION
self._register_tac()
self.context.logger.info(
- "[{}]: TAC open for registration until: {}".format(
- self.context.agent_name, parameters.start_time
- )
+ "TAC open for registration until: {}".format(parameters.start_time)
)
elif (
game.phase.value == Phase.GAME_REGISTRATION.value
and parameters.start_time < now < parameters.end_time
):
if game.registration.nb_agents < parameters.min_nb_agents:
- self._cancel_tac()
+ self._cancel_tac(game)
game.phase = Phase.POST_GAME
self._unregister_tac()
else:
game.phase = Phase.GAME_SETUP
- self._start_tac()
+ self._start_tac(game)
self._unregister_tac()
game.phase = Phase.GAME
elif game.phase.value == Phase.GAME.value and now > parameters.end_time:
- self._cancel_tac()
+ self._cancel_tac(game)
game.phase = Phase.POST_GAME
def teardown(self) -> None:
@@ -96,8 +92,29 @@ def teardown(self) -> None:
:return: None
"""
- if self._registered_desc is not None:
- self._unregister_tac()
+ self._unregister_tac()
+ self._unregister_agent()
+
+ def _register_agent(self) -> None:
+ """
+ Register the agent's location.
+
+ :return: None
+ """
+ game = cast(Game, self.context.game)
+ description = game.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering agent on SOEF.")
def _register_tac(self) -> None:
"""
@@ -105,22 +122,20 @@ def _register_tac(self) -> None:
:return: None.
"""
- self._oef_msg_id += 1
- desc = Description(
- {"version": self.context.parameters.version_id},
- data_model=CONTROLLER_DATAMODEL,
- )
- self.context.logger.info(
- "[{}]: Registering TAC data model".format(self.context.agent_name)
+ game = cast(Game, self.context.game)
+ description = game.get_register_tac_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
)
- oef_msg = OefSearchMessage(
+ oef_search_msg = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(self._oef_msg_id), ""),
- service_description=desc,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
)
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
- self._registered_desc = desc
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering TAC data model on SOEF.")
def _unregister_tac(self) -> None:
"""
@@ -128,78 +143,104 @@ def _unregister_tac(self) -> None:
:return: None.
"""
- if self._registered_desc is not None:
- self._oef_msg_id += 1
- self.context.logger.info(
- "[{}]: Unregistering TAC data model".format(self.context.agent_name)
- )
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(self._oef_msg_id), ""),
- service_description=self._registered_desc,
- )
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
- self._registered_desc = None
+ game = cast(Game, self.context.game)
+ description = game.get_unregister_tac_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self._registered_description = None
+ self.context.logger.info("unregistering TAC data model from SOEF.")
- def _start_tac(self):
- """Create a game and send the game configuration to every registered agent."""
+ def _unregister_agent(self) -> None:
+ """
+ Unregister agent from the SOEF.
+
+ :return: None
+ """
game = cast(Game, self.context.game)
+ description = game.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogues.update(oef_search_msg)
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("unregistering agent from SOEF.")
+
+ def _start_tac(self, game: Game):
+ """Create a game and send the game configuration to every registered agent."""
game.create()
self.context.logger.info(
- "[{}]: Started competition:\n{}".format(
- self.context.agent_name, game.holdings_summary
- )
+ "started competition:\n{}".format(game.holdings_summary)
)
self.context.logger.info(
- "[{}]: Computed equilibrium:\n{}".format(
- self.context.agent_name, game.equilibrium_summary
- )
+ "computed equilibrium:\n{}".format(game.equilibrium_summary)
)
+ tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)
for agent_address in game.conf.agent_addr_to_name.keys():
+ tac_dialogue = tac_dialogues.dialogue_by_address.get(agent_address, None)
+ assert tac_dialogue is not None, "Error when retrieving dialogue."
+ last_msg = tac_dialogue.last_message
+ assert last_msg is not None, "Error when retrieving last message."
agent_state = game.current_agent_states[agent_address]
tac_msg = TacMessage(
performative=TacMessage.Performative.GAME_DATA,
+ dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
amount_by_currency_id=agent_state.amount_by_currency_id,
exchange_params_by_currency_id=agent_state.exchange_params_by_currency_id,
quantities_by_good_id=agent_state.quantities_by_good_id,
utility_params_by_good_id=agent_state.utility_params_by_good_id,
- tx_fee=game.conf.tx_fee,
+ fee_by_currency_id=game.conf.fee_by_currency_id,
currency_id_to_name=game.conf.currency_id_to_name,
agent_addr_to_name=game.conf.agent_addr_to_name,
good_id_to_name=game.conf.good_id_to_name,
version_id=game.conf.version_id,
)
- self.context.logger.debug(
- "[{}]: sending game data to '{}': {}".format(
- self.context.agent_name, agent_address, str(tac_msg)
- )
- )
tac_msg.counterparty = agent_address
+ tac_dialogues.update(tac_msg)
self.context.outbox.put_message(message=tac_msg)
+ self.context.logger.debug(
+ "sending game data to '{}': {}".format(agent_address, str(tac_msg))
+ )
- def _cancel_tac(self):
+ def _cancel_tac(self, game: Game):
"""Notify agents that the TAC is cancelled."""
- game = cast(Game, self.context.game)
- self.context.logger.info(
- "[{}]: Notifying agents that TAC is cancelled.".format(
- self.context.agent_name
+ self.context.logger.info("notifying agents that TAC is cancelled.")
+ tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)
+ for agent_address in game.registration.agent_addr_to_name.keys():
+ tac_dialogue = tac_dialogues.dialogue_by_address.get(agent_address, None)
+ assert tac_dialogue is not None, "Error when retrieving dialogue."
+ last_msg = tac_dialogue.last_message
+ assert last_msg is not None, "Error when retrieving last message."
+ tac_msg = TacMessage(
+ performative=TacMessage.Performative.CANCELLED,
+ dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
)
- )
- for agent_addr in game.registration.agent_addr_to_name.keys():
- tac_msg = TacMessage(performative=TacMessage.Performative.CANCELLED)
- tac_msg.counterparty = agent_addr
+ tac_msg.counterparty = agent_address
+ tac_dialogues.update(tac_msg)
self.context.outbox.put_message(message=tac_msg)
if game.phase == Phase.GAME:
self.context.logger.info(
- "[{}]: Finished competition:\n{}".format(
- self.context.agent_name, game.holdings_summary
- )
+ "finished competition:\n{}".format(game.holdings_summary)
)
self.context.logger.info(
- "[{}]: Computed equilibrium:\n{}".format(
- self.context.agent_name, game.equilibrium_summary
- )
+ "computed equilibrium:\n{}".format(game.equilibrium_summary)
)
-
self.context.is_active = False
diff --git a/packages/fetchai/skills/tac_control/dialogues.py b/packages/fetchai/skills/tac_control/dialogues.py
new file mode 100644
index 0000000000..646c15e498
--- /dev/null
+++ b/packages/fetchai/skills/tac_control/dialogues.py
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 classes required for dialogue management.
+
+- DefaultDialogue: The dialogue class maintains state of a dialogue of type default and manages it.
+- DefaultDialogues: The dialogues class keeps track of all dialogues of type default.
+- OefSearchDialogue: The dialogue class maintains state of a dialogue of type oef_search and manages it.
+- OefSearchDialogues: The dialogues class keeps track of all dialogues of type oef_search.
+- TacDialogue: The dialogue class maintains state of a dialogue of type tac and manages it.
+- TacDialogues: The dialogues class keeps track of all dialogues of type tac.
+"""
+
+from typing import Dict
+
+from aea.helpers.dialogue.base import Dialogue
+from aea.helpers.dialogue.base import DialogueLabel
+from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.skills.base import Model
+
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue as BaseOefSearchDialogue,
+)
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogues as BaseOefSearchDialogues,
+)
+from packages.fetchai.protocols.tac.dialogues import TacDialogue as BaseTacDialogue
+from packages.fetchai.protocols.tac.dialogues import TacDialogues as BaseTacDialogues
+
+
+DefaultDialogue = BaseDefaultDialogue
+
+
+class DefaultDialogues(Model, BaseDefaultDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+OefSearchDialogue = BaseOefSearchDialogue
+
+
+class OefSearchDialogues(Model, BaseOefSearchDialogues):
+ """This class keeps track of all oef_search dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseOefSearchDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseOefSearchDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> OefSearchDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = OefSearchDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+TacDialogue = BaseTacDialogue
+
+
+class TacDialogues(Model, BaseTacDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseTacDialogues.__init__(self, self.context.agent_address)
+ self._dialogue_by_address = {} # type: Dict[str, Dialogue]
+
+ @property
+ def dialogue_by_address(self) -> Dict[str, Dialogue]:
+ """Get the dialogue by address."""
+ return self._dialogue_by_address
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return TacDialogue.Role.CONTROLLER
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> TacDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = TacDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ self._dialogue_by_address[dialogue_label.dialogue_opponent_addr] = dialogue
+ return dialogue
diff --git a/packages/fetchai/skills/tac_control/game.py b/packages/fetchai/skills/tac_control/game.py
index 620ca8a16c..c3b52e283d 100644
--- a/packages/fetchai/skills/tac_control/game.py
+++ b/packages/fetchai/skills/tac_control/game.py
@@ -25,16 +25,18 @@
from enum import Enum
from typing import Dict, List, Optional, cast
-from eth_account.messages import encode_defunct
-
-from hexbytes import HexBytes
-
-from web3 import Web3
-
+from aea.crypto.ledger_apis import LedgerApis
from aea.helpers.preference_representations.base import (
linear_utility,
logarithmic_utility,
)
+from aea.helpers.search.generic import (
+ AGENT_LOCATION_MODEL,
+ AGENT_REMOVE_SERVICE_MODEL,
+ AGENT_SET_SERVICE_MODEL,
+)
+from aea.helpers.search.models import Description
+from aea.helpers.transaction.base import Terms
from aea.mail.base import Address
from aea.skills.base import Model
@@ -48,7 +50,6 @@
generate_good_endowments,
generate_good_id_to_name,
generate_utility_params,
- tx_hash_from_values,
)
from packages.fetchai.skills.tac_control.parameters import Parameters
@@ -107,9 +108,9 @@ def version_id(self) -> str:
return self._version_id
@property
- def tx_fee(self) -> int:
+ def fee_by_currency_id(self) -> Dict[str, int]:
"""Transaction fee for the TAC instance."""
- return self._tx_fee
+ return {next(iter(self.currency_id_to_name.keys())): self._tx_fee}
@property
def agent_addr_to_name(self) -> Dict[Address, str]:
@@ -134,7 +135,7 @@ def _check_consistency(self):
:raises: AssertionError: if some constraint is not satisfied.
"""
assert self.version_id is not None, "A version id must be set."
- assert self.tx_fee >= 0, "Tx fee must be non-negative."
+ assert self._tx_fee >= 0, "Tx fee must be non-negative."
assert len(self.agent_addr_to_name) >= 2, "Must have at least two agents."
assert len(self.good_id_to_name) >= 2, "Must have at least two goods."
assert len(self.currency_id_to_name) == 1, "Must have exactly one currency."
@@ -262,88 +263,50 @@ def _check_consistency(self):
), "Dimensions for utility_params and good_endowments rows must be the same."
-class Transaction:
+class Transaction(Terms):
"""Convenience representation of a transaction."""
def __init__(
self,
- transaction_id: TransactionId,
- sender_addr: Address,
- counterparty_addr: Address,
+ ledger_id: str,
+ sender_address: Address,
+ counterparty_address: Address,
amount_by_currency_id: Dict[str, int],
- sender_fee: int,
- counterparty_fee: int,
quantities_by_good_id: Dict[str, int],
- nonce: int,
+ is_sender_payable_tx_fee: bool,
+ nonce: str,
+ fee_by_currency_id: Optional[Dict[str, int]],
sender_signature: str,
counterparty_signature: str,
) -> None:
"""
- Instantiate transaction request.
-
- :param transaction_id: the id of the transaction.
- :param sender_addr: the sender of the transaction.
- :param tx_counterparty_addr: the counterparty of the transaction.
- :param amount_by_currency_id: the currency used.
- :param sender_fee: the transaction fee covered by the sender.
- :param counterparty_fee: the transaction fee covered by the counterparty.
- :param quantities_by_good_id: a map from good pbk to the quantity of that good involved in the transaction.
- :param nonce: the nonce of the transaction
- :param sender_signature: the signature of the transaction sender
- :param counterparty_signature: the signature of the transaction counterparty
- :return: None
- """
- self._id = transaction_id
- self._sender_addr = sender_addr
- self._counterparty_addr = counterparty_addr
- self._amount_by_currency_id = amount_by_currency_id
- self._sender_fee = sender_fee
- self._counterparty_fee = counterparty_fee
- self._quantities_by_good_id = quantities_by_good_id
- self._nonce = nonce
+ Instantiate transaction.
+
+ This extends a terms object to be used as a transaction.
+
+ :param ledger_id: the ledger on which the terms are to be settled.
+ :param sender_address: the sender address of the transaction.
+ :param counterparty_address: the counterparty address of the transaction.
+ :param amount_by_currency_id: the amount by the currency of the transaction.
+ :param quantities_by_good_id: a map from good id to the quantity of that good involved in the transaction.
+ :param is_sender_payable_tx_fee: whether the sender or counterparty pays the tx fee.
+ :param nonce: nonce to be included in transaction to discriminate otherwise identical transactions.
+ :param fee_by_currency_id: the fee associated with the transaction.
+ :param sender_signature: the signature of the terms by the sender.
+ :param counterparty_signature: the signature of the terms by the counterparty.
+ """
+ super().__init__(
+ ledger_id=ledger_id,
+ sender_address=sender_address,
+ counterparty_address=counterparty_address,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ fee_by_currency_id=fee_by_currency_id,
+ )
self._sender_signature = sender_signature
self._counterparty_signature = counterparty_signature
- self._check_consistency()
-
- @property
- def id(self) -> str:
- """Get the transaction id."""
- return self._id
-
- @property
- def sender_addr(self) -> Address:
- """Get the sender address."""
- return self._sender_addr
-
- @property
- def counterparty_addr(self) -> Address:
- """Get the counterparty address."""
- return self._counterparty_addr
-
- @property
- def amount_by_currency_id(self) -> Dict[CurrencyId, Quantity]:
- """Get the amount for each currency."""
- return copy.copy(self._amount_by_currency_id)
-
- @property
- def sender_fee(self) -> int:
- """Get the sender fee."""
- return self._sender_fee
-
- @property
- def counterparty_fee(self) -> int:
- """Get the counterparty fee."""
- return self._counterparty_fee
-
- @property
- def quantities_by_good_id(self) -> Dict[GoodId, Quantity]:
- """Get the quantities by good_id."""
- return copy.copy(self._quantities_by_good_id)
-
- @property
- def nonce(self) -> int:
- """Get the nonce of the transaction."""
- return self._nonce
@property
def sender_signature(self) -> str:
@@ -355,119 +318,31 @@ def counterparty_signature(self) -> str:
"""Get the counterparty signature."""
return self._counterparty_signature
- @property
- def is_sender_buyer(self) -> bool:
- """Get the sender is buyer status."""
- return all(value <= 0 for value in self.amount_by_currency_id.values())
-
- @property
- def buyer_addr(self) -> Address:
- """Get the buyer address."""
- return self._sender_addr if self.is_sender_buyer else self._counterparty_addr
-
- @property
- def sender_hash(self) -> bytes:
- """Get the sender hash."""
- return tx_hash_from_values(
- tx_sender_addr=self.sender_addr,
- tx_counterparty_addr=self.counterparty_addr,
- tx_quantities_by_good_id=self.quantities_by_good_id,
- tx_amount_by_currency_id=self.amount_by_currency_id,
- tx_nonce=self.nonce,
- )
-
- @property
- def counterparty_hash(self) -> bytes:
- """Get the sender hash."""
- return tx_hash_from_values(
- tx_sender_addr=self.counterparty_addr,
- tx_counterparty_addr=self.sender_addr,
- tx_quantities_by_good_id={
- good_id: -quantity
- for good_id, quantity in self.quantities_by_good_id.items()
- },
- tx_amount_by_currency_id={
- currency_id: -amount
- for currency_id, amount in self.amount_by_currency_id.items()
- },
- tx_nonce=self.nonce,
- )
-
- @property
- def amount(self) -> int:
- """Get the amount."""
- return list(self.amount_by_currency_id.values())[0]
-
- @property
- def currency_id(self) -> str:
- """Get the currency id."""
- return list(self.amount_by_currency_id.keys())[0]
-
- @property
- def sender_amount(self) -> int:
- """Get the amount the sender gets/pays."""
- return self.amount - self.sender_fee
-
- @property
- def counterparty_amount(self) -> int:
- """Get the amount the counterparty gets/pays."""
- return -self.amount - self.counterparty_fee
-
- def _check_consistency(self) -> None:
- """
- Check the consistency of the transaction parameters.
-
- :return: None
- :raises AssertionError if some constraint is not satisfied.
- """
- assert self.sender_addr != self.counterparty_addr
- assert (
- len(self.amount_by_currency_id.keys()) == 1
- ) # For now we restrict to one currency per transaction.
- assert self.sender_fee >= 0
- assert self.counterparty_fee >= 0
- assert (
- self.amount >= 0
- and all(quantity <= 0 for quantity in self.quantities_by_good_id.values())
- ) or (
- self.amount <= 0
- and all(quantity >= 0 for quantity in self.quantities_by_good_id.values())
- )
- assert isinstance(self.sender_signature, str) and isinstance(
- self.counterparty_signature, str
- )
- if self.amount >= 0:
- assert (
- self.sender_amount >= 0
- ), "Sender_amount must be positive when the sender is the payment receiver."
- else:
- assert (
- self.counterparty_amount >= 0
- ), "Counterparty_amount must be positive when the counterpary is the payment receiver."
-
def has_matching_signatures(self) -> bool:
"""
Check that the signatures match the terms of trade.
:return: True if the transaction has been signed by both parties
"""
- w3 = Web3()
- singable_message = encode_defunct(primitive=self.sender_hash)
+
+ # singable_message = LedgerApis.sign_message(self.sender_hash)
result = (
- w3.eth.account.recover_message( # pylint: disable=no-member
- signable_message=singable_message,
- signature=HexBytes(self.sender_signature),
+ self.sender_address
+ in LedgerApis.recover_message( # pylint: disable=no-member
+ identifier=self.ledger_id,
+ message=self.sender_hash.encode("utf-8"),
+ signature=self.sender_signature,
)
- == self.sender_addr
)
- counterparty_signable_message = encode_defunct(primitive=self.counterparty_hash)
+ # counterparty_signable_message = LedgerApis.sign_message(self.counterparty_hash)
result = (
result
- and w3.eth.account.recover_message( # pylint: disable=no-member
- signable_message=counterparty_signable_message,
- signature=HexBytes(self.counterparty_signature),
+ and self.counterparty_address
+ in LedgerApis.recover_message( # pylint: disable=no-member
+ identifier=self.ledger_id,
+ message=self.counterparty_hash.encode("utf-8"),
+ signature=self.counterparty_signature,
)
- == self.counterparty_addr
)
return result
@@ -479,32 +354,31 @@ def from_message(cls, message: TacMessage) -> "Transaction":
:param message: the message
:return: Transaction
"""
- assert message.performative == TacMessage.Performative.TRANSACTION
- return Transaction(
- message.tx_id,
- message.tx_sender_addr,
- message.tx_counterparty_addr,
- message.amount_by_currency_id,
- message.tx_sender_fee,
- message.tx_counterparty_fee,
- message.quantities_by_good_id,
- message.tx_nonce,
- message.tx_sender_signature,
- message.tx_counterparty_signature,
+ assert (
+ message.performative == TacMessage.Performative.TRANSACTION
+ ), "Wrong performative"
+ transaction = Transaction(
+ ledger_id=message.ledger_id,
+ sender_address=message.sender_address,
+ counterparty_address=message.counterparty_address,
+ amount_by_currency_id=message.amount_by_currency_id,
+ fee_by_currency_id=message.fee_by_currency_id,
+ quantities_by_good_id=message.quantities_by_good_id,
+ is_sender_payable_tx_fee=True, # TODO: check
+ nonce=str(message.nonce),
+ sender_signature=message.sender_signature,
+ counterparty_signature=message.counterparty_signature,
)
+ assert (
+ transaction.id == message.transaction_id
+ ), "Transaction content does not match hash."
+ return transaction
def __eq__(self, other):
"""Compare to another object."""
return (
isinstance(other, Transaction)
- and self.id == other.id
- and self.sender_addr == other.sender_addr
- and self.counterparty_addr == other.counterparty_addr
- and self.amount_by_currency_id == other.amount_by_currency_id
- and self.sender_fee == other.sender_fee
- and self.counterparty_fee == other.counterparty_fee
- and self.quantities_by_good_id == other.quantities_by_good_id
- and self.nonce == other.nonce
+ and super.__eq__()
and self.sender_signature == other.sender_signature
and self.counterparty_signature == other.counterparty_signature
)
@@ -592,42 +466,47 @@ def is_consistent_transaction(self, tx: Transaction) -> bool:
or enough holdings if it is a seller.
:return: True if the transaction is legal wrt the current state, False otherwise.
"""
- result = self.agent_address in [tx.sender_addr, tx.counterparty_addr]
- if tx.amount == 0 and all(
+ result = self.agent_address in [tx.sender_address, tx.counterparty_address]
+ result = result and tx.is_single_currency
+ if not result:
+ return result
+ if all(amount == 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity == 0 for quantity in tx.quantities_by_good_id.values()
):
# reject the transaction when there is no wealth exchange
result = False
- elif tx.amount <= 0 and all(
+ elif all(amount <= 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity >= 0 for quantity in tx.quantities_by_good_id.values()
):
# sender is buyer, counterparty is seller
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# check this sender state has enough money
result = result and (
- self.amount_by_currency_id[tx.currency_id] >= tx.sender_amount
+ self.amount_by_currency_id[tx.currency_id]
+ >= tx.sender_payable_amount
)
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
# check this counterparty state has enough goods
result = result and all(
self.quantities_by_good_id[good_id] >= quantity
for good_id, quantity in tx.quantities_by_good_id.items()
)
- elif tx.amount >= 0 and all(
+ elif all(amount >= 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity <= 0 for quantity in tx.quantities_by_good_id.values()
):
# sender is seller, counterparty is buyer
# Note, on a ledger, this atomic swap would only be possible for amount == 0!
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# check this sender state has enough goods
result = result and all(
self.quantities_by_good_id[good_id] >= -quantity
for good_id, quantity in tx.quantities_by_good_id.items()
)
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
# check this counterparty state has enough money
result = result and (
- self.amount_by_currency_id[tx.currency_id] >= tx.counterparty_amount
+ self.amount_by_currency_id[tx.currency_id]
+ >= tx.counterparty_payable_amount
)
else:
result = False
@@ -656,20 +535,22 @@ def update(self, tx: Transaction) -> None:
assert self.is_consistent_transaction(tx), "Inconsistent transaction."
new_amount_by_currency_id = self.amount_by_currency_id
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# settling the transaction for the sender
- new_amount_by_currency_id[tx.currency_id] += tx.sender_amount
- elif self.agent_address == tx.counterparty_addr:
+ for currency_id, amount in tx.amount_by_currency_id.items():
+ new_amount_by_currency_id[currency_id] += amount
+ elif self.agent_address == tx.counterparty_address:
# settling the transaction for the counterparty
- new_amount_by_currency_id[tx.currency_id] += tx.counterparty_amount
+ for currency_id, amount in tx.amount_by_currency_id.items():
+ new_amount_by_currency_id[currency_id] += amount
self._amount_by_currency_id = new_amount_by_currency_id
new_quantities_by_good_id = self.quantities_by_good_id
for good_id, quantity in tx.quantities_by_good_id.items():
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
new_quantities_by_good_id[good_id] += quantity
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
new_quantities_by_good_id[good_id] -= quantity
self._quantities_by_good_id = new_quantities_by_good_id
@@ -741,12 +622,12 @@ def add(self, transaction: Transaction) -> None:
"""
now = datetime.datetime.now()
self._confirmed[now] = transaction
- if self._confirmed_per_agent.get(transaction.sender_addr) is None:
- self._confirmed_per_agent[transaction.sender_addr] = {}
- self._confirmed_per_agent[transaction.sender_addr][now] = transaction
- if self._confirmed_per_agent.get(transaction.counterparty_addr) is None:
- self._confirmed_per_agent[transaction.counterparty_addr] = {}
- self._confirmed_per_agent[transaction.counterparty_addr][now] = transaction
+ if self._confirmed_per_agent.get(transaction.sender_address) is None:
+ self._confirmed_per_agent[transaction.sender_address] = {}
+ self._confirmed_per_agent[transaction.sender_address][now] = transaction
+ if self._confirmed_per_agent.get(transaction.counterparty_address) is None:
+ self._confirmed_per_agent[transaction.counterparty_address] = {}
+ self._confirmed_per_agent[transaction.counterparty_address][now] = transaction
class Registration:
@@ -1020,8 +901,8 @@ def is_transaction_valid(self, tx: Transaction) -> bool:
:return: True if the transaction is valid, False otherwise.
:raises: AssertionError: if the data in the transaction are not allowed (e.g. negative amount).
"""
- sender_state = self.current_agent_states[tx.sender_addr]
- counterparty_state = self.current_agent_states[tx.counterparty_addr]
+ sender_state = self.current_agent_states[tx.sender_address]
+ counterparty_state = self.current_agent_states[tx.counterparty_address]
result = tx.has_matching_signatures()
result = result and sender_state.is_consistent_transaction(tx)
result = result and counterparty_state.is_consistent_transaction(tx)
@@ -1039,14 +920,41 @@ def settle_transaction(self, tx: Transaction) -> None:
self._current_agent_states is not None
), "Call create before calling current_agent_states."
assert self.is_transaction_valid(tx), "Transaction is not valid."
- sender_state = self.current_agent_states[tx.sender_addr]
- counterparty_state = self.current_agent_states[tx.counterparty_addr]
+ sender_state = self.current_agent_states[tx.sender_address]
+ counterparty_state = self.current_agent_states[tx.counterparty_address]
new_sender_state = sender_state.apply([tx])
new_counterparty_state = counterparty_state.apply([tx])
self.transactions.add(tx)
- self._current_agent_states.update({tx.sender_addr: new_sender_state})
+ self._current_agent_states.update({tx.sender_address: new_sender_state})
self._current_agent_states.update(
- {tx.counterparty_addr: new_counterparty_state}
+ {tx.counterparty_address: new_counterparty_state}
+ )
+
+ def get_location_description(self) -> Description:
+ """
+ Get the location description.
+
+ :return: a description of the agent's location
+ """
+ description = Description(
+ self.context.parameters.agent_location, data_model=AGENT_LOCATION_MODEL,
+ )
+ return description
+
+ def get_register_tac_description(self) -> Description:
+ """Get the tac description for registering."""
+ description = Description(
+ self.context.parameters.set_service_data,
+ data_model=AGENT_SET_SERVICE_MODEL,
+ )
+ return description
+
+ def get_unregister_tac_description(self) -> Description:
+ """Get the tac description for unregistering."""
+ description = Description(
+ self.context.parameters.remove_service_data,
+ data_model=AGENT_REMOVE_SERVICE_MODEL,
)
+ return description
diff --git a/packages/fetchai/skills/tac_control/handlers.py b/packages/fetchai/skills/tac_control/handlers.py
index 7d55057a03..64f82deb66 100644
--- a/packages/fetchai/skills/tac_control/handlers.py
+++ b/packages/fetchai/skills/tac_control/handlers.py
@@ -19,18 +19,26 @@
"""This package contains the handlers."""
-from typing import cast
+from typing import Optional, cast
from aea.protocols.base import Message
+from aea.protocols.default.message import DefaultMessage
from aea.skills.base import Handler
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
from packages.fetchai.protocols.tac.message import TacMessage
+from packages.fetchai.skills.tac_control.dialogues import (
+ DefaultDialogues,
+ OefSearchDialogue,
+ OefSearchDialogues,
+ TacDialogue,
+ TacDialogues,
+)
from packages.fetchai.skills.tac_control.game import Game, Phase, Transaction
from packages.fetchai.skills.tac_control.parameters import Parameters
-class TACHandler(Handler):
+class TacHandler(Handler):
"""This class handles oef messages."""
SUPPORTED_PROTOCOL = TacMessage.protocol_id
@@ -52,150 +60,188 @@ def handle(self, message: Message) -> None:
:param message: the 'get agent state' TacMessage.
:return: None
"""
- tac_message = cast(TacMessage, message)
+ tac_msg = cast(TacMessage, message)
- game = cast(Game, self.context.game)
+ # recover dialogue
+ tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)
+ tac_dialogue = cast(TacDialogue, tac_dialogues.update(tac_msg))
+ if tac_dialogue is None:
+ self._handle_unidentified_dialogue(tac_msg)
+ return
self.context.logger.debug(
- "[{}]: Handling TAC message. performative={}".format(
- self.context.agent_name, tac_message.performative
- )
+ "handling TAC message. performative={}".format(tac_msg.performative)
)
- if (
- tac_message.performative == TacMessage.Performative.REGISTER
- and game.phase == Phase.GAME_REGISTRATION
- ):
- self._on_register(tac_message)
- elif (
- tac_message.performative == TacMessage.Performative.UNREGISTER
- and game.phase == Phase.GAME_REGISTRATION
- ):
- self._on_unregister(tac_message)
- elif (
- tac_message.performative == TacMessage.Performative.TRANSACTION
- and game.phase == Phase.GAME
- ):
- self._on_transaction(tac_message)
+ if tac_msg.performative == TacMessage.Performative.REGISTER:
+ self._on_register(tac_msg, tac_dialogue)
+ elif tac_msg.performative == TacMessage.Performative.UNREGISTER:
+ self._on_unregister(tac_msg, tac_dialogue)
+ elif tac_msg.performative == TacMessage.Performative.TRANSACTION:
+ self._on_transaction(tac_msg, tac_dialogue)
else:
+ self._handle_invalid(tac_msg, tac_dialogue)
+
self.context.logger.warning(
- "[{}]: TAC Message performative not recognized or not permitted.".format(
- self.context.agent_name
- )
+ "TAC Message performative not recognized or not permitted."
)
- def _on_register(self, message: TacMessage) -> None:
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
+
+ def _handle_unidentified_dialogue(self, tac_msg: TacMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param tac_msg: the message
+ """
+ self.context.logger.info(
+ "received invalid tac message={}, unidentified dialogue.".format(tac_msg)
+ )
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
+ default_msg = DefaultMessage(
+ performative=DefaultMessage.Performative.ERROR,
+ dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),
+ error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
+ error_msg="Invalid dialogue.",
+ error_data={"tac_message": tac_msg.encode()},
+ )
+ default_msg.counterparty = tac_msg.counterparty
+ default_dialogues.update(default_msg)
+ self.context.outbox.put_message(message=default_msg)
+
+ def _on_register(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
Handle a register message.
If the address is not registered, answer with an error message.
- :param message: the 'get agent state' TacMessage.
+ :param tac_msg: the tac message
+ :param tac_dialogue: the tac dialogue
:return: None
"""
+ game = cast(Game, self.context.game)
+ if not game.phase == Phase.GAME_REGISTRATION:
+ self.context.logger.warning(
+ "received registration outside of game registration phase: '{}'".format(
+ tac_msg
+ )
+ )
+ return
+
parameters = cast(Parameters, self.context.parameters)
- agent_name = message.agent_name
+ agent_name = tac_msg.agent_name
if len(parameters.whitelist) != 0 and agent_name not in parameters.whitelist:
self.context.logger.warning(
- "[{}]: Agent name not in whitelist: '{}'".format(
- self.context.agent_name, agent_name
- )
+ "agent name not in whitelist: '{}'".format(agent_name)
)
- tac_msg = TacMessage(
+ error_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
error_code=TacMessage.ErrorCode.AGENT_NAME_NOT_IN_WHITELIST,
)
- tac_msg.counterparty = message.counterparty
- self.context.outbox.put_message(message=tac_msg)
+ error_msg.counterparty = tac_msg.counterparty
+ self.context.outbox.put_message(message=error_msg)
return
game = cast(Game, self.context.game)
- if message.counterparty in game.registration.agent_addr_to_name:
+ if tac_msg.counterparty in game.registration.agent_addr_to_name:
self.context.logger.warning(
- "[{}]: Agent already registered: '{}'".format(
- self.context.agent_name,
- game.registration.agent_addr_to_name[message.counterparty],
+ "agent already registered: '{}'".format(
+ game.registration.agent_addr_to_name[tac_msg.counterparty],
)
)
- tac_msg = TacMessage(
+ error_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
error_code=TacMessage.ErrorCode.AGENT_ADDR_ALREADY_REGISTERED,
)
- tac_msg.counterparty = message.counterparty
- self.context.outbox.put_message(message=tac_msg)
+ error_msg.counterparty = tac_msg.counterparty
+ self.context.outbox.put_message(message=error_msg)
+ return
if agent_name in game.registration.agent_addr_to_name.values():
self.context.logger.warning(
- "[{}]: Agent with this name already registered: '{}'".format(
- self.context.agent_name, agent_name
- )
+ "agent with this name already registered: '{}'".format(agent_name)
)
- tac_msg = TacMessage(
+ error_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
error_code=TacMessage.ErrorCode.AGENT_NAME_ALREADY_REGISTERED,
)
- tac_msg.counterparty = message.counterparty
- self.context.outbox.put_message(message=tac_msg)
+ error_msg.counterparty = tac_msg.counterparty
+ self.context.outbox.put_message(message=error_msg)
+ return
- game.registration.register_agent(message.counterparty, agent_name)
- self.context.logger.info(
- "[{}]: Agent registered: '{}'".format(self.context.agent_name, agent_name)
- )
+ game.registration.register_agent(tac_msg.counterparty, agent_name)
+ self.context.logger.info("agent registered: '{}'".format(agent_name))
- def _on_unregister(self, message: TacMessage) -> None:
+ def _on_unregister(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
Handle a unregister message.
If the address is not registered, answer with an error message.
- :param message: the 'get agent state' TacMessage.
+ :param tac_msg: the tac message
+ :param tac_dialogue: the tac dialogue
:return: None
"""
game = cast(Game, self.context.game)
- if message.counterparty not in game.registration.agent_addr_to_name:
+ if not game.phase == Phase.GAME_REGISTRATION:
self.context.logger.warning(
- "[{}]: Agent not registered: '{}'".format(
- self.context.agent_name, message.counterparty
+ "received unregister outside of game registration phase: '{}'".format(
+ tac_msg
)
)
- tac_msg = TacMessage(
+ return
+
+ if tac_msg.counterparty not in game.registration.agent_addr_to_name:
+ self.context.logger.warning(
+ "agent not registered: '{}'".format(tac_msg.counterparty)
+ )
+ error_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
error_code=TacMessage.ErrorCode.AGENT_NOT_REGISTERED,
)
- tac_msg.counterparty = message.counterparty
- self.context.outbox.put_message(message=tac_msg)
+ error_msg.counterparty = tac_msg.counterparty
+ self.context.outbox.put_message(message=error_msg)
else:
self.context.logger.debug(
- "[{}]: Agent unregistered: '{}'".format(
- self.context.agent_name,
- game.conf.agent_addr_to_name[message.counterparty],
+ "agent unregistered: '{}'".format(
+ game.conf.agent_addr_to_name[tac_msg.counterparty],
)
)
- game.registration.unregister_agent(message.counterparty)
+ game.registration.unregister_agent(tac_msg.counterparty)
- def _on_transaction(self, message: TacMessage) -> None:
+ def _on_transaction(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
Handle a transaction TacMessage message.
If the transaction is invalid (e.g. because the state of the game are not consistent), reply with an error.
- :param message: the 'get agent state' TacMessage.
+ :param tac_msg: the tac message
+ :param tac_dialogue: the tac dialogue
:return: None
"""
- transaction = Transaction.from_message(message)
- self.context.logger.debug(
- "[{}]: Handling transaction: {}".format(
- self.context.agent_name, transaction
+ game = cast(Game, self.context.game)
+ if not game.phase == Phase.GAME:
+ self.context.logger.warning(
+ "received transaction outside of game phase: '{}'".format(tac_msg)
)
- )
+ return
+
+ transaction = Transaction.from_message(tac_msg)
+ self.context.logger.debug("handling transaction: {}".format(transaction))
game = cast(Game, self.context.game)
if game.is_transaction_valid(transaction):
- self._handle_valid_transaction(message, transaction)
+ self._handle_valid_transaction(tac_msg, transaction)
else:
- self._handle_invalid_transaction(message)
+ self._handle_invalid_transaction(tac_msg)
def _handle_valid_transaction(
- self, message: TacMessage, transaction: Transaction
+ self, tac_msg: TacMessage, transaction: Transaction
) -> None:
"""
Handle a valid transaction.
@@ -209,9 +255,7 @@ def _handle_valid_transaction(
"""
game = cast(Game, self.context.game)
self.context.logger.info(
- "[{}]: Handling valid transaction: {}".format(
- self.context.agent_name, transaction.id[-10:]
- )
+ "handling valid transaction: {}".format(transaction.id[-10:])
)
game.settle_transaction(transaction)
@@ -229,49 +273,46 @@ def _handle_valid_transaction(
amount_by_currency_id=transaction.amount_by_currency_id,
quantities_by_good_id=transaction.quantities_by_good_id,
)
- sender_tac_msg.counterparty = transaction.sender_addr
+ sender_tac_msg.counterparty = transaction.sender_address
self.context.outbox.put_message(message=sender_tac_msg)
- counterparty_tac_msg.counterparty = transaction.counterparty_addr
+ counterparty_tac_msg.counterparty = transaction.counterparty_address
self.context.outbox.put_message(message=counterparty_tac_msg)
# log messages
self.context.logger.info(
- "[{}]: Transaction '{}' settled successfully.".format(
- self.context.agent_name, transaction.id[-10:]
- )
- )
- self.context.logger.info(
- "[{}]: Current state:\n{}".format(
- self.context.agent_name, game.holdings_summary
- )
+ "transaction '{}' settled successfully.".format(transaction.id[-10:])
)
+ self.context.logger.info("current state:\n{}".format(game.holdings_summary))
- def _handle_invalid_transaction(self, message: TacMessage) -> None:
+ def _handle_invalid_transaction(self, tac_msg: TacMessage) -> None:
"""Handle an invalid transaction."""
- tx_id = message.tx_id[-10:]
self.context.logger.info(
- "[{}]: Handling invalid transaction: {}".format(
- self.context.agent_name, tx_id
- )
+ "handling invalid transaction: {}".format(tac_msg.transaction_id)
)
tac_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
error_code=TacMessage.ErrorCode.TRANSACTION_NOT_VALID,
- info={"transaction_id": message.tx_id},
+ info={"transaction_id": tac_msg.transaction_id},
)
- tac_msg.counterparty = message.counterparty
+ tac_msg.counterparty = tac_msg.counterparty
self.context.outbox.put_message(message=tac_msg)
- def teardown(self) -> None:
+ def _handle_invalid(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
- Implement the handler teardown.
+ Handle a tac message of invalid performative.
+ :param tac_msg: the message
+ :param tac_dialogue: the fipa dialogue
:return: None
"""
- pass
+ self.context.logger.warning(
+ "cannot handle tac message of performative={} in dialogue={}.".format(
+ tac_msg.performative, tac_dialogue
+ )
+ )
-class OEFRegistrationHandler(Handler):
+class OefSearchHandler(Handler):
"""Handle the message exchange with the OEF search node."""
SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id
@@ -291,40 +332,73 @@ def handle(self, message: Message) -> None:
:param message: the message
:return: None
"""
- oef_message = cast(OefSearchMessage, message)
+ oef_search_msg = cast(OefSearchMessage, message)
- self.context.logger.debug(
- "[{}]: Handling OEF message. performative={}".format(
- self.context.agent_name, oef_message.performative
- )
+ # recover dialogue
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)
)
- if oef_message.performative == OefSearchMessage.Performative.OEF_ERROR:
- self._on_oef_error(oef_message)
+ if oef_search_dialogue is None:
+ self._handle_unidentified_dialogue(oef_search_msg)
+ return
+
+ # handle message
+ if oef_search_msg.performative is OefSearchMessage.Performative.OEF_ERROR:
+ self._handle_error(oef_search_msg, oef_search_dialogue)
else:
- self.context.logger.warning(
- "[{}]: OEF Message type not recognized.".format(self.context.agent_name)
- )
+ self._handle_invalid(oef_search_msg, oef_search_dialogue)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
- def _on_oef_error(self, oef_error: OefSearchMessage) -> None:
+ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:
"""
- Handle an OEF error message.
+ Handle an unidentified dialogue.
+
+ :param msg: the message
+ """
+ self.context.logger.info(
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
+ )
+ )
- :param oef_error: the oef error
+ def _handle_error(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
:return: None
"""
- self.context.logger.warning(
- "[{}]: Received OEF Search error: dialogue_reference={}, oef_error_operation={}".format(
- self.context.agent_name,
- oef_error.dialogue_reference,
- oef_error.oef_error_operation,
+ self.context.logger.info(
+ "received oef_search error message={} in dialogue={}.".format(
+ oef_search_msg, oef_search_dialogue
)
)
- def teardown(self) -> None:
+ def _handle_invalid(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
"""
- Implement the handler teardown.
+ Handle an oef search message.
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
:return: None
"""
- pass
+ self.context.logger.warning(
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
+ )
+ )
diff --git a/packages/fetchai/skills/tac_control/helpers.py b/packages/fetchai/skills/tac_control/helpers.py
index 2fa07b57bc..8758272cf3 100644
--- a/packages/fetchai/skills/tac_control/helpers.py
+++ b/packages/fetchai/skills/tac_control/helpers.py
@@ -20,17 +20,12 @@
"""This module contains the helpers methods for the controller agent."""
-import collections
import math
import random
from typing import Dict, List, Tuple, cast
import numpy as np
-from web3 import Web3 # pylint: disable=wrong-import-order
-
-from aea.mail.base import Address
-
QUANTITY_SHIFT = 1 # Any non-negative integer is fine.
DEFAULT_CURRENCY_ID_TO_NAME = {"0": "FET"}
@@ -282,98 +277,3 @@ def generate_equilibrium_prices_and_holdings(
)
}
return eq_prices_dict, eq_good_holdings_dict, eq_currency_holdings_dict
-
-
-def _get_hash(
- tx_sender_addr: Address,
- tx_counterparty_addr: Address,
- good_ids: List[int],
- sender_supplied_quantities: List[int],
- counterparty_supplied_quantities: List[int],
- tx_amount: int,
- tx_nonce: int,
-) -> bytes:
- """
- Generate a hash from transaction information.
-
- :param tx_sender_addr: the sender address
- :param tx_counterparty_addr: the counterparty address
- :param good_ids: the list of good ids
- :param sender_supplied_quantities: the quantities supplied by the sender (must all be positive)
- :param counterparty_supplied_quantities: the quantities supplied by the counterparty (must all be positive)
- :param tx_amount: the amount of the transaction
- :param tx_nonce: the nonce of the transaction
- :return: the hash
- """
- aggregate_hash = Web3.keccak(
- b"".join(
- [
- good_ids[0].to_bytes(32, "big"),
- sender_supplied_quantities[0].to_bytes(32, "big"),
- counterparty_supplied_quantities[0].to_bytes(32, "big"),
- ]
- )
- )
- for idx, good_id in enumerate(good_ids):
- if not idx == 0:
- aggregate_hash = Web3.keccak(
- b"".join(
- [
- aggregate_hash,
- good_id.to_bytes(32, "big"),
- sender_supplied_quantities[idx].to_bytes(32, "big"),
- counterparty_supplied_quantities[idx].to_bytes(32, "big"),
- ]
- )
- )
-
- m_list = [] # type: List[bytes]
- m_list.append(tx_sender_addr.encode("utf-8"))
- m_list.append(tx_counterparty_addr.encode("utf-8"))
- m_list.append(aggregate_hash)
- m_list.append(tx_amount.to_bytes(32, "big"))
- m_list.append(tx_nonce.to_bytes(32, "big"))
- return Web3.keccak(b"".join(m_list))
-
-
-def tx_hash_from_values(
- tx_sender_addr: str,
- tx_counterparty_addr: str,
- tx_quantities_by_good_id: Dict[str, int],
- tx_amount_by_currency_id: Dict[str, int],
- tx_nonce: int,
-) -> bytes:
- """
- Get the hash for a transaction based on the transaction message.
-
- :param tx_message: the transaction message
- :return: the hash
- """
- _tx_quantities_by_good_id = {
- int(good_id): quantity for good_id, quantity in tx_quantities_by_good_id.items()
- } # type: Dict[int, int]
- ordered = collections.OrderedDict(sorted(_tx_quantities_by_good_id.items()))
- good_uids = [] # type: List[int]
- sender_supplied_quantities = [] # type: List[int]
- counterparty_supplied_quantities = [] # type: List[int]
- for good_uid, quantity in ordered.items():
- good_uids.append(good_uid)
- if quantity >= 0:
- sender_supplied_quantities.append(quantity)
- counterparty_supplied_quantities.append(0)
- else:
- sender_supplied_quantities.append(0)
- counterparty_supplied_quantities.append(-quantity)
- assert len(tx_amount_by_currency_id) == 1
- for amount in tx_amount_by_currency_id.values():
- tx_amount = amount if amount >= 0 else 0
- tx_hash = _get_hash(
- tx_sender_addr=tx_sender_addr,
- tx_counterparty_addr=tx_counterparty_addr,
- good_ids=good_uids,
- sender_supplied_quantities=sender_supplied_quantities,
- counterparty_supplied_quantities=counterparty_supplied_quantities,
- tx_amount=tx_amount,
- tx_nonce=tx_nonce,
- )
- return tx_hash
diff --git a/packages/fetchai/skills/tac_control/parameters.py b/packages/fetchai/skills/tac_control/parameters.py
index ff8f8be2ad..1e646c2644 100644
--- a/packages/fetchai/skills/tac_control/parameters.py
+++ b/packages/fetchai/skills/tac_control/parameters.py
@@ -20,10 +20,14 @@
"""This package contains a class representing the game parameters."""
import datetime
-from typing import Set
+from typing import Dict, Set
+from aea.helpers.search.models import Location
from aea.skills.base import Model
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SERVICE_DATA = {"key": "tac", "value": "v1"}
+
class Parameters(Model):
"""This class contains the parameters of the game."""
@@ -45,22 +49,38 @@ def __init__(self, **kwargs):
self._competition_timeout = kwargs.pop("competition_timeout", 20) # type: int
self._inactivity_timeout = kwargs.pop("inactivity_timeout", 10) # type: int
self._whitelist = set(kwargs.pop("whitelist", [])) # type: Set[str]
- self._version_id = kwargs.pop("version_id", "v1") # type: str
+ self._location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._service_data = kwargs.pop("service_data", DEFAULT_SERVICE_DATA)
+ assert (
+ len(self._service_data) == 2
+ and "key" in self._service_data
+ and "value" in self._service_data
+ ), "service_data must contain keys `key` and `value`"
+ self._version_id = self._service_data["value"] # type: str
+
+ self._agent_location = {
+ "location": Location(
+ self._location["longitude"], self._location["latitude"]
+ )
+ }
+ self._set_service_data = self._service_data
+ self._remove_service_data = {"key": self._service_data["key"]}
+ self._simple_service_data = {
+ self._service_data["key"]: self._service_data["value"]
+ }
+
super().__init__(**kwargs)
now = datetime.datetime.now()
if now > self.registration_start_time:
self.context.logger.warning(
- "[{}]: TAC registration start time {} is in the past!".format(
- self.context.agent_name, self.registration_start_time
+ "TAC registration start time {} is in the past!".format(
+ self.registration_start_time
)
)
else:
self.context.logger.info(
- "[{}]: TAC registation start time: {}, and start time: {}, and end time: {}".format(
- self.context.agent_name,
- self.registration_start_time,
- self.start_time,
- self.end_time,
+ "TAC registation start time: {}, and start time: {}, and end time: {}".format(
+ self.registration_start_time, self.start_time, self.end_time,
)
)
@@ -128,3 +148,23 @@ def whitelist(self) -> Set[str]:
def version_id(self) -> str:
"""Version id."""
return self._version_id
+
+ @property
+ def agent_location(self) -> Dict[str, Location]:
+ """Get the agent location."""
+ return self._agent_location
+
+ @property
+ def set_service_data(self) -> Dict[str, str]:
+ """Get the set service data."""
+ return self._set_service_data
+
+ @property
+ def remove_service_data(self) -> Dict[str, str]:
+ """Get the remove service data."""
+ return self._remove_service_data
+
+ @property
+ def simple_service_data(self) -> Dict[str, str]:
+ """Get the simple service data."""
+ return self._simple_service_data
diff --git a/packages/fetchai/skills/tac_control/skill.yaml b/packages/fetchai/skills/tac_control/skill.yaml
index 554d450d2f..32c823c2f8 100644
--- a/packages/fetchai/skills/tac_control/skill.yaml
+++ b/packages/fetchai/skills/tac_control/skill.yaml
@@ -1,55 +1,68 @@
name: tac_control
author: fetchai
-version: 0.3.0
+version: 0.4.0
description: The tac control skill implements the logic for an AEA to control an instance
of the TAC.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: Qme9YfgfPXymvupw1EHMJWGUSMTT6JQZxk2qaeKE76pgyN
- behaviours.py: Qmcb6RPGT6x5aupA4m95nAFXJioUNjQersWfaAApL83GEA
- game.py: QmRM1gtNS9aiLwHUa3WKSLVm3hbXRsnBYr93tZF4bSm4mf
- handlers.py: QmRvgtFvtMsNeTUoKLSeap9efQpohySi4X6UJXDhXVv8Xx
- helpers.py: QmT8vvpwxA9rUNX7Xdob4ZNXYXG8LW8nhFfyeV5dUbAFbB
- parameters.py: QmSmR8PycMvfB9omUz7nzZZXqwFkSZMDTb8pBZrntfDPre
+ behaviours.py: QmeJhvrP7GhLPLpQVFHeyXFiaGdcTzF9Cwe8BUZS1SuRbB
+ dialogues.py: QmYYvm4fKUxceKc9CzkZXKZbmRegoVdBFkXqAj5YhKN8eb
+ game.py: QmXmGh6nBzbMSUjJqpJxbtVCm8Sn7EqQhyE9Wf6evYRekS
+ handlers.py: Qme9aCQDrzLT47GdnkAEj7decZsYpVNo3ZR7eg25Y6nMTz
+ helpers.py: QmdhGNhBwn5Zn4yacQEo3EAU74kSkhMR7icvPoj6ZVAJfV
+ parameters.py: QmR7EcnmmQstPKwpT7D5HjbfqWYN7cNEYsKWUE5Dvgn1LG
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills: []
behaviours:
tac:
args: {}
- class_name: TACBehaviour
+ class_name: TacBehaviour
handlers:
oef:
args: {}
- class_name: OEFRegistrationHandler
+ class_name: OefSearchHandler
tac:
args: {}
- class_name: TACHandler
+ class_name: TacHandler
models:
+ default_dialogues:
+ args: {}
+ class_name: DefaultDialogues
game:
args: {}
class_name: Game
+ oef_search_dialogues:
+ args: {}
+ class_name: OefSearchDialogues
parameters:
args:
base_good_endowment: 2
competition_timeout: 180
inactivity_timeout: 60
+ location:
+ latitude: 0.127
+ longitude: 51.5194
lower_bound_factor: 1
min_nb_agents: 2
money_endowment: 2000000
nb_goods: 10
registration_timeout: 60
+ service_data:
+ key: tac
+ value: v1
start_time: 01 01 2020 00:01
tx_fee: 1
upper_bound_factor: 1
- version_id: v1
whitelist: []
class_name: Parameters
+ tac_dialogues:
+ args: {}
+ class_name: TacDialogues
dependencies:
numpy: {}
- web3:
- version: ==5.2.2
diff --git a/packages/fetchai/skills/tac_control_contract/behaviours.py b/packages/fetchai/skills/tac_control_contract/behaviours.py
index 31552601cb..edc0b3672a 100644
--- a/packages/fetchai/skills/tac_control_contract/behaviours.py
+++ b/packages/fetchai/skills/tac_control_contract/behaviours.py
@@ -94,11 +94,7 @@ def _deploy_contract(
"""Send deploy contract tx msg to decision maker."""
game = cast(Game, self.context.game)
game.phase = Phase.CONTRACT_DEPLOYMENT_PROPOSAL
- self.context.logger.info(
- "[{}]: Sending deploy transaction to decision maker.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending deploy transaction to decision maker.")
# request deploy tx
# contract.set_instance(ledger_api)
# transaction_message = contract.get_deploy_transaction_msg(
@@ -131,16 +127,12 @@ def act(self) -> None:
game.phase.value == Phase.GAME_REGISTRATION.value
and parameters.registration_end_time < now < parameters.start_time
):
- self.context.logger.info(
- "[{}] Closing registration!".format(self.context.agent_name)
- )
+ self.context.logger.info("closing registration!")
if game.registration.nb_agents < parameters.min_nb_agents:
game.phase = Phase.CANCELLED_GAME
self.context.logger.info(
- "[{}]: Registered agents={}, minimum agents required={}".format(
- self.context.agent_name,
- game.registration.nb_agents,
- parameters.min_nb_agents,
+ "registered agents={}, minimum agents required={}".format(
+ game.registration.nb_agents, parameters.min_nb_agents,
)
)
self._end_tac(game, "cancelled")
@@ -190,9 +182,7 @@ def _register_tac(self, parameters) -> None:
desc = Description(
{"version": parameters.version_id}, data_model=CONTROLLER_DATAMODEL,
)
- self.context.logger.info(
- "[{}]: Registering TAC data model".format(self.context.agent_name)
- )
+ self.context.logger.info("registering TAC data model")
oef_msg = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
dialogue_reference=(str(self._oef_msg_id), ""),
@@ -202,8 +192,8 @@ def _register_tac(self, parameters) -> None:
self.context.outbox.put_message(message=oef_msg)
self._registered_desc = desc
self.context.logger.info(
- "[{}]: TAC open for registration until: {}".format(
- self.context.agent_name, parameters.registration_end_time
+ "TAC open for registration until: {}".format(
+ parameters.registration_end_time
)
)
@@ -215,9 +205,7 @@ def _unregister_tac(self) -> None:
"""
if self._registered_desc is not None:
self._oef_msg_id += 1
- self.context.logger.info(
- "[{}]: Unregistering TAC data model".format(self.context.agent_name)
- )
+ self.context.logger.info("unregistering TAC data model")
oef_msg = OefSearchMessage(
performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
dialogue_reference=(str(self._oef_msg_id), ""),
@@ -231,11 +219,7 @@ def _create_items(
self, game: Game, ledger_api: LedgerApi, contract: ERC1155Contract
) -> None:
"""Send create items transaction to decision maker."""
- self.context.logger.info(
- "[{}]: Sending create_items transaction to decision maker.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending create_items transaction to decision maker.")
tx_msg = self._get_create_items_tx_msg( # pylint: disable=assignment-from-none
game.conf, ledger_api, contract
)
@@ -245,11 +229,7 @@ def _mint_items(
self, game: Game, ledger_api: LedgerApi, contract: ERC1155Contract
) -> None:
"""Send mint items transactions to decision maker."""
- self.context.logger.info(
- "[{}]: Sending mint_items transactions to decision maker.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending mint_items transactions to decision maker.")
for agent_state in game.initial_agent_states.values():
tx_msg = self._get_mint_goods_and_currency_tx_msg( # pylint: disable=assignment-from-none
agent_state, ledger_api, contract
@@ -259,14 +239,10 @@ def _mint_items(
def _start_tac(self, game: Game) -> None:
"""Create a game and send the game configuration to every registered agent."""
self.context.logger.info(
- "[{}]: Starting competition with configuration:\n{}".format(
- self.context.agent_name, game.holdings_summary
- )
+ "starting competition with configuration:\n{}".format(game.holdings_summary)
)
self.context.logger.info(
- "[{}]: Computed theoretical equilibrium:\n{}".format(
- self.context.agent_name, game.equilibrium_summary
- )
+ "computed theoretical equilibrium:\n{}".format(game.equilibrium_summary)
)
for agent_address in game.conf.agent_addr_to_name.keys():
agent_state = game.current_agent_states[agent_address]
@@ -284,23 +260,15 @@ def _start_tac(self, game: Game) -> None:
info={"contract_address": game.conf.contract_address},
)
self.context.logger.debug(
- "[{}]: sending game data to '{}'.".format(
- self.context.agent_name, agent_address
- )
- )
- self.context.logger.debug(
- "[{}]: game data={}".format(self.context.agent_name, str(tac_msg))
+ "sending game data to '{}'.".format(agent_address)
)
+ self.context.logger.debug("game data={}".format(str(tac_msg)))
tac_msg.counterparty = agent_address
self.context.outbox.put_message(message=tac_msg)
def _end_tac(self, game: Game, reason: str) -> None:
"""Notify agents that the TAC is cancelled."""
- self.context.logger.info(
- "[{}]: Notifying agents that TAC is {}.".format(
- self.context.agent_name, reason
- )
- )
+ self.context.logger.info("notifying agents that TAC is {}.".format(reason))
for agent_addr in game.registration.agent_addr_to_name.keys():
tac_msg = TacMessage(performative=TacMessage.Performative.CANCELLED)
tac_msg.counterparty = agent_addr
@@ -309,14 +277,10 @@ def _end_tac(self, game: Game, reason: str) -> None:
def _game_finished_summary(self, game: Game) -> None:
"""Provide summary of game stats."""
self.context.logger.info(
- "[{}]: Finished competition:\n{}".format(
- self.context.agent_name, game.holdings_summary
- )
+ "finished competition:\n{}".format(game.holdings_summary)
)
self.context.logger.info(
- "[{}]: Computed equilibrium:\n{}".format(
- self.context.agent_name, game.equilibrium_summary
- )
+ "computed equilibrium:\n{}".format(game.equilibrium_summary)
)
def _get_create_items_tx_msg( # pylint: disable=no-self-use
@@ -379,23 +343,19 @@ def act(self) -> None:
)
if tx_receipt is None:
self.context.logger.info(
- "[{}]: Cannot verify whether contract deployment was successful. Retrying...".format(
- self.context.agent_name
- )
+ "cannot verify whether contract deployment was successful. Retrying..."
)
elif tx_receipt.status != 1:
self.context.is_active = False
self.context.warning(
- "[{}]: The contract did not deployed successfully. Transaction hash: {}. Aborting!".format(
- self.context.agent_name, tx_receipt.transactionHash.hex()
+ "the contract did not deployed successfully. Transaction hash: {}. Aborting!".format(
+ tx_receipt.transactionHash.hex()
)
)
else:
self.context.logger.info(
- "[{}]: The contract was successfully deployed. Contract address: {}. Transaction hash: {}".format(
- self.context.agent_name,
- tx_receipt.contractAddress,
- tx_receipt.transactionHash.hex(),
+ "the contract was successfully deployed. Contract address: {}. Transaction hash: {}".format(
+ tx_receipt.contractAddress, tx_receipt.transactionHash.hex(),
)
)
configuration = Configuration(parameters.version_id, parameters.tx_fee,)
@@ -414,21 +374,19 @@ def act(self) -> None:
)
if tx_receipt is None:
self.context.logger.info(
- "[{}]: Cannot verify whether token creation was successful. Retrying...".format(
- self.context.agent_name
- )
+ "cannot verify whether token creation was successful. Retrying..."
)
elif tx_receipt.status != 1:
self.context.is_active = False
self.context.warning(
- "[{}]: The token creation wasn't successful. Transaction hash: {}. Aborting!".format(
- self.context.agent_name, tx_receipt.transactionHash.hex()
+ "the token creation wasn't successful. Transaction hash: {}. Aborting!".format(
+ tx_receipt.transactionHash.hex()
)
)
else:
self.context.logger.info(
- "[{}]: Successfully created the tokens. Transaction hash: {}".format(
- self.context.agent_name, tx_receipt.transactionHash.hex()
+ "successfully created the tokens. Transaction hash: {}".format(
+ tx_receipt.transactionHash.hex()
)
)
game.phase = Phase.TOKENS_CREATED
@@ -442,25 +400,21 @@ def act(self) -> None:
tx_receipt = ledger_api.get_transaction_receipt(tx_digest=tx_digest)
if tx_receipt is None:
self.context.logger.info(
- "[{}]: Cannot verify whether token minting for agent_addr={} was successful. Retrying...".format(
- self.context.agent_name, agent_addr
+ "cannot verify whether token minting for agent_addr={} was successful. Retrying...".format(
+ agent_addr
)
)
elif tx_receipt.status != 1:
self.context.is_active = False
self.context.logger.warning(
- "[{}]: The token minting for agent_addr={} wasn't successful. Transaction hash: {}. Aborting!".format(
- self.context.agent_name,
- agent_addr,
- tx_receipt.transactionHash.hex(),
+ "the token minting for agent_addr={} wasn't successful. Transaction hash: {}. Aborting!".format(
+ agent_addr, tx_receipt.transactionHash.hex(),
)
)
else:
self.context.logger.info(
- "[{}]: Successfully minted the tokens for agent_addr={}. Transaction hash: {}".format(
- self.context.agent_name,
- agent_addr,
- tx_receipt.transactionHash.hex(),
+ "successfully minted the tokens for agent_addr={}. Transaction hash: {}".format(
+ agent_addr, tx_receipt.transactionHash.hex(),
)
)
game.contract_manager.add_confirmed_mint_tokens_agents(agent_addr)
diff --git a/packages/fetchai/skills/tac_control_contract/game.py b/packages/fetchai/skills/tac_control_contract/game.py
index 84b0226634..34e6c5b963 100644
--- a/packages/fetchai/skills/tac_control_contract/game.py
+++ b/packages/fetchai/skills/tac_control_contract/game.py
@@ -29,6 +29,7 @@
linear_utility,
logarithmic_utility,
)
+from aea.helpers.transaction.base import Terms
from aea.mail.base import Address
from aea.skills.base import Model
@@ -288,88 +289,50 @@ def _check_consistency(self):
), "Dimensions for utility_params and good_endowments rows must be the same."
-class Transaction:
+class Transaction(Terms):
"""Convenience representation of a transaction."""
def __init__(
self,
- transaction_id: TransactionId,
- sender_addr: Address,
- counterparty_addr: Address,
+ ledger_id: str,
+ sender_address: Address,
+ counterparty_address: Address,
amount_by_currency_id: Dict[str, int],
- sender_fee: int,
- counterparty_fee: int,
quantities_by_good_id: Dict[str, int],
- nonce: int,
+ is_sender_payable_tx_fee: bool,
+ nonce: str,
+ fee_by_currency_id: Optional[Dict[str, int]],
sender_signature: str,
counterparty_signature: str,
) -> None:
"""
- Instantiate transaction request.
-
- :param transaction_id: the id of the transaction.
- :param sender_addr: the sender of the transaction.
- :param tx_counterparty_addr: the counterparty of the transaction.
- :param amount_by_currency_id: the currency used.
- :param sender_fee: the transaction fee covered by the sender.
- :param counterparty_fee: the transaction fee covered by the counterparty.
- :param quantities_by_good_id: a map from good pbk to the quantity of that good involved in the transaction.
- :param nonce: the nonce of the transaction
- :param sender_signature: the signature of the transaction sender
- :param counterparty_signature: the signature of the transaction counterparty
- :return: None
- """
- self._id = transaction_id
- self._sender_addr = sender_addr
- self._counterparty_addr = counterparty_addr
- self._amount_by_currency_id = amount_by_currency_id
- self._sender_fee = sender_fee
- self._counterparty_fee = counterparty_fee
- self._quantities_by_good_id = quantities_by_good_id
- self._nonce = nonce
+ Instantiate transaction.
+
+ This extends a terms object to be used as a transaction.
+
+ :param ledger_id: the ledger on which the terms are to be settled.
+ :param sender_address: the sender address of the transaction.
+ :param counterparty_address: the counterparty address of the transaction.
+ :param amount_by_currency_id: the amount by the currency of the transaction.
+ :param quantities_by_good_id: a map from good id to the quantity of that good involved in the transaction.
+ :param is_sender_payable_tx_fee: whether the sender or counterparty pays the tx fee.
+ :param nonce: nonce to be included in transaction to discriminate otherwise identical transactions.
+ :param fee_by_currency_id: the fee associated with the transaction.
+ :param sender_signature: the signature of the terms by the sender.
+ :param counterparty_signature: the signature of the terms by the counterparty.
+ """
+ super().__init__(
+ ledger_id=ledger_id,
+ sender_address=sender_address,
+ counterparty_address=counterparty_address,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ fee_by_currency_id=fee_by_currency_id,
+ )
self._sender_signature = sender_signature
self._counterparty_signature = counterparty_signature
- self._check_consistency()
-
- @property
- def id(self) -> str:
- """Get the transaction id."""
- return self._id
-
- @property
- def sender_addr(self) -> Address:
- """Get the sender address."""
- return self._sender_addr
-
- @property
- def counterparty_addr(self) -> Address:
- """Get the counterparty address."""
- return self._counterparty_addr
-
- @property
- def amount_by_currency_id(self) -> Dict[CurrencyId, Quantity]:
- """Get the amount for each currency."""
- return copy.copy(self._amount_by_currency_id)
-
- @property
- def sender_fee(self) -> int:
- """Get the sender fee."""
- return self._sender_fee
-
- @property
- def counterparty_fee(self) -> int:
- """Get the counterparty fee."""
- return self._counterparty_fee
-
- @property
- def quantities_by_good_id(self) -> Dict[GoodId, Quantity]:
- """Get the quantities by good_id."""
- return copy.copy(self._quantities_by_good_id)
-
- @property
- def nonce(self) -> int:
- """Get the nonce of the transaction."""
- return self._nonce
@property
def sender_signature(self) -> str:
@@ -381,68 +344,6 @@ def counterparty_signature(self) -> str:
"""Get the counterparty signature."""
return self._counterparty_signature
- @property
- def is_sender_buyer(self) -> bool:
- """Get the sender is buyer status."""
- return all(value <= 0 for value in self.amount_by_currency_id.values())
-
- @property
- def buyer_addr(self) -> Address:
- """Get the buyer address."""
- return self._sender_addr if self.is_sender_buyer else self._counterparty_addr
-
- @property
- def amount(self) -> int:
- """Get the amount."""
- return list(self.amount_by_currency_id.values())[0]
-
- @property
- def currency_id(self) -> str:
- """Get the currency id."""
- return list(self.amount_by_currency_id.keys())[0]
-
- @property
- def sender_amount(self) -> int:
- """Get the amount the sender gets/pays."""
- return self.amount - self.sender_fee
-
- @property
- def counterparty_amount(self) -> int:
- """Get the amount the counterparty gets/pays."""
- return -self.amount - self.counterparty_fee
-
- def _check_consistency(self) -> None:
- """
- Check the consistency of the transaction parameters.
-
- :return: None
- :raises AssertionError if some constraint is not satisfied.
- """
- assert self.sender_addr != self.counterparty_addr
- assert (
- len(self.amount_by_currency_id.keys()) == 1
- ) # For now we restrict to one currency per transaction.
- assert self.sender_fee >= 0
- assert self.counterparty_fee >= 0
- assert (
- self.amount >= 0
- and all(quantity <= 0 for quantity in self.quantities_by_good_id.values())
- ) or (
- self.amount <= 0
- and all(quantity >= 0 for quantity in self.quantities_by_good_id.values())
- )
- assert isinstance(self.sender_signature, str) and isinstance(
- self.counterparty_signature, str
- )
- if self.amount >= 0:
- assert (
- self.sender_amount >= 0
- ), "Sender_amount must be positive when the sender is the payment receiver."
- else:
- assert (
- self.counterparty_amount >= 0
- ), "Counterparty_amount must be positive when the counterpary is the payment receiver."
-
@classmethod
def from_message(cls, message: TacMessage) -> "Transaction":
"""
@@ -451,32 +352,31 @@ def from_message(cls, message: TacMessage) -> "Transaction":
:param message: the message
:return: Transaction
"""
- assert message.performative == TacMessage.Performative.TRANSACTION
- return Transaction(
- message.tx_id,
- message.tx_sender_addr,
- message.tx_counterparty_addr,
- message.amount_by_currency_id,
- message.tx_sender_fee,
- message.tx_counterparty_fee,
- message.quantities_by_good_id,
- message.tx_nonce,
- message.tx_sender_signature,
- message.tx_counterparty_signature,
+ assert (
+ message.performative == TacMessage.Performative.TRANSACTION
+ ), "Wrong performative"
+ transaction = Transaction(
+ ledger_id=message.ledger_id,
+ sender_address=message.sender_address,
+ counterparty_address=message.counterparty_address,
+ amount_by_currency_id=message.amount_by_currency_id,
+ fee_by_currency_id=message.fee_by_currency_id,
+ quantities_by_good_id=message.quantities_by_good_id,
+ is_sender_payable_tx_fee=True, # TODO: check
+ nonce=str(message.nonce),
+ sender_signature=message.sender_signature,
+ counterparty_signature=message.counterparty_signature,
)
+ assert (
+ transaction.id == message.transaction_id
+ ), "Transaction content does not match hash."
+ return transaction
def __eq__(self, other):
"""Compare to another object."""
return (
isinstance(other, Transaction)
- and self.id == other.id
- and self.sender_addr == other.sender_addr
- and self.counterparty_addr == other.counterparty_addr
- and self.amount_by_currency_id == other.amount_by_currency_id
- and self.sender_fee == other.sender_fee
- and self.counterparty_fee == other.counterparty_fee
- and self.quantities_by_good_id == other.quantities_by_good_id
- and self.nonce == other.nonce
+ and super.__eq__()
and self.sender_signature == other.sender_signature
and self.counterparty_signature == other.counterparty_signature
)
@@ -564,42 +464,47 @@ def is_consistent_transaction(self, tx: Transaction) -> bool:
or enough holdings if it is a seller.
:return: True if the transaction is legal wrt the current state, False otherwise.
"""
- result = self.agent_address in [tx.sender_addr, tx.counterparty_addr]
- if tx.amount == 0 and all(
+ result = self.agent_address in [tx.sender_address, tx.counterparty_address]
+ result = result and tx.is_single_currency
+ if not result:
+ return result
+ if all(amount == 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity == 0 for quantity in tx.quantities_by_good_id.values()
):
# reject the transaction when there is no wealth exchange
result = False
- elif tx.amount <= 0 and all(
+ elif all(amount <= 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity >= 0 for quantity in tx.quantities_by_good_id.values()
):
# sender is buyer, counterparty is seller
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# check this sender state has enough money
result = result and (
- self.amount_by_currency_id[tx.currency_id] >= tx.sender_amount
+ self.amount_by_currency_id[tx.currency_id]
+ >= tx.sender_payable_amount
)
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
# check this counterparty state has enough goods
result = result and all(
self.quantities_by_good_id[good_id] >= quantity
for good_id, quantity in tx.quantities_by_good_id.items()
)
- elif tx.amount >= 0 and all(
+ elif all(amount >= 0 for amount in tx.amount_by_currency_id.values()) and all(
quantity <= 0 for quantity in tx.quantities_by_good_id.values()
):
# sender is seller, counterparty is buyer
# Note, on a ledger, this atomic swap would only be possible for amount == 0!
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# check this sender state has enough goods
result = result and all(
self.quantities_by_good_id[good_id] >= -quantity
for good_id, quantity in tx.quantities_by_good_id.items()
)
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
# check this counterparty state has enough money
result = result and (
- self.amount_by_currency_id[tx.currency_id] >= tx.counterparty_amount
+ self.amount_by_currency_id[tx.currency_id]
+ >= tx.counterparty_payable_amount
)
else:
result = False
@@ -628,20 +533,22 @@ def update(self, tx: Transaction) -> None:
assert self.is_consistent_transaction(tx), "Inconsistent transaction."
new_amount_by_currency_id = self.amount_by_currency_id
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
# settling the transaction for the sender
- new_amount_by_currency_id[tx.currency_id] += tx.sender_amount
- elif self.agent_address == tx.counterparty_addr:
+ for currency_id, amount in tx.amount_by_currency_id.items():
+ new_amount_by_currency_id[currency_id] += amount
+ elif self.agent_address == tx.counterparty_address:
# settling the transaction for the counterparty
- new_amount_by_currency_id[tx.currency_id] += tx.counterparty_amount
+ for currency_id, amount in tx.amount_by_currency_id.items():
+ new_amount_by_currency_id[currency_id] += amount
self._amount_by_currency_id = new_amount_by_currency_id
new_quantities_by_good_id = self.quantities_by_good_id
for good_id, quantity in tx.quantities_by_good_id.items():
- if self.agent_address == tx.sender_addr:
+ if self.agent_address == tx.sender_address:
new_quantities_by_good_id[good_id] += quantity
- elif self.agent_address == tx.counterparty_addr:
+ elif self.agent_address == tx.counterparty_address:
new_quantities_by_good_id[good_id] -= quantity
self._quantities_by_good_id = new_quantities_by_good_id
@@ -713,12 +620,12 @@ def add(self, transaction: Transaction) -> None:
"""
now = datetime.datetime.now()
self._confirmed[now] = transaction
- if self._confirmed_per_agent.get(transaction.sender_addr) is None:
- self._confirmed_per_agent[transaction.sender_addr] = {}
- self._confirmed_per_agent[transaction.sender_addr][now] = transaction
- if self._confirmed_per_agent.get(transaction.counterparty_addr) is None:
- self._confirmed_per_agent[transaction.counterparty_addr] = {}
- self._confirmed_per_agent[transaction.counterparty_addr][now] = transaction
+ if self._confirmed_per_agent.get(transaction.sender_address) is None:
+ self._confirmed_per_agent[transaction.sender_address] = {}
+ self._confirmed_per_agent[transaction.sender_address][now] = transaction
+ if self._confirmed_per_agent.get(transaction.counterparty_address) is None:
+ self._confirmed_per_agent[transaction.counterparty_address] = {}
+ self._confirmed_per_agent[transaction.counterparty_address][now] = transaction
class Registration:
@@ -908,9 +815,7 @@ def transactions(self) -> Transactions:
def create(self):
"""Create a game."""
assert self.phase.value == Phase.GAME_SETUP.value, "Wrong game phase."
- self.context.logger.info(
- "[{}]: Setting Up the TAC game.".format(self.context.agent_name)
- )
+ self.context.logger.info("setting Up the TAC game.")
self._generate()
def _generate(self):
diff --git a/packages/fetchai/skills/tac_control_contract/handlers.py b/packages/fetchai/skills/tac_control_contract/handlers.py
index c0bc0da724..a9079380d8 100644
--- a/packages/fetchai/skills/tac_control_contract/handlers.py
+++ b/packages/fetchai/skills/tac_control_contract/handlers.py
@@ -57,9 +57,7 @@ def handle(self, message: Message) -> None:
game = cast(Game, self.context.game)
self.context.logger.debug(
- "[{}]: Handling TAC message. type={}".format(
- self.context.agent_name, tac_message.performative
- )
+ "handling TAC message. type={}".format(tac_message.performative)
)
if (
tac_message.performative == TacMessage.Performative.REGISTER
@@ -73,9 +71,7 @@ def handle(self, message: Message) -> None:
self._on_unregister(tac_message)
else:
self.context.logger.warning(
- "[{}]: TAC Message type not recognized or not permitted.".format(
- self.context.agent_name
- )
+ "TAC Message type not recognized or not permitted."
)
def _on_register(self, message: TacMessage) -> None:
@@ -91,9 +87,7 @@ def _on_register(self, message: TacMessage) -> None:
agent_name = message.agent_name
if len(parameters.whitelist) != 0 and agent_name not in parameters.whitelist:
self.context.logger.warning(
- "[{}]: Agent name not in whitelist: '{}'".format(
- self.context.agent_name, agent_name
- )
+ "agent name not in whitelist: '{}'".format(agent_name)
)
tac_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
@@ -106,8 +100,7 @@ def _on_register(self, message: TacMessage) -> None:
game = cast(Game, self.context.game)
if message.counterparty in game.registration.agent_addr_to_name:
self.context.logger.warning(
- "[{}]: Agent already registered: '{}'".format(
- self.context.agent_name,
+ "agent already registered: '{}'".format(
game.registration.agent_addr_to_name[message.counterparty],
)
)
@@ -120,9 +113,7 @@ def _on_register(self, message: TacMessage) -> None:
if agent_name in game.registration.agent_addr_to_name.values():
self.context.logger.warning(
- "[{}]: Agent with this name already registered: '{}'".format(
- self.context.agent_name, agent_name
- )
+ "agent with this name already registered: '{}'".format(agent_name)
)
tac_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
@@ -131,9 +122,7 @@ def _on_register(self, message: TacMessage) -> None:
tac_msg.counterparty = message.counterparty
self.context.outbox.put_message(message=tac_msg)
game.registration.register_agent(message.counterparty, agent_name)
- self.context.logger.info(
- "[{}]: Agent registered: '{}'".format(self.context.agent_name, agent_name)
- )
+ self.context.logger.info("agent registered: '{}'".format(agent_name))
def _on_unregister(self, message: TacMessage) -> None:
"""
@@ -147,9 +136,7 @@ def _on_unregister(self, message: TacMessage) -> None:
game = cast(Game, self.context.game)
if message.counterparty not in game.registration.agent_addr_to_name:
self.context.logger.warning(
- "[{}]: Agent not registered: '{}'".format(
- self.context.agent_name, message.counterparty
- )
+ "agent not registered: '{}'".format(message.counterparty)
)
tac_msg = TacMessage(
performative=TacMessage.Performative.TAC_ERROR,
@@ -159,8 +146,7 @@ def _on_unregister(self, message: TacMessage) -> None:
self.context.outbox.put_message(message=tac_msg)
else:
self.context.logger.debug(
- "[{}]: Agent unregistered: '{}'".format(
- self.context.agent_name,
+ "agent unregistered: '{}'".format(
game.conf.agent_addr_to_name[message.counterparty],
)
)
@@ -198,16 +184,12 @@ def handle(self, message: Message) -> None:
oef_message = cast(OefSearchMessage, message)
self.context.logger.debug(
- "[{}]: Handling OEF message. type={}".format(
- self.context.agent_name, oef_message.performative
- )
+ "handling OEF message. type={}".format(oef_message.performative)
)
if oef_message.performative == OefSearchMessage.Performative.OEF_ERROR:
self._on_oef_error(oef_message)
else:
- self.context.logger.warning(
- "[{}]: OEF Message type not recognized.".format(self.context.agent_name)
- )
+ self.context.logger.warning("OEF Message type not recognized.")
def _on_oef_error(self, oef_error: OefSearchMessage) -> None:
"""
@@ -218,10 +200,8 @@ def _on_oef_error(self, oef_error: OefSearchMessage) -> None:
:return: None
"""
self.context.logger.warning(
- "[{}]: Received OEF Search error: dialogue_reference={}, operation={}".format(
- self.context.agent_name,
- oef_error.dialogue_reference,
- oef_error.oef_error_operation,
+ "received OEF Search error: dialogue_reference={}, operation={}".format(
+ oef_error.dialogue_reference, oef_error.oef_error_operation,
)
)
@@ -256,56 +236,32 @@ def handle(self, message: Message) -> None:
ledger_api = self.context.ledger_apis.get_api(parameters.ledger)
if signing_msg_response.dialogue_reference[0] == "contract_deploy":
game.phase = Phase.CONTRACT_DEPLOYING
- self.context.logger.info(
- "[{}]: Sending deployment transaction to the ledger...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending deployment transaction to the ledger...")
tx_signed = signing_msg_response.signed_transaction
tx_digest = ledger_api.send_signed_transaction(tx_signed=tx_signed)
if tx_digest is None:
- self.context.logger.warning(
- "[{}]: Sending transaction failed. Aborting!".format(
- self.context.agent_name
- )
- )
+ self.context.logger.warning("sending transaction failed. Aborting!")
self.context.is_active = False
else:
game.contract_manager.deploy_tx_digest = tx_digest
elif signing_msg_response.dialogue_reference[0] == "contract_create_batch":
game.phase = Phase.TOKENS_CREATING
- self.context.logger.info(
- "[{}]: Sending creation transaction to the ledger...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending creation transaction to the ledger...")
tx_signed = signing_msg_response.signed_transaction
tx_digest = ledger_api.send_signed_transaction(tx_signed=tx_signed)
if tx_digest is None:
- self.context.logger.warning(
- "[{}]: Sending transaction failed. Aborting!".format(
- self.context.agent_name
- )
- )
+ self.context.logger.warning("sending transaction failed. Aborting!")
self.context.is_active = False
else:
game.contract_manager.create_tokens_tx_digest = tx_digest
elif signing_msg_response.dialogue_reference[0] == "contract_mint_batch":
game.phase = Phase.TOKENS_MINTING
- self.context.logger.info(
- "[{}]: Sending minting transaction to the ledger...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("sending minting transaction to the ledger...")
tx_signed = signing_msg_response.signed_transaction
agent_addr = signing_msg_response.terms.counterparty_address
tx_digest = ledger_api.send_signed_transaction(tx_signed=tx_signed)
if tx_digest is None:
- self.context.logger.warning(
- "[{}]: Sending transaction failed. Aborting!".format(
- self.context.agent_name
- )
- )
+ self.context.logger.warning("sending transaction failed. Aborting!")
self.context.is_active = False
else:
game.contract_manager.set_mint_tokens_tx_digest(agent_addr, tx_digest)
diff --git a/packages/fetchai/skills/tac_control_contract/parameters.py b/packages/fetchai/skills/tac_control_contract/parameters.py
index e77409ef5c..7e7c1e0626 100644
--- a/packages/fetchai/skills/tac_control_contract/parameters.py
+++ b/packages/fetchai/skills/tac_control_contract/parameters.py
@@ -93,15 +93,14 @@ def __init__(self, **kwargs):
now = datetime.datetime.now()
if now > self.registration_start_time:
self.context.logger.warning(
- "[{}]: TAC registration start time {} is in the past! Deregistering skill.".format(
- self.context.agent_name, self.registration_start_time
+ "TAC registration start time {} is in the past! Deregistering skill.".format(
+ self.registration_start_time
)
)
self.context.is_active = False
else:
self.context.logger.info(
- "[{}]: TAC registation start time: {}, and registration end time: {}, and start time: {}, and end time: {}".format(
- self.context.agent_name,
+ "TAC registation start time: {}, and registration end time: {}, and start time: {}, and end time: {}".format(
self.registration_start_time,
self.registration_end_time,
self.start_time,
diff --git a/packages/fetchai/skills/tac_control_contract/skill.yaml b/packages/fetchai/skills/tac_control_contract/skill.yaml
index fcb6df65d7..911b3abcb6 100644
--- a/packages/fetchai/skills/tac_control_contract/skill.yaml
+++ b/packages/fetchai/skills/tac_control_contract/skill.yaml
@@ -1,23 +1,23 @@
name: tac_control_contract
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The tac control skill implements the logic for an AEA to control an instance
of the TAC.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmW9WBy1sNYVKpymGnpJY2pW5MEqGgVga2kBFUT9S34Yt5
- behaviours.py: QmcFmysYU23A8q1buM72R9bwkmvrHQMYyBcViRJKuFfzJ2
- game.py: QmdfWrg2y2sggm4c4so26r3g42mjaGK9o7TxHX6ADDSPRF
- handlers.py: QmTsHRVTjVfPetZjkcJybwAetwePWrmPYKAkfEU9uVZXbW
+ behaviours.py: QmREaovF6zG3KNYHkDUgjQ677R1RvBAvgwdZbGj7HJQqXc
+ game.py: QmNncyVW2cndDQ7tkg3aQGuSf58EUL94Ud1hfRu8iehrmu
+ handlers.py: QmNhXDjNHo2QfoVFyX3HhrrLDBFJKV3p9ipKumi5KxyUth
helpers.py: QmbS991iVkS7HCTHBZGoF47REXvsEfqJPi5CqGJR5BasLD
- parameters.py: QmZUf8ho1bPfRZv3tvc9hqwPtwhf2wRTJnox6kSX7ZEqmU
+ parameters.py: QmU6afX3gsJaP8sxNyCohaFrD6eRowtWoVYXzC3ytuob4Y
fingerprint_ignore_patterns: []
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills: []
behaviours:
contract:
diff --git a/packages/fetchai/skills/tac_negotiation/behaviours.py b/packages/fetchai/skills/tac_negotiation/behaviours.py
index 931a6e2568..e3410bf40c 100644
--- a/packages/fetchai/skills/tac_negotiation/behaviours.py
+++ b/packages/fetchai/skills/tac_negotiation/behaviours.py
@@ -19,21 +19,32 @@
"""This package contains a scaffold of a behaviour."""
-from typing import cast
+from typing import Optional, cast
-from aea.skills.base import Behaviour
from aea.skills.behaviours import TickerBehaviour
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
-from packages.fetchai.skills.tac_negotiation.registration import Registration
-from packages.fetchai.skills.tac_negotiation.search import Search
+from packages.fetchai.skills.tac_negotiation.dialogues import (
+ OefSearchDialogue,
+ OefSearchDialogues,
+)
from packages.fetchai.skills.tac_negotiation.strategy import Strategy
from packages.fetchai.skills.tac_negotiation.transactions import Transactions
+DEFAULT_REGISTER_AND_SEARCH_INTERVAL = 5.0
-class GoodsRegisterAndSearchBehaviour(Behaviour):
+
+class GoodsRegisterAndSearchBehaviour(TickerBehaviour):
"""This class implements the goods register and search behaviour."""
+ def __init__(self, **kwargs):
+ """Initialize the search behaviour."""
+ search_interval = cast(
+ float, kwargs.pop("search_interval", DEFAULT_REGISTER_AND_SEARCH_INTERVAL)
+ )
+ super().__init__(tick_interval=search_interval, **kwargs)
+ self.is_registered = False
+
def setup(self) -> None:
"""
Implement the setup.
@@ -54,16 +65,16 @@ def act(self) -> None:
self.context.is_active = False
return
- if self.context.decision_maker_handler_context.goal_pursuit_readiness.is_ready:
-
- registration = cast(Registration, self.context.registration)
- if registration.is_time_to_update_services():
- self._unregister_service()
- self._register_service()
+ if (
+ not self.context.decision_maker_handler_context.goal_pursuit_readiness.is_ready
+ ):
+ return
- search = cast(Search, self.context.search)
- if search.is_time_to_search_services():
- self._search_services()
+ if not self.is_registered:
+ self._register_agent()
+ self._register_service()
+ self.is_registered = True
+ self._search_services()
def teardown(self) -> None:
"""
@@ -71,35 +82,32 @@ def teardown(self) -> None:
:return: None
"""
- self._unregister_service()
+ if self.is_registered:
+ self._unregister_service()
+ self._unregister_agent()
+ self.is_registered = False
- def _unregister_service(self) -> None:
+ def _register_agent(self) -> None:
"""
- Unregister service from OEF Service Directory.
+ Register the agent's location.
:return: None
"""
- registration = cast(Registration, self.context.registration)
-
- if registration.registered_goods_demanded_description is not None:
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(registration.get_next_id()), ""),
- service_description=registration.registered_goods_demanded_description,
- )
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
- registration.registered_goods_demanded_description = None
-
- if registration.registered_goods_supplied_description is not None:
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(registration.get_next_id()), ""),
- service_description=registration.registered_goods_supplied_description,
- )
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
- registration.registered_goods_supplied_description = None
+ strategy = cast(Strategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert oef_search_dialogue is not None, "OefSearchDialogue not created."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("registering agent on SOEF.")
def _register_service(self) -> None:
"""
@@ -112,48 +120,71 @@ def _register_service(self) -> None:
:return: None
"""
- registration = cast(Registration, self.context.registration)
strategy = cast(Strategy, self.context.strategy)
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ self.context.logger.debug(
+ "updating service directory as {}.".format(strategy.registering_as)
+ )
+ description = strategy.get_register_service_description()
+ oef_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.REGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_msg)
+ assert oef_dialogue is not None, "OefSearchDialogue not created."
+ self.context.outbox.put_message(message=oef_msg)
- if strategy.is_registering_as_seller:
- self.context.logger.debug(
- "[{}]: Updating service directory as seller with goods supplied.".format(
- self.context.agent_name
- )
- )
- goods_supplied_description = strategy.get_own_service_description(
- is_supply=True, is_search_description=False,
- )
- registration.registered_goods_supplied_description = (
- goods_supplied_description
- )
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(registration.get_next_id()), ""),
- service_description=goods_supplied_description,
- )
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
+ def _unregister_service(self) -> None:
+ """
+ Unregister service from OEF Service Directory.
- if strategy.is_registering_as_buyer:
- self.context.logger.debug(
- "[{}]: Updating service directory as buyer with goods demanded.".format(
- self.context.agent_name
- )
- )
- goods_demanded_description = strategy.get_own_service_description(
- is_supply=False, is_search_description=False,
- )
- registration.registered_goods_demanded_description = (
- goods_demanded_description
- )
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(registration.get_next_id()), ""),
- service_description=goods_demanded_description,
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ self.context.logger.debug(
+ "unregistering from service directory as {}.".format(
+ strategy.registering_as
)
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
+ )
+ description = strategy.get_unregister_service_description()
+ oef_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_msg.counterparty = self.context.search_service_address
+ oef_dialogue = oef_search_dialogues.update(oef_msg)
+ assert oef_dialogue is not None, "OefSearchDialogue not created."
+ self.context.outbox.put_message(message=oef_msg)
+
+ def _unregister_agent(self) -> None:
+ """
+ Unregister agent from the SOEF.
+
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ description = strategy.get_location_description()
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=description,
+ )
+ oef_search_msg.counterparty = self.context.search_service_address
+ oef_search_dialogue = oef_search_dialogues.update(oef_search_msg)
+ assert oef_search_dialogue is not None, "OefSearchDialogue not created."
+ self.context.outbox.put_message(message=oef_search_msg)
+ self.context.logger.info("unregistering agent from SOEF.")
def _search_services(self) -> None:
"""
@@ -167,59 +198,28 @@ def _search_services(self) -> None:
:return: None
"""
strategy = cast(Strategy, self.context.strategy)
- search = cast(Search, self.context.search)
-
- if strategy.is_searching_for_sellers:
- query = strategy.get_own_services_query(
- is_searching_for_sellers=True, is_search_query=True
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ query = strategy.get_location_and_service_query()
+ for (is_seller_search, searching_for) in strategy.searching_for_types:
+ oef_msg = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ query=query,
)
- if query is None:
- self.context.logger.warning(
- "[{}]: Not searching the OEF for sellers because the agent demands no goods.".format(
- self.context.agent_name
- )
- )
- return None
- else:
- search_id = search.get_next_id(is_searching_for_sellers=True)
- self.context.logger.info(
- "[{}]: Searching for sellers which match the demand of the agent, search_id={}.".format(
- self.context.agent_name, search_id
- )
- )
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(search_id), ""),
- query=query,
- )
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
-
- if strategy.is_searching_for_buyers:
- query = strategy.get_own_services_query(
- is_searching_for_sellers=False, is_search_query=True
+ oef_msg.counterparty = self.context.search_service_address
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_msg)
)
- if query is None:
- self.context.logger.warning(
- "[{}]: Not searching the OEF for buyers because the agent supplies no goods.".format(
- self.context.agent_name
- )
- )
- return None
- else:
- search_id = search.get_next_id(is_searching_for_sellers=False)
- self.context.logger.info(
- "[{}]: Searching for buyers which match the supply of the agent, search_id={}.".format(
- self.context.agent_name, search_id
- )
- )
- oef_msg = OefSearchMessage(
- performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(search_id), ""),
- query=query,
+ assert oef_search_dialogue is not None, "OefSearchDialogue not created."
+ oef_search_dialogue.is_seller_search = is_seller_search
+ self.context.outbox.put_message(message=oef_msg)
+ self.context.logger.info(
+ "searching for {}, search_id={}.".format(
+ searching_for, oef_msg.dialogue_reference
)
- oef_msg.counterparty = self.context.search_service_address
- self.context.outbox.put_message(message=oef_msg)
+ )
class TransactionCleanUpBehaviour(TickerBehaviour):
@@ -240,6 +240,7 @@ def act(self) -> None:
:return: None
"""
transactions = cast(Transactions, self.context.transactions)
+ transactions.update_confirmed_transactions()
transactions.cleanup_pending_transactions()
def teardown(self) -> None:
diff --git a/packages/fetchai/skills/tac_negotiation/dialogues.py b/packages/fetchai/skills/tac_negotiation/dialogues.py
index e53143567a..1ef2ae3421 100644
--- a/packages/fetchai/skills/tac_negotiation/dialogues.py
+++ b/packages/fetchai/skills/tac_negotiation/dialogues.py
@@ -23,24 +23,36 @@
- Dialogues: The dialogues class keeps track of all dialogues.
"""
-from typing import cast
+from typing import Optional, cast
-from aea.helpers.dialogue.base import Dialogue as BaseDialogue
+from aea.helpers.dialogue.base import Dialogue, DialogueLabel
+from aea.mail.base import Address
from aea.protocols.base import Message
+from aea.protocols.default.dialogues import DefaultDialogue as BaseDefaultDialogue
+from aea.protocols.default.dialogues import DefaultDialogues as BaseDefaultDialogues
+from aea.protocols.signing.dialogues import SigningDialogue as BaseSigningDialogue
+from aea.protocols.signing.dialogues import SigningDialogues as BaseSigningDialogues
from aea.skills.base import Model
-from packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues
+from packages.fetchai.protocols.fipa.dialogues import FipaDialogue as BaseFipaDialogue
+from packages.fetchai.protocols.fipa.dialogues import FipaDialogues as BaseFipaDialogues
from packages.fetchai.protocols.fipa.message import FipaMessage
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue as BaseOefSearchDialogue,
+)
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogues as BaseOefSearchDialogues,
+)
from packages.fetchai.skills.tac_negotiation.helpers import (
DEMAND_DATAMODEL_NAME,
SUPPLY_DATAMODEL_NAME,
)
-Dialogue = FipaDialogue
+DefaultDialogue = BaseDefaultDialogue
-class Dialogues(Model, FipaDialogues):
+class DefaultDialogues(Model, BaseDefaultDialogues):
"""The dialogues class keeps track of all dialogues."""
def __init__(self, **kwargs) -> None:
@@ -50,10 +62,51 @@ def __init__(self, **kwargs) -> None:
:return: None
"""
Model.__init__(self, **kwargs)
- FipaDialogues.__init__(self, self.context.agent_address)
+ BaseDefaultDialogues.__init__(self, self.context.agent_address)
@staticmethod
- def role_from_first_message(message: Message) -> BaseDialogue.Role:
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return DefaultDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> DefaultDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = DefaultDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+FipaDialogue = BaseFipaDialogue
+
+
+class FipaDialogues(Model, BaseFipaDialogues):
+ """The dialogues class keeps track of all dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseFipaDialogues.__init__(self, self.context.agent_address)
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
"""
Infer the role of the agent from an incoming or outgoing first message
@@ -85,3 +138,124 @@ def role_from_first_message(message: Message) -> BaseDialogue.Role:
) # the agent is querying for demand/buyers (this agent is sending the CFP so it is the seller)
role = FipaDialogue.Role.SELLER if is_seller else FipaDialogue.Role.BUYER
return role
+
+
+class OefSearchDialogue(BaseOefSearchDialogue):
+ """The dialogue class maintains state of a dialogue and manages it."""
+
+ def __init__(
+ self,
+ dialogue_label: DialogueLabel,
+ agent_address: Address,
+ role: Dialogue.Role,
+ ) -> None:
+ """
+ Initialize a dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param agent_address: the address of the agent for whom this dialogue is maintained
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: None
+ """
+ BaseOefSearchDialogue.__init__(
+ self, dialogue_label=dialogue_label, agent_address=agent_address, role=role
+ )
+ self._is_seller_search = None # type: Optional[bool]
+
+ @property
+ def is_seller_search(self) -> bool:
+ """Get if it is a seller search."""
+ assert self._is_seller_search is not None, "is_seller_search not set!"
+ return self._is_seller_search
+
+ @is_seller_search.setter
+ def is_seller_search(self, is_seller_search: bool) -> None:
+ """Set is_seller_search."""
+ assert self._is_seller_search is None, "is_seller_search already set!"
+ self._is_seller_search = is_seller_search
+
+
+class OefSearchDialogues(Model, BaseOefSearchDialogues):
+ """This class keeps track of all oef_search dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseOefSearchDialogues.__init__(
+ self, self.context.agent_address + "_" + str(self.context.skill_id)
+ )
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseOefSearchDialogue.Role.AGENT
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> OefSearchDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = OefSearchDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
+
+
+SigningDialogue = BaseSigningDialogue
+
+
+class SigningDialogues(Model, BaseSigningDialogues):
+ """This class keeps track of all oef_search dialogues."""
+
+ def __init__(self, **kwargs) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Model.__init__(self, **kwargs)
+ BaseSigningDialogues.__init__(
+ self, self.context.agent_address + "_" + str(self.context.skill_id)
+ )
+
+ @staticmethod
+ def role_from_first_message(message: Message) -> Dialogue.Role:
+ """Infer the role of the agent from an incoming/outgoing first message
+
+ :param message: an incoming/outgoing first message
+ :return: The role of the agent
+ """
+ return BaseSigningDialogue.Role.SKILL
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> SigningDialogue:
+ """
+ Create an instance of fipa dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = SigningDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/packages/fetchai/skills/tac_negotiation/handlers.py b/packages/fetchai/skills/tac_negotiation/handlers.py
index e7d4dc77db..b6375b928d 100644
--- a/packages/fetchai/skills/tac_negotiation/handlers.py
+++ b/packages/fetchai/skills/tac_negotiation/handlers.py
@@ -21,9 +21,9 @@
import pprint
import time
-from typing import Dict, Optional, Tuple, cast
+from typing import Optional, Tuple, cast
-from aea.configurations.base import ProtocolId, PublicId
+from aea.configurations.base import ProtocolId
from aea.helpers.dialogue.base import DialogueLabel
from aea.helpers.search.models import Query
from aea.protocols.base import Message
@@ -33,13 +33,20 @@
from packages.fetchai.protocols.fipa.message import FipaMessage
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
-from packages.fetchai.skills.tac_negotiation.dialogues import Dialogue, Dialogues
-from packages.fetchai.skills.tac_negotiation.search import Search
+from packages.fetchai.skills.tac_negotiation.dialogues import (
+ DefaultDialogues,
+ FipaDialogue,
+ FipaDialogues,
+ OefSearchDialogue,
+ OefSearchDialogues,
+ SigningDialogue,
+ SigningDialogues,
+)
from packages.fetchai.skills.tac_negotiation.strategy import Strategy
from packages.fetchai.skills.tac_negotiation.transactions import Transactions
-class FIPANegotiationHandler(Handler):
+class FipaNegotiationHandler(Handler):
"""This class implements the fipa negotiation handler."""
SUPPORTED_PROTOCOL = FipaMessage.protocol_id # type: Optional[ProtocolId]
@@ -62,16 +69,14 @@ def handle(self, message: Message) -> None:
fipa_msg = cast(FipaMessage, message)
# recover dialogue
- dialogues = cast(Dialogues, self.context.dialogues)
- fipa_dialogue = cast(Dialogue, dialogues.update(fipa_msg))
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ fipa_dialogue = cast(FipaDialogue, fipa_dialogues.update(fipa_msg))
if fipa_dialogue is None:
self._handle_unidentified_dialogue(fipa_msg)
return
self.context.logger.debug(
- "[{}]: Handling FipaMessage of performative={}".format(
- self.context.agent_name, fipa_msg.performative
- )
+ "handling FipaMessage of performative={}".format(fipa_msg.performative)
)
if fipa_msg.performative == FipaMessage.Performative.CFP:
self._on_cfp(fipa_msg, fipa_dialogue)
@@ -92,7 +97,7 @@ def teardown(self) -> None:
"""
pass
- def _handle_unidentified_dialogue(self, msg: FipaMessage) -> None:
+ def _handle_unidentified_dialogue(self, fipa_msg: FipaMessage) -> None:
"""
Handle an unidentified dialogue.
@@ -103,26 +108,28 @@ def _handle_unidentified_dialogue(self, msg: FipaMessage) -> None:
:return: None
"""
self.context.logger.info(
- "[{}]: unidentified dialogue.".format(self.context.agent_name)
+ "received invalid fipa message={}, unidentified dialogue.".format(fipa_msg)
)
+ default_dialogues = cast(DefaultDialogues, self.context.default_dialogues)
default_msg = DefaultMessage(
- dialogue_reference=("", ""),
- message_id=1,
- target=0,
performative=DefaultMessage.Performative.ERROR,
+ dialogue_reference=default_dialogues.new_self_initiated_dialogue_reference(),
error_code=DefaultMessage.ErrorCode.INVALID_DIALOGUE,
error_msg="Invalid dialogue.",
- error_data={"fipa_message": msg.encode()},
+ error_data={"fipa_message": fipa_msg.encode()},
)
- default_msg.counterparty = msg.counterparty
+ default_msg.counterparty = fipa_msg.counterparty
+ assert (
+ default_dialogues.update(default_msg) is not None
+ ), "DefaultDialogue not constructed."
self.context.outbox.put_message(message=default_msg)
- def _on_cfp(self, cfp: FipaMessage, dialogue: Dialogue) -> None:
+ def _on_cfp(self, cfp: FipaMessage, fipa_dialogue: FipaDialogue) -> None:
"""
Handle a CFP.
:param cfp: the fipa message containing the CFP
- :param dialogue: the dialogue
+ :param fipa_dialogue: the fipa_dialogue
:return: None
"""
@@ -130,19 +137,18 @@ def _on_cfp(self, cfp: FipaMessage, dialogue: Dialogue) -> None:
query = cast(Query, cfp.query)
strategy = cast(Strategy, self.context.strategy)
proposal_description = strategy.get_proposal_for_query(
- query, cast(Dialogue.Role, dialogue.role)
+ query, cast(FipaDialogue.Role, fipa_dialogue.role)
)
if proposal_description is None:
self.context.logger.debug(
- "[{}]: sending to {} a Decline{}".format(
- self.context.agent_name,
- dialogue.dialogue_label.dialogue_opponent_addr[-5:],
+ "sending to {} a Decline{}".format(
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],
pprint.pformat(
{
"msg_id": new_msg_id,
"dialogue_reference": cfp.dialogue_reference,
- "origin": dialogue.dialogue_label.dialogue_opponent_addr[
+ "origin": fipa_dialogue.dialogue_label.dialogue_opponent_addr[
-5:
],
"target": cfp.target,
@@ -153,34 +159,33 @@ def _on_cfp(self, cfp: FipaMessage, dialogue: Dialogue) -> None:
fipa_msg = FipaMessage(
performative=FipaMessage.Performative.DECLINE,
message_id=new_msg_id,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
target=cfp.message_id,
)
- dialogues = cast(Dialogues, self.context.dialogues)
- dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ fipa_dialogues.dialogue_stats.add_dialogue_endstate(
+ FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated
)
else:
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.generate_transaction_message(
+ signing_msg = transactions.generate_signing_message(
SigningMessage.Performative.SIGN_MESSAGE,
proposal_description,
- dialogue.dialogue_label,
- cast(Dialogue.Role, dialogue.role),
+ fipa_dialogue.dialogue_label,
+ cast(FipaDialogue.Role, fipa_dialogue.role),
self.context.agent_address,
)
transactions.add_pending_proposal(
- dialogue.dialogue_label, new_msg_id, transaction_msg
+ fipa_dialogue.dialogue_label, new_msg_id, signing_msg
)
self.context.logger.info(
- "[{}]: sending to {} a Propose {}".format(
- self.context.agent_name,
- dialogue.dialogue_label.dialogue_opponent_addr[-5:],
+ "sending to {} a Propose {}".format(
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],
pprint.pformat(
{
"msg_id": new_msg_id,
"dialogue_reference": cfp.dialogue_reference,
- "origin": dialogue.dialogue_label.dialogue_opponent_addr[
+ "origin": fipa_dialogue.dialogue_label.dialogue_opponent_addr[
-5:
],
"target": cfp.message_id,
@@ -192,153 +197,143 @@ def _on_cfp(self, cfp: FipaMessage, dialogue: Dialogue) -> None:
fipa_msg = FipaMessage(
performative=FipaMessage.Performative.PROPOSE,
message_id=new_msg_id,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
target=cfp.message_id,
proposal=proposal_description,
)
fipa_msg.counterparty = cfp.counterparty
- dialogue.update(fipa_msg)
+ fipa_dialogue.update(fipa_msg)
self.context.outbox.put_message(message=fipa_msg)
- def _on_propose(self, propose: FipaMessage, dialogue: Dialogue) -> None:
+ def _on_propose(self, propose: FipaMessage, fipa_dialogue: FipaDialogue) -> None:
"""
Handle a Propose.
:param propose: the message containing the Propose
- :param dialogue: the dialogue
+ :param fipa_dialogue: the fipa_dialogue
:return: None
"""
new_msg_id = propose.message_id + 1
strategy = cast(Strategy, self.context.strategy)
proposal_description = propose.proposal
- self.context.logger.debug(
- "[{}]: on Propose as {}.".format(self.context.agent_name, dialogue.role)
- )
+ self.context.logger.debug("on Propose as {}.".format(fipa_dialogue.role))
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.generate_transaction_message(
+ signing_msg = transactions.generate_signing_message(
SigningMessage.Performative.SIGN_MESSAGE,
proposal_description,
- dialogue.dialogue_label,
- cast(Dialogue.Role, dialogue.role),
+ fipa_dialogue.dialogue_label,
+ cast(FipaDialogue.Role, fipa_dialogue.role),
self.context.agent_address,
)
if strategy.is_profitable_transaction(
- transaction_msg, role=cast(Dialogue.Role, dialogue.role)
+ signing_msg, role=cast(FipaDialogue.Role, fipa_dialogue.role)
):
self.context.logger.info(
- "[{}]: Accepting propose (as {}).".format(
- self.context.agent_name, dialogue.role
- )
+ "accepting propose (as {}).".format(fipa_dialogue.role)
)
transactions.add_locked_tx(
- transaction_msg, role=cast(Dialogue.Role, dialogue.role)
+ signing_msg, role=cast(FipaDialogue.Role, fipa_dialogue.role)
)
transactions.add_pending_initial_acceptance(
- dialogue.dialogue_label, new_msg_id, transaction_msg
+ fipa_dialogue.dialogue_label, new_msg_id, signing_msg
)
fipa_msg = FipaMessage(
performative=FipaMessage.Performative.ACCEPT,
message_id=new_msg_id,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
target=propose.message_id,
)
else:
self.context.logger.info(
- "[{}]: Declining propose (as {})".format(
- self.context.agent_name, dialogue.role
- )
+ "declining propose (as {})".format(fipa_dialogue.role)
)
fipa_msg = FipaMessage(
performative=FipaMessage.Performative.DECLINE,
message_id=new_msg_id,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
target=propose.message_id,
)
- dialogues = cast(Dialogues, self.context.dialogues)
- dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ fipa_dialogues.dialogue_stats.add_dialogue_endstate(
+ FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated
)
fipa_msg.counterparty = propose.counterparty
- dialogue.update(fipa_msg)
+ fipa_dialogue.update(fipa_msg)
self.context.outbox.put_message(message=fipa_msg)
- def _on_decline(self, decline: FipaMessage, dialogue: Dialogue) -> None:
+ def _on_decline(self, decline: FipaMessage, fipa_dialogue: FipaDialogue) -> None:
"""
Handle a Decline.
:param decline: the Decline message
- :param dialogue: the dialogue
+ :param fipa_dialogue: the fipa_dialogue
:return: None
"""
self.context.logger.debug(
- "[{}]: on_decline: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
- self.context.agent_name,
+ "on_decline: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
decline.message_id,
decline.dialogue_reference,
- dialogue.dialogue_label.dialogue_opponent_addr,
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr,
decline.target,
)
)
target = decline.target
- dialogues = cast(Dialogues, self.context.dialogues)
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
if target == 1:
- dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_CFP, dialogue.is_self_initiated
+ fipa_dialogues.dialogue_stats.add_dialogue_endstate(
+ FipaDialogue.EndState.DECLINED_CFP, fipa_dialogue.is_self_initiated
)
elif target == 2:
- dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_PROPOSE, dialogue.is_self_initiated
+ fipa_dialogues.dialogue_stats.add_dialogue_endstate(
+ FipaDialogue.EndState.DECLINED_PROPOSE, fipa_dialogue.is_self_initiated
)
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.pop_pending_proposal(
- dialogue.dialogue_label, target
+ signing_msg = transactions.pop_pending_proposal(
+ fipa_dialogue.dialogue_label, target
)
elif target == 3:
- dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated
+ fipa_dialogues.dialogue_stats.add_dialogue_endstate(
+ FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated
)
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.pop_pending_initial_acceptance(
- dialogue.dialogue_label, target
+ signing_msg = transactions.pop_pending_initial_acceptance(
+ fipa_dialogue.dialogue_label, target
)
- transactions.pop_locked_tx(transaction_msg)
+ transactions.pop_locked_tx(signing_msg)
- def _on_accept(self, accept: FipaMessage, dialogue: Dialogue) -> None:
+ def _on_accept(self, accept: FipaMessage, fipa_dialogue: FipaDialogue) -> None:
"""
Handle an Accept.
:param accept: the Accept message
- :param dialogue: the dialogue
+ :param fipa_dialogue: the fipa_dialogue
:return: None
"""
self.context.logger.debug(
- "[{}]: on_accept: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
- self.context.agent_name,
+ "on_accept: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
accept.message_id,
accept.dialogue_reference,
- dialogue.dialogue_label.dialogue_opponent_addr,
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr,
accept.target,
)
)
new_msg_id = accept.message_id + 1
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.pop_pending_proposal(
- dialogue.dialogue_label, accept.target
+ signing_msg = transactions.pop_pending_proposal(
+ fipa_dialogue.dialogue_label, accept.target
)
strategy = cast(Strategy, self.context.strategy)
if strategy.is_profitable_transaction(
- transaction_msg, role=cast(Dialogue.Role, dialogue.role)
+ signing_msg, role=cast(FipaDialogue.Role, fipa_dialogue.role)
):
self.context.logger.info(
- "[{}]: locking the current state (as {}).".format(
- self.context.agent_name, dialogue.role
- )
+ "locking the current state (as {}).".format(fipa_dialogue.role)
)
transactions.add_locked_tx(
- transaction_msg, role=cast(Dialogue.Role, dialogue.role)
+ signing_msg, role=cast(FipaDialogue.Role, fipa_dialogue.role)
)
if strategy.is_contract_tx:
pass
@@ -385,60 +380,68 @@ def _on_accept(self, accept: FipaMessage, dialogue: Dialogue) -> None:
# ledger_api=self.context.ledger_apis.get_api(strategy.ledger_id),
# skill_callback_id=self.context.skill_id,
# skill_callback_info={
- # "dialogue_label": dialogue.dialogue_label.json
+ # "dialogue_label": fipa_dialogue.dialogue_label.json
# },
# )
- self.context.logger.info(
- "[{}]: sending tx_message={} to decison maker.".format(
- self.context.agent_name, transaction_msg
+ else:
+ signing_dialogues = cast(
+ SigningDialogues, self.context.signing_dialogues
)
- )
- self.context.decision_maker_message_queue.put(transaction_msg)
+ signing_dialogue = cast(
+ Optional[SigningDialogue], signing_dialogues.update(signing_msg)
+ )
+ assert (
+ signing_dialogue is not None
+ ), "Could not construct sigining dialogue."
+ self.context.logger.info(
+ "sending signing_msg={} to decison maker following ACCEPT.".format(
+ signing_msg
+ )
+ )
+ self.context.decision_maker_message_queue.put(signing_msg)
else:
self.context.logger.debug(
- "[{}]: decline the Accept (as {}).".format(
- self.context.agent_name, dialogue.role
- )
+ "decline the Accept (as {}).".format(fipa_dialogue.role)
)
fipa_msg = FipaMessage(
performative=FipaMessage.Performative.DECLINE,
message_id=new_msg_id,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
target=accept.message_id,
)
fipa_msg.counterparty = accept.counterparty
- dialogue.update(fipa_msg)
- dialogues = cast(Dialogues, self.context.dialogues)
+ fipa_dialogue.update(fipa_msg)
+ dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
dialogues.dialogue_stats.add_dialogue_endstate(
- Dialogue.EndState.DECLINED_ACCEPT, dialogue.is_self_initiated
+ FipaDialogue.EndState.DECLINED_ACCEPT, fipa_dialogue.is_self_initiated
)
self.context.outbox.put_message(message=fipa_msg)
- def _on_match_accept(self, match_accept: FipaMessage, dialogue: Dialogue) -> None:
+ def _on_match_accept(
+ self, match_accept: FipaMessage, fipa_dialogue: FipaDialogue
+ ) -> None:
"""
Handle a matching Accept.
:param match_accept: the MatchAccept message
- :param dialogue: the dialogue
+ :param fipa_dialogue: the fipa_dialogue
:return: None
"""
self.context.logger.debug(
- "[{}]: on_match_accept: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
- self.context.agent_name,
+ "on_match_accept: msg_id={}, dialogue_reference={}, origin={}, target={}".format(
match_accept.message_id,
match_accept.dialogue_reference,
- dialogue.dialogue_label.dialogue_opponent_addr,
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr,
match_accept.target,
)
)
- if (match_accept.info.get("tx_signature") is not None) and (
- match_accept.info.get("tx_id") is not None
- ):
+ if match_accept.info.get("signature") is not None:
transactions = cast(Transactions, self.context.transactions)
- transaction_msg = transactions.pop_pending_initial_acceptance(
- dialogue.dialogue_label, match_accept.target
+ signing_msg = transactions.pop_pending_initial_acceptance(
+ fipa_dialogue.dialogue_label, match_accept.target
)
strategy = cast(Strategy, self.context.strategy)
+ counterparty_signature = match_accept.info.get("signature")
if strategy.is_contract_tx:
pass
# contract = cast(ERC1155Contract, self.context.contracts.erc1155)
@@ -496,34 +499,30 @@ def _on_match_accept(self, match_accept: FipaMessage, dialogue: Dialogue) -> Non
# },
# )
else:
- transaction_msg.set(
- "skill_callback_ids",
- [PublicId.from_str("fetchai/tac_participation:0.4.0")],
- )
- transaction_msg.set(
+ signing_msg.set(
"skill_callback_info",
{
- **transaction_msg.skill_callback_info,
- **{
- "tx_counterparty_signature": match_accept.info.get(
- "tx_signature"
- ),
- "tx_counterparty_id": match_accept.info.get("tx_id"),
- },
+ **signing_msg.skill_callback_info,
+ **{"counterparty_signature": counterparty_signature},
},
)
- self.context.logger.info(
- "[{}]: sending tx_message={} to decison maker.".format(
- self.context.agent_name, transaction_msg
+ signing_dialogues = cast(
+ SigningDialogues, self.context.signing_dialogues
)
- )
- self.context.decision_maker_message_queue.put(transaction_msg)
- else:
- self.context.logger.warning(
- "[{}]: match_accept did not contain tx_signature and tx_id!".format(
- self.context.agent_name
+ signing_dialogue = cast(
+ Optional[SigningDialogue], signing_dialogues.update(signing_msg)
)
- )
+ assert (
+ signing_dialogue is not None
+ ), "Could not construct sigining dialogue."
+ self.context.logger.info(
+ "sending signing_msg={} to decison maker following MATCH_ACCEPT.".format(
+ signing_msg
+ )
+ )
+ self.context.decision_maker_message_queue.put(signing_msg)
+ else:
+ self.context.logger.warning("match_accept did not contain signature!")
class SigningHandler(Handler):
@@ -546,139 +545,262 @@ def handle(self, message: Message) -> None:
:param message: the message
:return: None
"""
- tx_message = cast(SigningMessage, message)
- if tx_message.performative == SigningMessage.Performative.SIGNED_MESSAGE:
+ signing_msg = cast(SigningMessage, message)
+
+ # recover dialogue
+ signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)
+ signing_dialogue = cast(
+ Optional[SigningDialogue], signing_dialogues.update(signing_msg)
+ )
+ if signing_dialogue is None:
+ self._handle_unidentified_dialogue(signing_msg)
+ return
+
+ # handle message
+ if signing_msg.performative is SigningMessage.Performative.SIGNED_MESSAGE:
+ self._handle_signed_message(signing_msg, signing_dialogue)
+ elif signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:
+ self._handle_signed_transaction(signing_msg, signing_dialogue)
+ elif signing_msg.performative is SigningMessage.Performative.ERROR:
+ self._handle_error(signing_msg, signing_dialogue)
+ else:
+ self._handle_invalid(signing_msg, signing_dialogue)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+ pass
+
+ def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param msg: the message
+ """
+ self.context.logger.info(
+ "received invalid signing message={}, unidentified dialogue.".format(
+ signing_msg
+ )
+ )
+
+ def _handle_signed_message(
+ self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param signing_msg: the signing message
+ :param signing_dialogue: the dialogue
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ if strategy.is_contract_tx:
+ self.context.logger.warning(
+ "signed message handler only for non-contract case."
+ )
+ return None
+ self.context.logger.info("message signed by decision maker.")
+ dialogue_label = DialogueLabel.from_str(
+ cast(str, signing_msg.skill_callback_info.get("dialogue_label"))
+ )
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ fipa_dialogue = fipa_dialogues.dialogues[dialogue_label]
+ last_fipa_message = cast(FipaMessage, fipa_dialogue.last_incoming_message)
+ if (
+ last_fipa_message is not None
+ and last_fipa_message.performative == FipaMessage.Performative.ACCEPT
+ ):
+ fipa_msg = FipaMessage(
+ performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
+ message_id=last_fipa_message.message_id + 1,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
+ target=last_fipa_message.message_id,
+ info={"signature": signing_msg.signed_message.body},
+ )
+ fipa_msg.counterparty = last_fipa_message.counterparty
+ fipa_dialogue.update(fipa_msg)
+ self.context.outbox.put_message(message=fipa_msg)
self.context.logger.info(
- "[{}]: transaction confirmed by decision maker".format(
- self.context.agent_name
+ "sending match accept to {}.".format(
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],
)
)
- strategy = cast(Strategy, self.context.strategy)
- dialogue_label = DialogueLabel.from_json(
- cast(
- Dict[str, str], tx_message.skill_callback_info.get("dialogue_label")
- )
+ elif (
+ last_fipa_message is not None
+ and last_fipa_message.performative
+ == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM
+ ):
+ counterparty_signature = cast(
+ str, signing_msg.skill_callback_info.get("counterparty_signature")
)
- dialogues = cast(Dialogues, self.context.dialogues)
- dialogue = dialogues.dialogues[dialogue_label]
- last_fipa_message = cast(FipaMessage, dialogue.last_incoming_message)
- if (
- last_fipa_message is not None
- and last_fipa_message.performative == FipaMessage.Performative.ACCEPT
- ):
- self.context.logger.info(
- "[{}]: sending match accept to {}.".format(
- self.context.agent_name,
- dialogue.dialogue_label.dialogue_opponent_addr[-5:],
- )
+ if counterparty_signature is not None:
+ last_signing_msg = cast(
+ Optional[SigningMessage], signing_dialogue.last_outgoing_message
)
- fipa_msg = FipaMessage(
- performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
- message_id=last_fipa_message.message_id + 1,
- dialogue_reference=dialogue.dialogue_label.dialogue_reference,
- target=last_fipa_message.message_id,
- info={
- "tx_signature": tx_message.signed_transaction,
- "tx_id": tx_message.dialogue_reference[0],
- },
+ assert (
+ last_signing_msg is not None
+ ), "Could not recover last signing message."
+ tx_id = (
+ last_signing_msg.terms.sender_hash
+ + "_"
+ + last_signing_msg.terms.counterparty_hash
)
- fipa_msg.counterparty = dialogue.dialogue_label.dialogue_opponent_addr
- dialogue.update(fipa_msg)
- self.context.outbox.put_message(message=fipa_msg)
- elif (
- last_fipa_message is not None
- and last_fipa_message.performative
- == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM
- and strategy.is_contract_tx
- ):
- self.context.logger.info(
- "[{}]: sending atomic swap tx to ledger.".format(
- self.context.agent_name
- )
+ if "transactions" not in self.context.shared_state.keys():
+ self.context.shared_state["transactions"] = {}
+ self.context.shared_state["transactions"][tx_id] = {
+ "terms": last_signing_msg.terms,
+ "sender_signature": signing_msg.signed_message.body,
+ "counterparty_signature": counterparty_signature,
+ }
+ self.context.logger.info("sending transaction to controller.")
+ else:
+ self.context.logger.warning(
+ "transaction has no counterparty signature!"
+ )
+ else:
+ self.context.logger.warning(
+ "last message should be of performative accept or match accept."
+ )
+
+ def _handle_signed_transaction(
+ self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param signing_msg: the signing message
+ :param signing_dialogue: the dialogue
+ :return: None
+ """
+ strategy = cast(Strategy, self.context.strategy)
+ if not strategy.is_contract_tx:
+ self.context.logger.warning(
+ "signed transaction handler only for contract case."
+ )
+ return None
+ self.context.logger.info("transaction signed by decision maker.")
+ dialogue_label = DialogueLabel.from_str(
+ cast(str, signing_msg.skill_callback_info.get("dialogue_label"))
+ )
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ fipa_dialogue = fipa_dialogues.dialogues[dialogue_label]
+ last_fipa_message = cast(FipaMessage, fipa_dialogue.last_incoming_message)
+ if (
+ last_fipa_message is not None
+ and last_fipa_message.performative == FipaMessage.Performative.ACCEPT
+ ):
+ self.context.logger.info(
+ "sending match accept to {}.".format(
+ fipa_dialogue.dialogue_label.dialogue_opponent_addr[-5:],
)
- tx_signed = tx_message.signed_transaction
- tx_digest = self.context.ledger_apis.get_api(
+ )
+ fipa_msg = FipaMessage(
+ performative=FipaMessage.Performative.MATCH_ACCEPT_W_INFORM,
+ message_id=last_fipa_message.message_id + 1,
+ dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference,
+ target=last_fipa_message.message_id,
+ info={
+ "tx_signature": signing_msg.signed_transaction,
+ "tx_id": signing_msg.dialogue_reference[0],
+ },
+ )
+ fipa_msg.counterparty = fipa_dialogue.dialogue_label.dialogue_opponent_addr
+ fipa_dialogue.update(fipa_msg)
+ self.context.outbox.put_message(message=fipa_msg)
+ elif (
+ last_fipa_message is not None
+ and last_fipa_message.performative
+ == FipaMessage.Performative.MATCH_ACCEPT_W_INFORM
+ ):
+ self.context.logger.info("sending atomic swap tx to ledger.")
+ tx_signed = signing_msg.signed_transaction
+ tx_digest = self.context.ledger_apis.get_api(
+ strategy.ledger_id
+ ).send_signed_transaction(tx_signed=tx_signed)
+ # TODO; handle case when no tx_digest returned and remove loop
+ assert tx_digest is not None, "Error when submitting tx."
+ self.context.logger.info("tx_digest={}.".format(tx_digest))
+ count = 0
+ while (
+ not self.context.ledger_apis.get_api(
strategy.ledger_id
- ).send_signed_transaction(tx_signed=tx_signed)
- # TODO; handle case when no tx_digest returned and remove loop
- assert tx_digest is not None, "Error when submitting tx."
+ ).is_transaction_settled(tx_digest)
+ and count < 20
+ ):
self.context.logger.info(
- "[{}]: tx_digest={}.".format(self.context.agent_name, tx_digest)
+ "waiting for tx to confirm. Sleeping for 3 seconds ..."
)
- count = 0
- while (
- not self.context.ledger_apis.get_api(
- strategy.ledger_id
- ).is_transaction_settled(tx_digest)
- and count < 20
- ):
- self.context.logger.info(
- "[{}]: waiting for tx to confirm. Sleeping for 3 seconds ...".format(
- self.context.agent_name
- )
- )
- time.sleep(3.0)
- count += 1
- tx_receipt = self.context.ledger_apis.get_api(
- strategy.ledger_id
- ).get_transaction_receipt(tx_digest=tx_digest)
- if tx_receipt is None:
- self.context.logger.info(
- "[{}]: Failed to get tx receipt for atomic swap.".format(
- self.context.agent_name
- )
- )
- elif tx_receipt.status != 1:
- self.context.logger.info(
- "[{}]: Failed to conduct atomic swap.".format(
- self.context.agent_name
- )
- )
- else:
- self.context.logger.info(
- "[{}]: Successfully conducted atomic swap. Transaction digest: {}".format(
- self.context.agent_name, tx_digest
- )
- )
- # contract = cast(ERC1155Contract, self.context.contracts.erc1155)
- # result = contract.get_balances(
- # address=self.context.agent_address,
- # token_ids=[
- # int(key)
- # for key in tx_message.terms.quantities_by_good_id.keys()
- # ]
- # + [
- # int(key)
- # for key in tx_message.terms.amount_by_currency_id.keys()
- # ],
- # )
- result = 0
- self.context.logger.info(
- "[{}]: Current balances: {}".format(
- self.context.agent_name, result
- )
- )
+ time.sleep(3.0)
+ count += 1
+ tx_receipt = self.context.ledger_apis.get_api(
+ strategy.ledger_id
+ ).get_transaction_receipt(tx_digest=tx_digest)
+ if tx_receipt is None:
+ self.context.logger.info("failed to get tx receipt for atomic swap.")
+ elif tx_receipt.status != 1:
+ self.context.logger.info("failed to conduct atomic swap.")
else:
- self.context.logger.warning(
- "[{}]: last message should be of performative accept or match accept.".format(
- self.context.agent_name
+ self.context.logger.info(
+ "successfully conducted atomic swap. Transaction digest: {}".format(
+ tx_digest
)
)
+ # contract = cast(ERC1155Contract, self.context.contracts.erc1155)
+ # result = contract.get_balances(
+ # address=self.context.agent_address,
+ # token_ids=[
+ # int(key)
+ # for key in tx_message.terms.quantities_by_good_id.keys()
+ # ]
+ # + [
+ # int(key)
+ # for key in tx_message.terms.amount_by_currency_id.keys()
+ # ],
+ # )
+ result = 0
+ self.context.logger.info("current balances: {}".format(result))
else:
- self.context.logger.info(
- "[{}]: transaction was not successful.".format(self.context.agent_name)
+ self.context.logger.warning(
+ "last message should be of performative accept or match accept."
)
- def teardown(self) -> None:
+ def _handle_error(
+ self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
+ ) -> None:
"""
- Implement the handler teardown.
+ Handle an oef search message.
+ :param signing_msg: the signing message
+ :param signing_dialogue: the dialogue
:return: None
"""
- pass
+ self.context.logger.info(
+ "transaction signing was not successful. Error_code={} in dialogue={}".format(
+ signing_msg.error_code, signing_dialogue
+ )
+ )
+ def _handle_invalid(
+ self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
-class OEFSearchHandler(Handler):
+ :param signing_msg: the signing message
+ :param signing_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle signing message of performative={} in dialogue={}.".format(
+ signing_msg.performative, signing_dialogue
+ )
+ )
+
+
+class OefSearchHandler(Handler):
"""This class implements the oef search handler."""
SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id # type: Optional[ProtocolId]
@@ -698,24 +820,26 @@ def handle(self, message: Message) -> None:
:param message: the message
:return: None
"""
- # convenience representations
- oef_msg = cast(OefSearchMessage, message)
-
- if oef_msg.performative is OefSearchMessage.Performative.SEARCH_RESULT:
- agents = list(oef_msg.agents)
- search_id = int(oef_msg.dialogue_reference[0])
- search = cast(Search, self.context.search)
- if self.context.agent_address in agents:
- agents.remove(self.context.agent_address)
- agents_less_self = tuple(agents)
- if search_id in search.ids_for_sellers:
- self._handle_search(
- agents_less_self, search_id, is_searching_for_sellers=True
- )
- elif search_id in search.ids_for_buyers:
- self._handle_search(
- agents_less_self, search_id, is_searching_for_sellers=False
- )
+ oef_search_msg = cast(OefSearchMessage, message)
+
+ # recover dialogue
+ oef_search_dialogues = cast(
+ OefSearchDialogues, self.context.oef_search_dialogues
+ )
+ oef_search_dialogue = cast(
+ Optional[OefSearchDialogue], oef_search_dialogues.update(oef_search_msg)
+ )
+ if oef_search_dialogue is None:
+ self._handle_unidentified_dialogue(oef_search_msg)
+ return
+
+ # handle message
+ if oef_search_msg.performative == OefSearchMessage.Performative.SEARCH_RESULT:
+ self._on_search_result(oef_search_msg, oef_search_dialogue)
+ elif oef_search_msg.performative == OefSearchMessage.Performative.OEF_ERROR:
+ self._on_oef_error(oef_search_msg, oef_search_dialogue)
+ else:
+ self._handle_invalid(oef_search_msg, oef_search_dialogue)
def teardown(self) -> None:
"""
@@ -725,6 +849,55 @@ def teardown(self) -> None:
"""
pass
+ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> None:
+ """
+ Handle an unidentified dialogue.
+
+ :param msg: the message
+ """
+ self.context.logger.warning(
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
+ )
+ )
+
+ def _on_oef_error(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an OEF error message.
+
+ :param oef_search_msg: the oef search msg
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "received OEF Search error: dialogue_reference={}, oef_error_operation={}".format(
+ oef_search_msg.dialogue_reference, oef_search_msg.oef_error_operation,
+ )
+ )
+
+ def _on_search_result(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Split the search results from the OEF search node.
+
+ :param oef_search_msg: the search result
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ agents = list(oef_search_msg.agents)
+ search_id = int(oef_search_msg.dialogue_reference[0])
+ if self.context.agent_address in agents:
+ agents.remove(self.context.agent_address)
+ agents_less_self = tuple(agents)
+ self._handle_search(
+ agents_less_self,
+ search_id,
+ is_searching_for_sellers=oef_search_dialogue.is_seller_search,
+ )
+
def _handle_search(
self, agents: Tuple[str, ...], search_id: int, is_searching_for_sellers: bool
) -> None:
@@ -738,38 +911,45 @@ def _handle_search(
searched_for = "sellers" if is_searching_for_sellers else "buyers"
if len(agents) > 0:
self.context.logger.info(
- "[{}]: found potential {} agents={} on search_id={}.".format(
- self.context.agent_name,
- searched_for,
- list(map(lambda x: x[-5:], agents)),
- search_id,
+ "found potential {} agents={} on search_id={}.".format(
+ searched_for, list(map(lambda x: x[-5:], agents)), search_id,
)
)
strategy = cast(Strategy, self.context.strategy)
- dialogues = cast(Dialogues, self.context.dialogues)
- query = strategy.get_own_services_query(
- is_searching_for_sellers, is_search_query=False
- )
+ fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues)
+ query = strategy.get_own_services_query(is_searching_for_sellers)
for opponent_addr in agents:
self.context.logger.info(
- "[{}]: sending CFP to agent={}".format(
- self.context.agent_name, opponent_addr[-5:]
- )
+ "sending CFP to agent={}".format(opponent_addr[-5:])
)
fipa_msg = FipaMessage(
- message_id=Dialogue.STARTING_MESSAGE_ID,
- dialogue_reference=dialogues.new_self_initiated_dialogue_reference(),
+ dialogue_reference=fipa_dialogues.new_self_initiated_dialogue_reference(),
performative=FipaMessage.Performative.CFP,
- target=Dialogue.STARTING_TARGET,
query=query,
)
fipa_msg.counterparty = opponent_addr
- dialogues.update(fipa_msg)
+ fipa_dialogues.update(fipa_msg)
self.context.outbox.put_message(message=fipa_msg)
else:
self.context.logger.info(
- "[{}]: found no {} agents on search_id={}, continue searching.".format(
- self.context.agent_name, searched_for, search_id
+ "found no {} agents on search_id={}, continue searching.".format(
+ searched_for, search_id
)
)
+
+ def _handle_invalid(
+ self, oef_search_msg: OefSearchMessage, oef_search_dialogue: OefSearchDialogue
+ ) -> None:
+ """
+ Handle an oef search message.
+
+ :param oef_search_msg: the oef search message
+ :param oef_search_dialogue: the dialogue
+ :return: None
+ """
+ self.context.logger.warning(
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
+ )
+ )
diff --git a/packages/fetchai/skills/tac_negotiation/helpers.py b/packages/fetchai/skills/tac_negotiation/helpers.py
index f8874798c4..ce8a30f6d2 100644
--- a/packages/fetchai/skills/tac_negotiation/helpers.py
+++ b/packages/fetchai/skills/tac_negotiation/helpers.py
@@ -19,12 +19,9 @@
"""This class contains the helpers for FIPA negotiation."""
-import collections
import copy
from typing import Dict, List, Union, cast
-from web3 import Web3
-
from aea.helpers.search.models import (
Attribute,
Constraint,
@@ -35,11 +32,9 @@
Or,
Query,
)
-from aea.mail.base import Address
SUPPLY_DATAMODEL_NAME = "supply"
DEMAND_DATAMODEL_NAME = "demand"
-PREFIX = "pre_"
def _build_goods_datamodel(good_ids: List[str], is_supply: bool) -> DataModel:
@@ -54,67 +49,55 @@ def _build_goods_datamodel(good_ids: List[str], is_supply: bool) -> DataModel:
good_quantities_attributes = [
Attribute(good_id, int, True, "A good on offer.") for good_id in good_ids
]
+ ledger_id_attribute = Attribute(
+ "ledger_id", str, True, "The ledger for transacting."
+ )
currency_attribute = Attribute(
"currency_id", str, True, "The currency for pricing and transacting the goods."
)
price_attribute = Attribute(
"price", int, False, "The price of the goods in the currency."
)
- seller_tx_fee_attribute = Attribute(
- "seller_tx_fee",
- int,
- False,
- "The transaction fee payable by the seller in the currency.",
- )
- buyer_tx_fee_attribute = Attribute(
- "buyer_tx_fee",
- int,
- False,
- "The transaction fee payable by the buyer in the currency.",
+ fee_attribute = Attribute(
+ "fee", int, False, "The transaction fee payable by the buyer in the currency.",
)
- tx_nonce_attribute = Attribute(
- "tx_nonce", str, False, "The nonce to distinguish identical descriptions."
+ nonce_attribute = Attribute(
+ "nonce", str, False, "The nonce to distinguish identical descriptions."
)
description = SUPPLY_DATAMODEL_NAME if is_supply else DEMAND_DATAMODEL_NAME
attributes = good_quantities_attributes + [
+ ledger_id_attribute,
currency_attribute,
price_attribute,
- seller_tx_fee_attribute,
- buyer_tx_fee_attribute,
- tx_nonce_attribute,
+ fee_attribute,
+ nonce_attribute,
]
data_model = DataModel(description, attributes)
return data_model
def build_goods_description(
- good_id_to_quantities: Dict[str, int],
+ quantities_by_good_id: Dict[str, int],
currency_id: str,
+ ledger_id: str,
is_supply: bool,
- is_search_description: bool,
) -> Description:
"""
Get the service description (good quantities supplied or demanded and their price).
- :param good_id_to_quantities: a dictionary mapping the ids of the goods to the quantities.
+ :param quantities_by_good_id: a dictionary mapping the ids of the goods to the quantities.
:param currency_id: the currency used for pricing and transacting.
+ :param ledger_id: the ledger used for transacting.
:param is_supply: True if the description is indicating supply, False if it's indicating demand.
- :param is_search_description: Whether or not the description is used for search
:return: the description to advertise on the Service Directory.
"""
- _good_id_to_quantities = copy.copy(good_id_to_quantities)
- if is_search_description:
- # the OEF does not accept attribute names consisting of integers only
- _good_id_to_quantities = {
- PREFIX + good_id: quantity
- for good_id, quantity in _good_id_to_quantities.items()
- }
data_model = _build_goods_datamodel(
- good_ids=list(_good_id_to_quantities.keys()), is_supply=is_supply
+ good_ids=list(quantities_by_good_id.keys()), is_supply=is_supply
)
- values = cast(Dict[str, Union[int, str]], _good_id_to_quantities)
+ values = cast(Dict[str, Union[int, str]], copy.copy(quantities_by_good_id))
values.update({"currency_id": currency_id})
+ values.update({"ledger_id": ledger_id})
desc = Description(values, data_model=data_model)
return desc
@@ -122,8 +105,8 @@ def build_goods_description(
def build_goods_query(
good_ids: List[str],
currency_id: str,
+ ledger_id: str,
is_searching_for_sellers: bool,
- is_search_query: bool,
) -> Query:
"""
Build buyer or seller search query.
@@ -141,119 +124,22 @@ def build_goods_query(
:param good_ids: the list of good ids to put in the query
:param currency_id: the currency used for pricing and transacting.
+ :param ledger_id: the ledger used for transacting.
:param is_searching_for_sellers: Boolean indicating whether the query is for sellers (supply) or buyers (demand).
- :param is_search_query: whether or not the query is used for search on OEF
:return: the query
"""
- if is_search_query:
- # the OEF does not accept attribute names consisting of integers only
- good_ids = [PREFIX + good_id for good_id in good_ids]
-
data_model = _build_goods_datamodel(
good_ids=good_ids, is_supply=is_searching_for_sellers
)
constraints = [Constraint(good_id, ConstraintType(">=", 1)) for good_id in good_ids]
constraints.append(Constraint("currency_id", ConstraintType("==", currency_id)))
+ constraints.append(Constraint("ledger_id", ConstraintType("==", ledger_id)))
constraint_expr = cast(List[ConstraintExpr], constraints)
if len(good_ids) > 1:
+ # TODO: fix
constraint_expr = [Or(constraint_expr)]
query = Query(constraint_expr, model=data_model)
return query
-
-
-def _get_hash(
- tx_sender_addr: Address,
- tx_counterparty_addr: Address,
- good_ids: List[int],
- sender_supplied_quantities: List[int],
- counterparty_supplied_quantities: List[int],
- tx_amount: int,
- tx_nonce: int,
-) -> bytes:
- """
- Generate a hash from transaction information.
-
- :param tx_sender_addr: the sender address
- :param tx_counterparty_addr: the counterparty address
- :param good_ids: the list of good ids
- :param sender_supplied_quantities: the quantities supplied by the sender (must all be positive)
- :param counterparty_supplied_quantities: the quantities supplied by the counterparty (must all be positive)
- :param tx_amount: the amount of the transaction
- :param tx_nonce: the nonce of the transaction
- :return: the hash
- """
- aggregate_hash = Web3.keccak(
- b"".join(
- [
- good_ids[0].to_bytes(32, "big"),
- sender_supplied_quantities[0].to_bytes(32, "big"),
- counterparty_supplied_quantities[0].to_bytes(32, "big"),
- ]
- )
- )
- for idx, good_id in enumerate(good_ids):
- if not idx == 0:
- aggregate_hash = Web3.keccak(
- b"".join(
- [
- aggregate_hash,
- good_id.to_bytes(32, "big"),
- sender_supplied_quantities[idx].to_bytes(32, "big"),
- counterparty_supplied_quantities[idx].to_bytes(32, "big"),
- ]
- )
- )
-
- m_list = [] # type: List[bytes]
- m_list.append(tx_sender_addr.encode("utf-8"))
- m_list.append(tx_counterparty_addr.encode("utf-8"))
- m_list.append(aggregate_hash)
- m_list.append(tx_amount.to_bytes(32, "big"))
- m_list.append(tx_nonce.to_bytes(32, "big"))
- return Web3.keccak(b"".join(m_list))
-
-
-def tx_hash_from_values(
- tx_sender_addr: str,
- tx_counterparty_addr: str,
- tx_quantities_by_good_id: Dict[str, int],
- tx_amount_by_currency_id: Dict[str, int],
- tx_nonce: int,
-) -> bytes:
- """
- Get the hash for a transaction based on the transaction message.
-
- :param tx_message: the transaction message
- :return: the hash
- """
- _tx_quantities_by_good_id = {
- int(good_id): quantity for good_id, quantity in tx_quantities_by_good_id.items()
- } # type: Dict[int, int]
- ordered = collections.OrderedDict(sorted(_tx_quantities_by_good_id.items()))
- good_uids = [] # type: List[int]
- sender_supplied_quantities = [] # type: List[int]
- counterparty_supplied_quantities = [] # type: List[int]
- for good_uid, quantity in ordered.items():
- good_uids.append(good_uid)
- if quantity >= 0:
- sender_supplied_quantities.append(quantity)
- counterparty_supplied_quantities.append(0)
- else:
- sender_supplied_quantities.append(0)
- counterparty_supplied_quantities.append(-quantity)
- assert len(tx_amount_by_currency_id) == 1
- for amount in tx_amount_by_currency_id.values():
- tx_amount = amount if amount >= 0 else 0
- tx_hash = _get_hash(
- tx_sender_addr=tx_sender_addr,
- tx_counterparty_addr=tx_counterparty_addr,
- good_ids=good_uids,
- sender_supplied_quantities=sender_supplied_quantities,
- counterparty_supplied_quantities=counterparty_supplied_quantities,
- tx_amount=tx_amount,
- tx_nonce=tx_nonce,
- )
- return tx_hash
diff --git a/packages/fetchai/skills/tac_negotiation/registration.py b/packages/fetchai/skills/tac_negotiation/registration.py
deleted file mode 100644
index 7b177e0ff7..0000000000
--- a/packages/fetchai/skills/tac_negotiation/registration.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- coding: utf-8 -*-
-# ------------------------------------------------------------------------------
-#
-# Copyright 2018-2019 Fetch.AI Limited
-#
-# 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 package contains a class representing the registration state."""
-
-import datetime
-from typing import Optional
-
-from aea.helpers.search.models import Description
-from aea.skills.base import Model
-
-
-class Registration(Model):
- """This class deals with the services registration state."""
-
- def __init__(self, **kwargs):
- """Instantiate the search class."""
- self._update_interval = kwargs.pop("update_interval", 5) # type: int
- super().__init__(**kwargs)
- self._id = 0
- self.registered_goods_demanded_description = None # type: Optional[Description]
- self.registered_goods_supplied_description = None # type: Optional[Description]
- self._last_update_time = datetime.datetime.now() # type: datetime.datetime
-
- @property
- def id(self) -> int:
- """Get the search id."""
- return self._id
-
- def get_next_id(self) -> int:
- """
- Generate the next search id and stores it.
-
- :return: a search id
- """
- self._id += 1
- return self.id
-
- def is_time_to_update_services(self) -> bool:
- """
- Check if the agent should update the service directory.
-
- :return: bool indicating the action
- """
- now = datetime.datetime.now()
- diff = now - self._last_update_time
- result = diff.total_seconds() > self._update_interval
- if result:
- self._last_update_time = now
- return result
diff --git a/packages/fetchai/skills/tac_negotiation/search.py b/packages/fetchai/skills/tac_negotiation/search.py
deleted file mode 100644
index d407f89c5c..0000000000
--- a/packages/fetchai/skills/tac_negotiation/search.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-# ------------------------------------------------------------------------------
-#
-# Copyright 2018-2019 Fetch.AI Limited
-#
-# 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 package contains a class representing the search state."""
-
-import datetime
-from typing import Set
-
-from aea.skills.base import Model
-
-
-class Search(Model):
- """This class deals with the services search state."""
-
- def __init__(self, **kwargs):
- """Instantiate the search class."""
- self._search_interval = kwargs.pop("search_interval", 5) # type: int
- super().__init__(**kwargs)
- self._id = 0
- self._ids_for_sellers = set() # type: Set[int]
- self._ids_for_buyers = set() # type: Set[int]
- self._last_search_time = datetime.datetime.now() # type: datetime.datetime
-
- @property
- def id(self) -> int:
- """Get the search id."""
- return self._id
-
- @property
- def ids_for_sellers(self) -> Set[int]:
- """Get search ids for the sellers."""
- return self._ids_for_sellers
-
- @property
- def ids_for_buyers(self) -> Set[int]:
- """Get search ids for the buyers."""
- return self._ids_for_buyers
-
- def get_next_id(self, is_searching_for_sellers: bool) -> int:
- """
- Generate the next search id and stores it.
-
- :param is_searching_for_sellers: whether it is a seller search
- :return: a search id
- """
- self._id += 1
- if is_searching_for_sellers:
- self._ids_for_sellers.add(self.id)
- else:
- self._ids_for_buyers.add(self.id)
- return self.id
-
- def is_time_to_search_services(self) -> bool:
- """
- Check if the agent should search the service directory.
-
- :return: bool indicating the action
- """
- now = datetime.datetime.now()
- diff = now - self._last_search_time
- result = diff.total_seconds() > self._search_interval
- if result:
- self._last_search_time = now
- return result
diff --git a/packages/fetchai/skills/tac_negotiation/skill.yaml b/packages/fetchai/skills/tac_negotiation/skill.yaml
index 3725318581..0e10bd3a6b 100644
--- a/packages/fetchai/skills/tac_negotiation/skill.yaml
+++ b/packages/fetchai/skills/tac_negotiation/skill.yaml
@@ -1,63 +1,69 @@
name: tac_negotiation
author: fetchai
-version: 0.5.0
+version: 0.6.0
description: The tac negotiation skill implements the logic for an AEA to do fipa
negotiation in the TAC.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmcgZLvHebdfocqBmbu6gJp35khs6nbdbC649jzUyS86wy
- behaviours.py: QmSgtvb4rD4RZ5H2zQQqPUwBzAeoR6ZBTJ1p33YqL5XjMe
- dialogues.py: QmZe9PJncaWzJ4yn9b76Mm5R93VLNxGVd5ogUWhfp8Q6km
- handlers.py: QmSdEvCaP9JnfQVcEpLvnzy6c8Uva24ifbGMkr2hFy5qFZ
- helpers.py: QmXa3aD15jcv3NiEAcTjqrKNHv7U1ZQfES9siknL1kLtbV
- registration.py: QmexnkCCmyiFpzM9bvXNj5uQuxQ2KfBTUeMomuGN9ccP7g
- search.py: QmSTtMm4sHUUhUFsQzufHjKihCEVe5CaU5MGjhzSdPUzDT
- strategy.py: QmQMSPqS3TZxhQoh6SUA8u2c5BNTxYGV95DSQc4neen6Ja
- transactions.py: QmTCErZmswHAx6UXfPkrredRDKVnLYhyVEBtm5ppSJpZBf
+ behaviours.py: QmWYDj8QSx1qYCteS7nWXKJEsh7UChNrf45HJ7rQVdQhwY
+ dialogues.py: QmWXhnspH2NJjV5qh7wfnNUiMfe6FGhxjeJvdTV8YoWPPT
+ handlers.py: QmSm9wYxLYfRbeA5NwNwDz1Az5xPeR3ACyujYRvmotztEJ
+ helpers.py: QmUMCBgsZ5tB24twoWjfGibb1v5uDpUBxHPtzqZbzbvyL1
+ strategy.py: QmdrwXQVW49zkACzaFEbpyjX11fz7aC8riLxXamsvekR1v
+ transactions.py: QmZkb2GfiGHwSSQuMafEkGKF4GHiyNu6mQancZkTWS7D6F
fingerprint_ignore_patterns: []
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/fipa:0.4.0
-- fetchai/oef_search:0.3.0
-skills: []
+- fetchai/fipa:0.5.0
+- fetchai/oef_search:0.4.0
+skills:
+- fetchai/tac_participation:0.5.0
behaviours:
clean_up:
args:
tick_interval: 5.0
class_name: TransactionCleanUpBehaviour
tac_negotiation:
- args: {}
+ args:
+ search_interval: 5.0
class_name: GoodsRegisterAndSearchBehaviour
handlers:
fipa:
args: {}
- class_name: FIPANegotiationHandler
+ class_name: FipaNegotiationHandler
oef:
args: {}
- class_name: OEFSearchHandler
- transaction:
+ class_name: OefSearchHandler
+ signing:
args: {}
- class_name: TransactionHandler
+ class_name: SigningHandler
models:
- dialogues:
+ default_dialogues:
args: {}
- class_name: Dialogues
- registration:
- args:
- update_interval: 5
- class_name: Registration
- search:
- args:
- search_interval: 5
- class_name: Search
+ class_name: DefaultDialogues
+ fipa_dialogues:
+ args: {}
+ class_name: FipaDialogues
+ oef_search_dialogues:
+ args: {}
+ class_name: OefSearchDialogues
+ signing_dialogues:
+ args: {}
+ class_name: SigningDialogues
strategy:
args:
is_contract_tx: false
ledger_id: cosmos
+ location:
+ latitude: 0.127
+ longitude: 51.5194
register_as: both
search_for: both
+ search_radius: 5.0
+ service_key: tac_service
class_name: Strategy
transactions:
args:
diff --git a/packages/fetchai/skills/tac_negotiation/strategy.py b/packages/fetchai/skills/tac_negotiation/strategy.py
index 192d2df52a..1380ea46a3 100644
--- a/packages/fetchai/skills/tac_negotiation/strategy.py
+++ b/packages/fetchai/skills/tac_negotiation/strategy.py
@@ -22,13 +22,25 @@
import copy
import random
from enum import Enum
-from typing import Dict, Optional, cast
+from typing import Dict, List, Optional, Tuple, cast
-from aea.helpers.search.models import Description, Query
+from aea.decision_maker.default import OwnershipState, Preferences
+from aea.helpers.search.generic import (
+ AGENT_LOCATION_MODEL,
+ AGENT_REMOVE_SERVICE_MODEL,
+ AGENT_SET_SERVICE_MODEL,
+)
+from aea.helpers.search.models import (
+ Constraint,
+ ConstraintType,
+ Description,
+ Location,
+ Query,
+)
from aea.protocols.signing.message import SigningMessage
from aea.skills.base import Model
-from packages.fetchai.skills.tac_negotiation.dialogues import Dialogue
+from packages.fetchai.skills.tac_negotiation.dialogues import FipaDialogue
from packages.fetchai.skills.tac_negotiation.helpers import (
build_goods_description,
build_goods_query,
@@ -37,6 +49,14 @@
ROUNDING_ADJUSTMENT = 1
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SERVICE_KEY = "tac_service"
+DEFAULT_SEARCH_QUERY = {
+ "search_key": "tac_service",
+ "search_value": "generic_service",
+ "constraint_type": "==",
+}
+DEFAULT_SEARCH_RADIUS = 5.0
class Strategy(Model):
@@ -69,39 +89,83 @@ def __init__(self, **kwargs) -> None:
self._search_for = Strategy.SearchFor(kwargs.pop("search_for", "both"))
self._is_contract_tx = kwargs.pop("is_contract_tx", False)
self._ledger_id = kwargs.pop("ledger_id", "ethereum")
- super().__init__(**kwargs)
- @property
- def is_registering_as_seller(self) -> bool:
- """Check if the agent registers as a seller on the OEF service directory."""
- return (
- self._register_as == Strategy.RegisterAs.SELLER
- or self._register_as == Strategy.RegisterAs.BUYER
- )
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = {
+ "location": Location(location["longitude"], location["latitude"])
+ }
+ service_key = kwargs.pop("service_key", DEFAULT_SERVICE_KEY)
+ self._set_service_data = {"key": service_key, "value": self._register_as.value}
+ self._remove_service_data = {"key": service_key}
+ self._simple_service_data = {service_key: self._register_as.value}
+ self._search_query = {
+ "search_key": service_key,
+ "search_value": self._search_for.value,
+ "constraint_type": "==",
+ }
+ self._radius = kwargs.pop("search_radius", DEFAULT_SEARCH_RADIUS)
+
+ super().__init__(**kwargs)
@property
- def is_searching_for_sellers(self) -> bool:
- """Check if the agent searches for sellers on the OEF service directory."""
+ def registering_as(self) -> str:
+ """Get what the agent is registering as."""
return (
- self._search_for == Strategy.SearchFor.SELLERS
- or self._search_for == Strategy.SearchFor.BOTH
+ self._register_as.value
+ if self._register_as != self.RegisterAs.BOTH
+ else "buyer and seller"
)
@property
- def is_registering_as_buyer(self) -> bool:
- """Check if the agent registers as a buyer on the OEF service directory."""
+ def searching_for(self) -> str:
+ """Get what the agent is searching for."""
return (
- self._register_as == Strategy.RegisterAs.BUYER
- or self._register_as == Strategy.RegisterAs.BOTH
+ self._search_for.value
+ if self._search_for != self.SearchFor.BOTH
+ else "buyer and seller"
)
@property
- def is_searching_for_buyers(self) -> bool:
- """Check if the agent searches for buyers on the OEF service directory."""
- return (
- self._search_for == Strategy.SearchFor.BUYERS
- or self._search_for == Strategy.SearchFor.BOTH
- )
+ def searching_for_types(self) -> List[Tuple[bool, str]]:
+ """Get the types the agent is searching for."""
+ result = [] # type: List[Tuple[bool, str]]
+ if self._search_for in [self.SearchFor.SELLERS, self.SearchFor.BOTH]:
+ result.append((True, "sellers"))
+ if self._search_for in [self.SearchFor.BUYERS, self.SearchFor.BOTH]:
+ result.append((False, "buyers"))
+ return result
+
+ # @property
+ # def is_registering_as_seller(self) -> bool:
+ # """Check if the agent registers as a seller on the OEF service directory."""
+ # return (
+ # self._register_as == Strategy.RegisterAs.SELLER
+ # or self._register_as == Strategy.RegisterAs.BUYER
+ # )
+
+ # @property
+ # def is_searching_for_sellers(self) -> bool:
+ # """Check if the agent searches for sellers on the OEF service directory."""
+ # return (
+ # self._search_for == Strategy.SearchFor.SELLERS
+ # or self._search_for == Strategy.SearchFor.BOTH
+ # )
+
+ # @property
+ # def is_registering_as_buyer(self) -> bool:
+ # """Check if the agent registers as a buyer on the OEF service directory."""
+ # return (
+ # self._register_as == Strategy.RegisterAs.BUYER
+ # or self._register_as == Strategy.RegisterAs.BOTH
+ # )
+
+ # @property
+ # def is_searching_for_buyers(self) -> bool:
+ # """Check if the agent searches for buyers on the OEF service directory."""
+ # return (
+ # self._search_for == Strategy.SearchFor.BUYERS
+ # or self._search_for == Strategy.SearchFor.BOTH
+ # )
@property
def is_contract_tx(self) -> bool:
@@ -113,32 +177,84 @@ def ledger_id(self) -> str:
"""Get the ledger id."""
return self._ledger_id
- def get_own_service_description(
- self, is_supply: bool, is_search_description: bool
- ) -> Description:
+ def get_location_description(self) -> Description:
"""
- Get the description of the supplied goods (as a seller), or the demanded goods (as a buyer).
+ Get the location description.
- :param is_supply: Boolean indicating whether it is supply or demand.
- :param is_search_description: whether or not the description is for search.
+ :return: a description of the agent's location
+ """
+ description = Description(
+ self._agent_location, data_model=AGENT_LOCATION_MODEL,
+ )
+ return description
+ def get_register_service_description(self) -> Description:
+ """
+ Get the register service description.
+
+ :return: a description of the offered services
+ """
+ description = Description(
+ self._set_service_data, data_model=AGENT_SET_SERVICE_MODEL,
+ )
+ return description
+
+ def get_unregister_service_description(self) -> Description:
+ """
+ Get the unregister service description.
+
+ :return: a description of the to be removed service
+ """
+ description = Description(
+ self._remove_service_data, data_model=AGENT_REMOVE_SERVICE_MODEL,
+ )
+ return description
+
+ def get_location_and_service_query(self) -> Query:
+ """
+ Get the location and service query of the agent.
+
+ :return: the query
+ """
+ close_to_my_service = Constraint(
+ "location",
+ ConstraintType(
+ "distance", (self._agent_location["location"], self._radius)
+ ),
+ )
+ service_key_filter = Constraint(
+ self._search_query["search_key"],
+ ConstraintType(
+ self._search_query["constraint_type"],
+ self._search_query["search_value"],
+ ),
+ )
+ query = Query([close_to_my_service, service_key_filter],)
+ return query
+
+ def get_own_service_description(self, is_supply: bool) -> Description:
+ """
+ Get the description of the supplied goods (as a seller), or the demanded goods (as a buyer).
+ :param is_supply: Boolean indicating whether it is supply or demand.
:return: the description (to advertise on the Service Directory).
"""
transactions = cast(Transactions, self.context.transactions)
ownership_state_after_locks = transactions.ownership_state_after_locks(
is_seller=is_supply
)
- good_id_to_quantities = (
+ quantities_by_good_id = (
self._supplied_goods(ownership_state_after_locks.quantities_by_good_id)
if is_supply
else self._demanded_goods(ownership_state_after_locks.quantities_by_good_id)
)
- currency_id = list(ownership_state_after_locks.amount_by_currency_id.keys())[0]
+ currency_id = next(
+ iter(ownership_state_after_locks.amount_by_currency_id.keys())
+ )
desc = build_goods_description(
- good_id_to_quantities=good_id_to_quantities,
+ quantities_by_good_id=quantities_by_good_id,
currency_id=currency_id,
+ ledger_id=self.ledger_id,
is_supply=is_supply,
- is_search_description=is_search_description,
)
return desc
@@ -168,9 +284,7 @@ def _demanded_goods(good_holdings: Dict[str, int]) -> Dict[str, int]:
demand[good_id] = 1
return demand
- def get_own_services_query(
- self, is_searching_for_sellers: bool, is_search_query: bool
- ) -> Query:
+ def get_own_services_query(self, is_searching_for_sellers: bool,) -> Query:
"""
Build a query.
@@ -179,7 +293,6 @@ def get_own_services_query(
- which demand the agent's supplied goods (i.e. buyers).
:param is_searching_for_sellers: Boolean indicating whether the search is for sellers or buyers.
- :param is_search_query: whether or not the query is used for search on OEF
:return: the Query, or None.
"""
@@ -192,12 +305,14 @@ def get_own_services_query(
if is_searching_for_sellers
else self._supplied_goods(ownership_state_after_locks.quantities_by_good_id)
)
- currency_id = list(ownership_state_after_locks.amount_by_currency_id.keys())[0]
+ currency_id = next(
+ iter(ownership_state_after_locks.amount_by_currency_id.keys())
+ )
query = build_goods_query(
good_ids=list(good_id_to_quantities.keys()),
currency_id=currency_id,
+ ledger_id=self.ledger_id,
is_searching_for_sellers=is_searching_for_sellers,
- is_search_query=is_search_query,
)
return query
@@ -224,7 +339,7 @@ def _get_proposal_for_query(
return random.choice(proposals) # nosec
def get_proposal_for_query(
- self, query: Query, role: Dialogue.Role
+ self, query: Query, role: FipaDialogue.Role
) -> Optional[Description]:
"""
Generate proposal (in the form of a description) which matches the query.
@@ -234,17 +349,11 @@ def get_proposal_for_query(
:return: a description
"""
- is_seller = role == Dialogue.Role.SELLER
+ is_seller = role == FipaDialogue.Role.SELLER
- own_service_description = self.get_own_service_description(
- is_supply=is_seller, is_search_description=False
- )
+ own_service_description = self.get_own_service_description(is_supply=is_seller,)
if not query.check(own_service_description):
- self.context.logger.debug(
- "[{}]: Current holdings do not satisfy CFP query.".format(
- self.context.agent_name
- )
- )
+ self.context.logger.debug("current holdings do not satisfy CFP query.")
return None
else:
proposal_description = self._get_proposal_for_query(
@@ -252,9 +361,7 @@ def get_proposal_for_query(
)
if proposal_description is None:
self.context.logger.debug(
- "[{}]: Current strategy does not generate proposal that satisfies CFP query.".format(
- self.context.agent_name
- )
+ "current strategy does not generate proposal that satisfies CFP query."
)
return proposal_description
@@ -279,25 +386,25 @@ def _generate_candidate_proposals(self, is_seller: bool):
good_id: 0 for good_id in good_id_to_quantities.keys()
} # type: Dict[str, int]
proposals = []
- seller_tx_fee = (
- self.context.decision_maker_handler_context.preferences.seller_transaction_fee
+ fee_by_currency_id = self.context.shared_state.get("tx_fee", {"FET": 0})
+ buyer_tx_fee = next(iter(fee_by_currency_id.values()))
+ ownership_state = cast(
+ OwnershipState, self.context.decision_maker_handler_context.ownership_state
)
- buyer_tx_fee = (
- self.context.decision_maker_handler_context.preferences.buyer_transaction_fee
+ currency_id = list(ownership_state.amount_by_currency_id.keys())[0]
+ preferences = cast(
+ Preferences, self.context.decision_maker_handler_context.preferences
)
- currency_id = list(
- self.context.decision_maker_handler_context.ownership_state.amount_by_currency_id.keys()
- )[0]
for good_id, quantity in good_id_to_quantities.items():
if is_seller and quantity == 0:
continue
proposal_dict = copy.copy(nil_proposal_dict)
proposal_dict[good_id] = 1
proposal = build_goods_description(
- good_id_to_quantities=proposal_dict,
+ quantities_by_good_id=proposal_dict,
currency_id=currency_id,
+ ledger_id=self.ledger_id,
is_supply=is_seller,
- is_search_description=False,
)
if is_seller:
delta_quantities_by_good_id = {
@@ -306,7 +413,7 @@ def _generate_candidate_proposals(self, is_seller: bool):
} # type: Dict[str, int]
else:
delta_quantities_by_good_id = proposal_dict
- marginal_utility_from_delta_good_holdings = self.context.decision_maker_handler_context.preferences.marginal_utility(
+ marginal_utility_from_delta_good_holdings = preferences.marginal_utility(
ownership_state=ownership_state_after_locks,
delta_quantities_by_good_id=delta_quantities_by_good_id,
)
@@ -315,24 +422,21 @@ def _generate_candidate_proposals(self, is_seller: bool):
round(marginal_utility_from_delta_good_holdings) * switch
)
if is_seller:
- proposal.values["price"] = (
- breakeven_price_rounded + seller_tx_fee + ROUNDING_ADJUSTMENT
- )
+ proposal.values["price"] = breakeven_price_rounded + ROUNDING_ADJUSTMENT
else:
proposal.values["price"] = (
breakeven_price_rounded - buyer_tx_fee - ROUNDING_ADJUSTMENT
)
- proposal.values["seller_tx_fee"] = seller_tx_fee
- proposal.values["buyer_tx_fee"] = buyer_tx_fee
+ proposal.values["fee"] = buyer_tx_fee
if not proposal.values["price"] > 0:
continue
- tx_nonce = transactions.get_next_tx_nonce()
- proposal.values["tx_nonce"] = tx_nonce
+ nonce = transactions.get_next_nonce()
+ proposal.values["nonce"] = nonce
proposals.append(proposal)
return proposals
def is_profitable_transaction(
- self, transaction_msg: SigningMessage, role: Dialogue.Role
+ self, signing_msg: SigningMessage, role: FipaDialogue.Role
) -> bool:
"""
Check if a transaction is profitable.
@@ -342,23 +446,24 @@ def is_profitable_transaction(
- check if the transaction is consistent with the locks (enough money/holdings)
- check that we gain score.
- :param transaction_msg: the transaction_msg
+ :param signing_msg: the signing_msg
:param role: the role of the agent (seller or buyer)
:return: True if the transaction is good (as stated above), False otherwise.
"""
- is_seller = role == Dialogue.Role.SELLER
+ is_seller = role == FipaDialogue.Role.SELLER
transactions = cast(Transactions, self.context.transactions)
ownership_state_after_locks = transactions.ownership_state_after_locks(
is_seller
)
- if not ownership_state_after_locks.is_affordable_transaction(
- transaction_msg.terms
- ):
+ if not ownership_state_after_locks.is_affordable_transaction(signing_msg.terms):
return False
- proposal_delta_score = self.context.decision_maker_handler_context.preferences.utility_diff_from_transaction(
- ownership_state_after_locks, transaction_msg
+ preferences = cast(
+ Preferences, self.context.decision_maker_handler_context.preferences
+ )
+ proposal_delta_score = preferences.utility_diff_from_transaction(
+ ownership_state_after_locks, signing_msg.terms
)
if proposal_delta_score >= 0:
return True
diff --git a/packages/fetchai/skills/tac_negotiation/transactions.py b/packages/fetchai/skills/tac_negotiation/transactions.py
index 95c9823784..e811b70688 100644
--- a/packages/fetchai/skills/tac_negotiation/transactions.py
+++ b/packages/fetchai/skills/tac_negotiation/transactions.py
@@ -22,19 +22,20 @@
import copy
import datetime
from collections import defaultdict, deque
-from typing import Deque, Dict, Tuple
+from typing import Deque, Dict, List, Tuple, cast
-from aea.configurations.base import PublicId
from aea.decision_maker.default import OwnershipState
from aea.helpers.dialogue.base import DialogueLabel
from aea.helpers.search.models import Description
-from aea.helpers.transaction.base import Terms
+from aea.helpers.transaction.base import RawMessage, Terms
from aea.mail.base import Address
from aea.protocols.signing.message import SigningMessage
from aea.skills.base import Model
-from packages.fetchai.skills.tac_negotiation.dialogues import Dialogue
-from packages.fetchai.skills.tac_negotiation.helpers import tx_hash_from_values
+from packages.fetchai.skills.tac_negotiation.dialogues import (
+ FipaDialogue,
+ SigningDialogues,
+)
MessageId = int
@@ -62,8 +63,7 @@ def __init__(self, **kwargs) -> None:
self._last_update_for_transactions = (
deque()
) # type: Deque[Tuple[datetime.datetime, str]]
- self._tx_nonce = 0
- self._tx_id = 0
+ self._nonce = 0
@property
def pending_proposals(
@@ -79,22 +79,17 @@ def pending_initial_acceptances(
"""Get the pending initial acceptances."""
return self._pending_initial_acceptances
- def get_next_tx_nonce(self) -> int:
+ def get_next_nonce(self) -> str:
"""Get the next nonce."""
- self._tx_nonce += 1
- return self._tx_nonce
+ self._nonce += 1
+ return str(self._nonce)
- def get_internal_tx_id(self) -> str:
- """Get an id for internal reference of the tx."""
- self._tx_id += 1
- return str(self._tx_id)
-
- def generate_transaction_message( # pylint: disable=no-self-use
+ def generate_signing_message(
self,
performative: SigningMessage.Performative,
proposal_description: Description,
dialogue_label: DialogueLabel,
- role: Dialogue.Role,
+ role: FipaDialogue.Role,
agent_addr: Address,
) -> SigningMessage:
"""
@@ -106,28 +101,12 @@ def generate_transaction_message( # pylint: disable=no-self-use
:param agent_addr: the address of the agent
:return: a transaction message
"""
- is_seller = role == Dialogue.Role.SELLER
-
- # sender_tx_fee = (
- # proposal_description.values["seller_tx_fee"]
- # if is_seller
- # else proposal_description.values["buyer_tx_fee"]
- # )
- # counterparty_tx_fee = (
- # proposal_description.values["buyer_tx_fee"]
- # if is_seller
- # else proposal_description.values["seller_tx_fee"]
- # )
+ is_seller = role == FipaDialogue.Role.SELLER
+
goods_component = copy.copy(proposal_description.values)
[ # pylint: disable=expression-not-assigned
goods_component.pop(key)
- for key in [
- "seller_tx_fee",
- "buyer_tx_fee",
- "price",
- "currency_id",
- "tx_nonce",
- ]
+ for key in ["fee", "price", "currency_id", "nonce", "ledger_id"]
]
# switch signs based on whether seller or buyer role
amount = (
@@ -135,43 +114,55 @@ def generate_transaction_message( # pylint: disable=no-self-use
if is_seller
else -proposal_description.values["price"]
)
+ fee = proposal_description.values["fee"]
if is_seller:
for good_id in goods_component.keys():
goods_component[good_id] = goods_component[good_id] * (-1)
- tx_amount_by_currency_id = {proposal_description.values["currency_id"]: amount}
- tx_fee_by_currency_id = {proposal_description.values["currency_id"]: 1}
- tx_nonce = proposal_description.values["tx_nonce"]
- # need to hash positive.negative side separately
- tx_hash = tx_hash_from_values(
- tx_sender_addr=agent_addr,
- tx_counterparty_addr=dialogue_label.dialogue_opponent_addr,
- tx_quantities_by_good_id=goods_component,
- tx_amount_by_currency_id=tx_amount_by_currency_id,
- tx_nonce=tx_nonce,
+ amount_by_currency_id = {proposal_description.values["currency_id"]: amount}
+ fee_by_currency_id = {proposal_description.values["currency_id"]: fee}
+ nonce = proposal_description.values["nonce"]
+ ledger_id = proposal_description.values["ledger_id"]
+ terms = Terms(
+ ledger_id=ledger_id,
+ sender_address=agent_addr,
+ counterparty_address=dialogue_label.dialogue_opponent_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ is_sender_payable_tx_fee=not is_seller,
+ quantities_by_good_id=goods_component,
+ nonce=nonce,
+ fee_by_currency_id=fee_by_currency_id,
)
- skill_callback_ids = (
- (PublicId.from_str("fetchai/tac_participation:0.4.0"),)
- if performative == SigningMessage.Performative.SIGN_MESSAGE
- else (PublicId.from_str("fetchai/tac_negotiation:0.5.0"),)
+ skill_callback_ids = (str(self.context.skill_id),)
+ signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)
+ skill_callback_info = {"dialogue_label": str(dialogue_label)}
+ raw_message = RawMessage(
+ ledger_id=ledger_id, body=terms.sender_hash.encode("utf-8")
)
- transaction_msg = SigningMessage(
+ signing_msg = SigningMessage(
performative=performative,
+ dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
skill_callback_ids=skill_callback_ids,
- # tx_id=self.get_internal_tx_id(),
- terms=Terms(
- ledger_id="ethereum",
- sender_address=agent_addr,
- counterparty_address=dialogue_label.dialogue_opponent_addr,
- amount_by_currency_id=tx_amount_by_currency_id,
- is_sender_payable_tx_fee=True, # TODO: check!
- quantities_by_good_id=goods_component,
- nonce=tx_nonce,
- fee_by_currency_id=tx_fee_by_currency_id,
- ),
- skill_callback_info={"dialogue_label": dialogue_label.json},
- message=tx_hash,
+ terms=terms,
+ skill_callback_info=skill_callback_info,
+ raw_message=raw_message,
)
- return transaction_msg
+ signing_msg.counterparty = "decision_maker"
+ return signing_msg
+
+ def update_confirmed_transactions(self) -> None:
+ """
+ Update model wrt to confirmed transactions.
+
+ :return: None
+ """
+ confirmed_tx_ids = self.context.shared_state.get(
+ "confirmed_tx_ids", []
+ ) # type: List[str]
+ for transaction_id in confirmed_tx_ids:
+ # remove (safely) the associated pending proposal (if present)
+ self._locked_txs.pop(transaction_id, None)
+ self._locked_txs_as_buyer.pop(transaction_id, None)
+ self._locked_txs_as_seller.pop(transaction_id, None)
def cleanup_pending_transactions(self) -> None:
"""
@@ -195,9 +186,7 @@ def cleanup_pending_transactions(self) -> None:
# extract dialogue label and message id
transaction_id = next_item
self.context.logger.debug(
- "[{}]: Removing transaction from pending list: {}".format(
- self.context.agent_name, transaction_id
- )
+ "removing transaction from pending list: {}".format(transaction_id)
)
# remove (safely) the associated pending proposal (if present)
@@ -214,14 +203,14 @@ def add_pending_proposal(
self,
dialogue_label: DialogueLabel,
proposal_id: int,
- transaction_msg: SigningMessage,
+ signing_msg: SigningMessage,
) -> None:
"""
Add a proposal (in the form of a transaction) to the pending list.
:param dialogue_label: the dialogue label associated with the proposal
:param proposal_id: the message id of the proposal
- :param transaction_msg: the transaction message
+ :param signing_msg: the transaction message
:raise AssertionError: if the pending proposal is already present.
:return: None
@@ -230,7 +219,7 @@ def add_pending_proposal(
dialogue_label not in self._pending_proposals
and proposal_id not in self._pending_proposals[dialogue_label]
)
- self._pending_proposals[dialogue_label][proposal_id] = transaction_msg
+ self._pending_proposals[dialogue_label][proposal_id] = signing_msg
def pop_pending_proposal(
self, dialogue_label: DialogueLabel, proposal_id: int
@@ -248,21 +237,21 @@ def pop_pending_proposal(
dialogue_label in self._pending_proposals
and proposal_id in self._pending_proposals[dialogue_label]
)
- transaction_msg = self._pending_proposals[dialogue_label].pop(proposal_id)
- return transaction_msg
+ signing_msg = self._pending_proposals[dialogue_label].pop(proposal_id)
+ return signing_msg
def add_pending_initial_acceptance(
self,
dialogue_label: DialogueLabel,
proposal_id: int,
- transaction_msg: SigningMessage,
+ signing_msg: SigningMessage,
) -> None:
"""
Add an acceptance (in the form of a transaction) to the pending list.
:param dialogue_label: the dialogue label associated with the proposal
:param proposal_id: the message id of the proposal
- :param transaction_msg: the transaction message
+ :param signing_msg: the transaction message
:raise AssertionError: if the pending acceptance is already present.
:return: None
@@ -271,7 +260,7 @@ def add_pending_initial_acceptance(
dialogue_label not in self._pending_initial_acceptances
and proposal_id not in self._pending_initial_acceptances[dialogue_label]
)
- self._pending_initial_acceptances[dialogue_label][proposal_id] = transaction_msg
+ self._pending_initial_acceptances[dialogue_label][proposal_id] = signing_msg
def pop_pending_initial_acceptance(
self, dialogue_label: DialogueLabel, proposal_id: int
@@ -289,10 +278,8 @@ def pop_pending_initial_acceptance(
dialogue_label in self._pending_initial_acceptances
and proposal_id in self._pending_initial_acceptances[dialogue_label]
)
- transaction_msg = self._pending_initial_acceptances[dialogue_label].pop(
- proposal_id
- )
- return transaction_msg
+ signing_msg = self._pending_initial_acceptances[dialogue_label].pop(proposal_id)
+ return signing_msg
def _register_transaction_with_time(self, transaction_id: str) -> None:
"""
@@ -306,43 +293,43 @@ def _register_transaction_with_time(self, transaction_id: str) -> None:
self._last_update_for_transactions.append((now, transaction_id))
def add_locked_tx(
- self, transaction_msg: SigningMessage, role: Dialogue.Role
+ self, signing_msg: SigningMessage, role: FipaDialogue.Role
) -> None:
"""
Add a lock (in the form of a transaction).
- :param transaction_msg: the transaction message
+ :param signing_msg: the transaction message
:param role: the role of the agent (seller or buyer)
:raise AssertionError: if the transaction is already present.
:return: None
"""
- as_seller = role == Dialogue.Role.SELLER
+ as_seller = role == FipaDialogue.Role.SELLER
- transaction_id = transaction_msg.dialogue_reference[0] # TODO: fix
+ transaction_id = signing_msg.terms.id
assert transaction_id not in self._locked_txs
self._register_transaction_with_time(transaction_id)
- self._locked_txs[transaction_id] = transaction_msg
+ self._locked_txs[transaction_id] = signing_msg
if as_seller:
- self._locked_txs_as_seller[transaction_id] = transaction_msg
+ self._locked_txs_as_seller[transaction_id] = signing_msg
else:
- self._locked_txs_as_buyer[transaction_id] = transaction_msg
+ self._locked_txs_as_buyer[transaction_id] = signing_msg
- def pop_locked_tx(self, transaction_msg: SigningMessage) -> SigningMessage:
+ def pop_locked_tx(self, signing_msg: SigningMessage) -> SigningMessage:
"""
Remove a lock (in the form of a transaction).
- :param transaction_msg: the transaction message
+ :param signing_msg: the transaction message
:raise AssertionError: if the transaction with the given transaction id has not been found.
:return: the transaction
"""
- transaction_id = transaction_msg.dialogue_reference[0] # TODO: fix
+ transaction_id = signing_msg.terms.id
assert transaction_id in self._locked_txs
- transaction_msg = self._locked_txs.pop(transaction_id)
+ signing_msg = self._locked_txs.pop(transaction_id)
self._locked_txs_as_buyer.pop(transaction_id, None)
self._locked_txs_as_seller.pop(transaction_id, None)
- return transaction_msg
+ return signing_msg
def ownership_state_after_locks(self, is_seller: bool) -> OwnershipState:
"""
@@ -354,12 +341,14 @@ def ownership_state_after_locks(self, is_seller: bool) -> OwnershipState:
:return: the agent state with the locks applied to current state
"""
- transaction_msgs = (
+ signing_msgs = (
list(self._locked_txs_as_seller.values())
if is_seller
else list(self._locked_txs_as_buyer.values())
)
- ownership_state_after_locks = self.context.decision_maker_handler_context.ownership_state.apply_transactions(
- transaction_msgs
+ terms = [signing_msg.terms for signing_msg in signing_msgs]
+ ownership_state = cast(
+ OwnershipState, self.context.decision_maker_handler_context.ownership_state
)
+ ownership_state_after_locks = ownership_state.apply_transactions(terms)
return ownership_state_after_locks
diff --git a/packages/fetchai/skills/tac_participation/behaviours.py b/packages/fetchai/skills/tac_participation/behaviours.py
index 23ab788355..14b215c663 100644
--- a/packages/fetchai/skills/tac_participation/behaviours.py
+++ b/packages/fetchai/skills/tac_participation/behaviours.py
@@ -19,11 +19,12 @@
"""This package contains a tac search behaviour."""
-from typing import cast
+from typing import Any, Dict, cast
from aea.skills.behaviours import TickerBehaviour
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from packages.fetchai.protocols.tac.message import TacMessage
from packages.fetchai.skills.tac_participation.dialogues import OefSearchDialogues
from packages.fetchai.skills.tac_participation.game import Game, Phase
@@ -80,7 +81,75 @@ def _search_for_tac(self) -> None:
oef_search_dialogues.update(oef_search_msg)
self.context.outbox.put_message(message=oef_search_msg)
self.context.logger.info(
- "[{}]: Searching for TAC, search_id={}".format(
- self.context.agent_name, oef_search_msg.dialogue_reference
- )
+ "searching for TAC, search_id={}".format(oef_search_msg.dialogue_reference)
)
+
+
+class TransactionProcessBehaviour(TickerBehaviour):
+ """This class implements the processing of the transactions class."""
+
+ def setup(self) -> None:
+ """
+ Implement the setup.
+
+ :return: None
+ """
+ pass
+
+ def act(self) -> None:
+ """
+ Implement the task execution.
+
+ :return: None
+ """
+ game = cast(Game, self.context.game)
+ if game.phase.value == Phase.GAME.value:
+ self._process_transactions()
+
+ def teardown(self) -> None:
+ """
+ Implement the task teardown.
+
+ :return: None
+ """
+ pass
+
+ def _process_transactions(self) -> None:
+ """
+ Process transactions.
+
+ :return: None
+ """
+ game = cast(Game, self.context.game)
+ tac_dialogue = game.tac_dialogue
+ transactions = cast(
+ Dict[str, Dict[str, Any]], self.context.shared_state.get("transactions", {})
+ )
+ for tx_id, tx_content in transactions.items():
+ self.context.logger.info(
+ "sending transaction {} to controller.".format(tx_id)
+ )
+ last_msg = tac_dialogue.last_message
+ assert last_msg is not None, "No last message available."
+ terms = tx_content["terms"]
+ sender_signature = tx_content["sender_signature"]
+ counterparty_signature = tx_content["counterparty_signature"]
+ msg = TacMessage(
+ performative=TacMessage.Performative.TRANSACTION,
+ dialogue_reference=tac_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
+ transaction_id=tx_id,
+ ledger_id=terms.ledger_id,
+ sender_address=terms.sender_address,
+ counterparty_address=terms.counterparty_address,
+ amount_by_currency_id=terms.amount_by_currency_id,
+ fee_by_currency_id=terms.fee_by_currency_id,
+ quantities_by_good_id=terms.quantities_by_good_id,
+ sender_signature=sender_signature,
+ counterparty_signature=counterparty_signature,
+ nonce=terms.nonce,
+ )
+ msg.counterparty = game.conf.controller_addr
+ tac_dialogue.update(msg)
+ self.context.outbox.put_message(message=msg)
diff --git a/packages/fetchai/skills/tac_participation/dialogues.py b/packages/fetchai/skills/tac_participation/dialogues.py
index 9717b8f190..deaf872cdd 100644
--- a/packages/fetchai/skills/tac_participation/dialogues.py
+++ b/packages/fetchai/skills/tac_participation/dialogues.py
@@ -31,8 +31,12 @@
from aea.helpers.dialogue.base import Dialogue as BaseDialogue
from aea.helpers.dialogue.base import DialogueLabel as BaseDialogueLabel
from aea.protocols.base import Message
-from aea.protocols.signing.dialogues import SigningDialogue as BaseSigningDialogue
-from aea.protocols.signing.dialogues import SigningDialogues as BaseSigningDialogues
+from aea.protocols.state_update.dialogues import (
+ StateUpdateDialogue as BaseStateUpdateDialogue,
+)
+from aea.protocols.state_update.dialogues import (
+ StateUpdateDialogues as BaseStateUpdateDialogues,
+)
from aea.skills.base import Model
from packages.fetchai.protocols.oef_search.dialogues import (
@@ -59,7 +63,9 @@ def __init__(self, **kwargs) -> None:
:return: None
"""
Model.__init__(self, **kwargs)
- BaseOefSearchDialogues.__init__(self, self.context.agent_address)
+ BaseOefSearchDialogues.__init__(
+ self, self.context.agent_address + "_" + str(self.context.skill_id)
+ )
@staticmethod
def role_from_first_message(message: Message) -> BaseDialogue.Role:
@@ -87,11 +93,11 @@ def create_dialogue(
return dialogue
-SigningDialogue = BaseSigningDialogue
+StateUpdateDialogue = BaseStateUpdateDialogue
-class SigningDialogues(Model, BaseSigningDialogues):
- """This class keeps track of all oef_search dialogues."""
+class StateUpdateDialogues(Model, BaseStateUpdateDialogues):
+ """This class keeps track of all state_update dialogues."""
def __init__(self, **kwargs) -> None:
"""
@@ -101,7 +107,9 @@ def __init__(self, **kwargs) -> None:
:return: None
"""
Model.__init__(self, **kwargs)
- BaseSigningDialogues.__init__(self, self.context.agent_address)
+ BaseStateUpdateDialogues.__init__(
+ self, self.context.agent_address + "_" + str(self.context.skill_id)
+ )
@staticmethod
def role_from_first_message(message: Message) -> BaseDialogue.Role:
@@ -110,11 +118,11 @@ def role_from_first_message(message: Message) -> BaseDialogue.Role:
:param message: an incoming/outgoing first message
:return: The role of the agent
"""
- return BaseSigningDialogue.Role.SKILL
+ return BaseStateUpdateDialogue.Role.SKILL
def create_dialogue(
self, dialogue_label: BaseDialogueLabel, role: BaseDialogue.Role,
- ) -> SigningDialogue:
+ ) -> StateUpdateDialogue:
"""
Create an instance of fipa dialogue.
@@ -123,7 +131,7 @@ def create_dialogue(
:return: the created dialogue
"""
- dialogue = SigningDialogue(
+ dialogue = StateUpdateDialogue(
dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
)
return dialogue
diff --git a/packages/fetchai/skills/tac_participation/game.py b/packages/fetchai/skills/tac_participation/game.py
index 5b03bc2021..414827693d 100644
--- a/packages/fetchai/skills/tac_participation/game.py
+++ b/packages/fetchai/skills/tac_participation/game.py
@@ -21,14 +21,26 @@
from enum import Enum
from typing import Dict, List, Optional
-from aea.helpers.search.models import Constraint, ConstraintType, Query
+from aea.helpers.search.models import Constraint, ConstraintType, Location, Query
from aea.mail.base import Address
from aea.skills.base import Model
from packages.fetchai.protocols.tac.message import TacMessage
+from packages.fetchai.skills.tac_participation.dialogues import (
+ StateUpdateDialogue,
+ TacDialogue,
+)
DEFAULT_LEDGER_ID = "ethereum"
+DEFAULT_LOCATION = {"longitude": 51.5194, "latitude": 0.1270}
+DEFAULT_SEARCH_QUERY = {
+ "search_key": "tac",
+ "search_value": "v1",
+ "constraint_type": "==",
+}
+DEFAULT_SEARCH_RADIUS = 5.0
+
class Phase(Enum):
"""This class defines the phases of the game."""
@@ -46,7 +58,7 @@ class Configuration:
def __init__(
self,
version_id: str,
- tx_fee: int,
+ fee_by_currency_id: Dict[str, int],
agent_addr_to_name: Dict[Address, str],
good_id_to_name: Dict[str, str],
controller_addr: Address,
@@ -55,7 +67,7 @@ def __init__(
Instantiate a game configuration.
:param version_id: the version of the game.
- :param tx_fee: the fee for a transaction.
+ :param fee_by_currency_id: the fee for a transaction by currency id.
:param agent_addr_to_name: a dictionary mapping agent addresses to agent names (as strings).
:param good_id_to_name: a dictionary mapping good ids to good names (as strings).
:param controller_addr: the address of the controller
@@ -63,7 +75,7 @@ def __init__(
self._version_id = version_id
self._nb_agents = len(agent_addr_to_name)
self._nb_goods = len(good_id_to_name)
- self._tx_fee = tx_fee
+ self._fee_by_currency_id = fee_by_currency_id
self._agent_addr_to_name = agent_addr_to_name
self._good_id_to_name = good_id_to_name
self._controller_addr = controller_addr
@@ -88,7 +100,14 @@ def nb_goods(self) -> int:
@property
def tx_fee(self) -> int:
"""Transaction fee for the TAC instance."""
- return self._tx_fee
+ assert len(self._fee_by_currency_id) == 1, "More than one currency id present!"
+ value = next(iter(self._fee_by_currency_id.values()))
+ return value
+
+ @property
+ def fee_by_currency_id(self) -> Dict[str, int]:
+ """Transaction fee for the TAC instance."""
+ return self._fee_by_currency_id
@property
def agent_addr_to_name(self) -> Dict[Address, str]:
@@ -133,7 +152,9 @@ def _check_consistency(self):
:raises: AssertionError: if some constraint is not satisfied.
"""
assert self.version_id is not None, "A version id must be set."
- assert self.tx_fee >= 0, "Tx fee must be non-negative."
+ assert (
+ len(self.fee_by_currency_id) == 1 and self.tx_fee >= 0
+ ), "Tx fee must be non-negative."
assert self.nb_agents > 1, "Must have at least two agents."
assert self.nb_goods > 1, "Must have at least two goods."
assert (
@@ -159,12 +180,20 @@ def __init__(self, **kwargs):
self._expected_controller_addr = kwargs.pop(
"expected_controller_addr", None
) # type: Optional[str]
+
+ self._search_query = kwargs.pop("search_query", DEFAULT_SEARCH_QUERY)
+ location = kwargs.pop("location", DEFAULT_LOCATION)
+ self._agent_location = Location(location["longitude"], location["latitude"])
+ self._radius = kwargs.pop("search_radius", DEFAULT_SEARCH_RADIUS)
+
self._ledger_id = kwargs.pop("ledger_id", DEFAULT_LEDGER_ID)
self._is_using_contract = kwargs.pop("is_using_contract", False) # type: bool
super().__init__(**kwargs)
self._phase = Phase.PRE_GAME
self._conf = None # type: Optional[Configuration]
self._contract_address = None # type: Optional[str]
+ self._tac_dialogue = None # type: Optional[TacDialogue]
+ self._state_update_dialogue = None # type: Optional[StateUpdateDialogue]
@property
def ledger_id(self) -> str:
@@ -198,6 +227,30 @@ def contract_address(self, contract_address: str) -> None:
assert self._contract_address is None, "Contract address already set!"
self._contract_address = contract_address
+ @property
+ def tac_dialogue(self) -> TacDialogue:
+ """Retrieve the tac dialogue."""
+ assert self._tac_dialogue is not None, "TacDialogue not set!"
+ return self._tac_dialogue
+
+ @tac_dialogue.setter
+ def tac_dialogue(self, tac_dialogue: TacDialogue) -> None:
+ """Set the tac dialogue."""
+ assert self._tac_dialogue is None, "TacDialogue already set!"
+ self._tac_dialogue = tac_dialogue
+
+ @property
+ def state_update_dialogue(self) -> StateUpdateDialogue:
+ """Retrieve the state_update dialogue."""
+ assert self._state_update_dialogue is not None, "StateUpdateDialogue not set!"
+ return self._state_update_dialogue
+
+ @state_update_dialogue.setter
+ def state_update_dialogue(self, state_update_dialogue: StateUpdateDialogue) -> None:
+ """Set the state_update dialogue."""
+ assert self._state_update_dialogue is None, "StateUpdateDialogue already set!"
+ self._state_update_dialogue = state_update_dialogue
+
@property
def expected_controller_addr(self) -> Address:
"""Get the expected controller pbk."""
@@ -232,7 +285,7 @@ def init(self, tac_message: TacMessage, controller_addr: Address) -> None:
), "TacMessage for unexpected game."
self._conf = Configuration(
tac_message.version_id,
- tac_message.tx_fee,
+ tac_message.fee_by_currency_id,
tac_message.agent_addr_to_name,
tac_message.good_id_to_name,
controller_addr,
@@ -247,9 +300,7 @@ def update_expected_controller_addr(self, controller_addr: Address):
:return: None
"""
self.context.logger.warning(
- "[{}]: TAKE CARE! Circumventing controller identity check! For added security provide the expected controller key as an argument to the Game instance and check against it.".format(
- self.context.agent_name
- )
+ "TAKE CARE! Circumventing controller identity check! For added security provide the expected controller key as an argument to the Game instance and check against it."
)
self._expected_controller_addr = controller_addr
@@ -267,7 +318,15 @@ def get_game_query(self) -> Query:
:return: the query
"""
- query = Query(
- [Constraint("version", ConstraintType("==", self.expected_version_id))]
+ close_to_my_service = Constraint(
+ "location", ConstraintType("distance", (self._agent_location, self._radius))
+ )
+ service_key_filter = Constraint(
+ self._search_query["search_key"],
+ ConstraintType(
+ self._search_query["constraint_type"],
+ self._search_query["search_value"],
+ ),
)
+ query = Query([close_to_my_service, service_key_filter],)
return query
diff --git a/packages/fetchai/skills/tac_participation/handlers.py b/packages/fetchai/skills/tac_participation/handlers.py
index e5abd22d95..eac7db285b 100644
--- a/packages/fetchai/skills/tac_participation/handlers.py
+++ b/packages/fetchai/skills/tac_participation/handlers.py
@@ -21,10 +21,8 @@
from typing import Dict, Optional, Tuple, cast
-from aea.configurations.base import ProtocolId
from aea.mail.base import Address
from aea.protocols.base import Message
-from aea.protocols.signing.message import SigningMessage
from aea.protocols.state_update.message import StateUpdateMessage
from aea.skills.base import Handler
@@ -33,15 +31,15 @@
from packages.fetchai.skills.tac_participation.dialogues import (
OefSearchDialogue,
OefSearchDialogues,
- SigningDialogue,
- SigningDialogues,
+ StateUpdateDialogue,
+ StateUpdateDialogues,
TacDialogue,
TacDialogues,
)
from packages.fetchai.skills.tac_participation.game import Game, Phase
-class OEFSearchHandler(Handler):
+class OefSearchHandler(Handler):
"""This class handles oef messages."""
SUPPORTED_PROTOCOL = OefSearchMessage.protocol_id
@@ -97,8 +95,8 @@ def _handle_unidentified_dialogue(self, oef_search_msg: OefSearchMessage) -> Non
:param msg: the message
"""
self.context.logger.warning(
- "[{}]: received invalid oef_search message={}, unidentified dialogue.".format(
- self.context.agent_name, oef_search_msg
+ "received invalid oef_search message={}, unidentified dialogue.".format(
+ oef_search_msg
)
)
@@ -113,10 +111,8 @@ def _on_oef_error(
:return: None
"""
self.context.logger.warning(
- "[{}]: Received OEF Search error: dialogue_reference={}, oef_error_operation={}".format(
- self.context.agent_name,
- oef_search_msg.dialogue_reference,
- oef_search_msg.oef_error_operation,
+ "received OEF Search error: dialogue_reference={}, oef_error_operation={}".format(
+ oef_search_msg.dialogue_reference, oef_search_msg.oef_error_operation,
)
)
@@ -131,10 +127,8 @@ def _on_search_result(
:return: None
"""
self.context.logger.debug(
- "[{}]: on search result: dialogue_reference={} agents={}".format(
- self.context.agent_name,
- oef_search_msg.dialogue_reference,
- oef_search_msg.agents,
+ "on search result: dialogue_reference={} agents={}".format(
+ oef_search_msg.dialogue_reference, oef_search_msg.agents,
)
)
self._on_controller_search_result(oef_search_msg.agents)
@@ -150,10 +144,8 @@ def _handle_invalid(
:return: None
"""
self.context.logger.warning(
- "[{}]: cannot handle oef_search message of performative={} in dialogue={}.".format(
- self.context.agent_name,
- oef_search_msg.performative,
- oef_search_dialogue,
+ "cannot handle oef_search message of performative={} in dialogue={}.".format(
+ oef_search_msg.performative, oef_search_dialogue,
)
)
@@ -170,30 +162,18 @@ def _on_controller_search_result(
game = cast(Game, self.context.game)
if game.phase.value != Phase.PRE_GAME.value:
self.context.logger.debug(
- "[{}]: Ignoring controller search result, the agent is already competing.".format(
- self.context.agent_name
- )
+ "ignoring controller search result, the agent is already competing."
)
return
if len(agent_addresses) == 0:
- self.context.logger.info(
- "[{}]: Couldn't find the TAC controller. Retrying...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("couldn't find the TAC controller. Retrying...")
elif len(agent_addresses) > 1:
self.context.logger.warning(
- "[{}]: Found more than one TAC controller. Retrying...".format(
- self.context.agent_name
- )
+ "found more than one TAC controller. Retrying..."
)
else:
- self.context.logger.info(
- "[{}]: Found the TAC controller. Registering...".format(
- self.context.agent_name
- )
- )
+ self.context.logger.info("found the TAC controller. Registering...")
controller_addr = agent_addresses[0]
self._register_to_tac(controller_addr)
@@ -208,13 +188,18 @@ def _register_to_tac(self, controller_addr: Address) -> None:
game = cast(Game, self.context.game)
game.update_expected_controller_addr(controller_addr)
game.update_game_phase(Phase.GAME_REGISTRATION)
+ tac_dialogues = cast(TacDialogues, self.context.tac_dialogues)
tac_msg = TacMessage(
performative=TacMessage.Performative.REGISTER,
+ dialogue_reference=tac_dialogues.new_self_initiated_dialogue_reference(),
agent_name=self.context.agent_name,
)
tac_msg.counterparty = controller_addr
+ tac_dialogue = cast(Optional[TacDialogue], tac_dialogues.update(tac_msg))
+ assert tac_dialogue is not None, "TacDialogue not created."
+ game.tac_dialogue = tac_dialogue
self.context.outbox.put_message(message=tac_msg)
- self.context.behaviours.tac.is_active = False
+ self.context.behaviours.tac_search.is_active = False
class TacHandler(Handler):
@@ -249,35 +234,21 @@ def handle(self, message: Message) -> None:
# handle message
game = cast(Game, self.context.game)
self.context.logger.debug(
- "[{}]: Handling controller response. performative={}".format(
- self.context.agent_name, tac_msg.performative
- )
+ "handling controller response. performative={}".format(tac_msg.performative)
)
- if message.counterparty != game.expected_controller_addr:
+ if tac_msg.counterparty != game.expected_controller_addr:
raise ValueError(
"The sender of the message is not the controller agent we registered with."
)
if tac_msg.performative == TacMessage.Performative.TAC_ERROR:
self._on_tac_error(tac_msg, tac_dialogue)
- elif game.phase.value == Phase.PRE_GAME.value:
- raise ValueError(
- "We do not expect a controller agent message in the pre game phase."
- )
- elif game.phase.value == Phase.GAME_REGISTRATION.value:
- if tac_msg.performative == TacMessage.Performative.GAME_DATA:
- self._on_start(tac_msg, tac_dialogue)
- elif tac_msg.performative == TacMessage.Performative.CANCELLED:
- self._on_cancelled(tac_msg, tac_dialogue)
- elif game.phase.value == Phase.GAME.value:
- if tac_msg.performative == TacMessage.Performative.TRANSACTION_CONFIRMATION:
- self._on_transaction_confirmed(tac_msg, tac_dialogue)
- elif tac_msg.performative == TacMessage.Performative.CANCELLED:
- self._on_cancelled(tac_msg, tac_dialogue)
- elif game.phase.value == Phase.POST_GAME.value:
- raise ValueError(
- "We do not expect a controller agent message in the post game phase."
- )
+ elif tac_msg.performative == TacMessage.Performative.GAME_DATA:
+ self._on_start(tac_msg, tac_dialogue)
+ elif tac_msg.performative == TacMessage.Performative.CANCELLED:
+ self._on_cancelled(tac_msg, tac_dialogue)
+ elif tac_msg.performative == TacMessage.Performative.TRANSACTION_CONFIRMATION:
+ self._on_transaction_confirmed(tac_msg, tac_dialogue)
else:
self._handle_invalid(tac_msg, tac_dialogue)
@@ -296,9 +267,7 @@ def _handle_unidentified_dialogue(self, tac_msg: TacMessage) -> None:
:param tac_msg: the message
"""
self.context.logger.warning(
- "[{}]: received invalid tac message={}, unidentified dialogue.".format(
- self.context.agent_name, tac_msg
- )
+ "received invalid tac message={}, unidentified dialogue.".format(tac_msg)
)
def _on_tac_error(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
@@ -311,8 +280,8 @@ def _on_tac_error(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
error_code = tac_msg.error_code
self.context.logger.debug(
- "[{}]: Received error from the controller. error_msg={}".format(
- self.context.agent_name, TacMessage.ErrorCode.to_msg(error_code.value)
+ "received error from the controller. error_msg={}".format(
+ TacMessage.ErrorCode.to_msg(error_code.value)
)
)
if error_code == TacMessage.ErrorCode.TRANSACTION_NOT_VALID:
@@ -323,9 +292,7 @@ def _on_tac_error(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
else "NO_TX_ID"
)
self.context.logger.warning(
- "[{}]: Received error on transaction id: {}".format(
- self.context.agent_name, transaction_id[-10:]
- )
+ "received error on transaction id: {}".format(transaction_id[-10:])
)
def _on_start(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
@@ -336,10 +303,17 @@ def _on_start(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
:param tac_dialogue: the tac dialogue
:return: None
"""
- self.context.logger.info(
- "[{}]: Received start event from the controller. Starting to compete...".format(
- self.context.agent_name
+ game = cast(Game, self.context.game)
+ if game.phase.value != Phase.GAME_REGISTRATION.value:
+ self.context.logger.warning(
+ "we do not expect a start message in game phase={}".format(
+ game.phase.value
+ )
)
+ return
+
+ self.context.logger.info(
+ "received start event from the controller. Starting to compete..."
)
game = cast(Game, self.context.game)
game.init(tac_msg, tac_msg.counterparty)
@@ -354,18 +328,12 @@ def _on_start(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
game.contract_address = contract_address
self.context.shared_state["erc1155_contract_address"] = contract_address
self.context.logger.info(
- "[{}]: Received a contract address: {}".format(
- self.context.agent_name, contract_address
- )
+ "received a contract address: {}".format(contract_address)
)
# TODO; verify on-chain matches off-chain wealth
self._update_ownership_and_preferences(tac_msg, tac_dialogue)
else:
- self.context.logger.warning(
- "[{}]: Did not receive a contract address!".format(
- self.context.agent_name
- )
- )
+ self.context.logger.warning("did not receive a contract address!")
else:
self._update_ownership_and_preferences(tac_msg, tac_dialogue)
@@ -379,14 +347,26 @@ def _update_ownership_and_preferences(
:param tac_dialogue: the tac dialogue
:return: None
"""
+ state_update_dialogues = cast(
+ StateUpdateDialogues, self.context.state_update_dialogues
+ )
state_update_msg = StateUpdateMessage(
performative=StateUpdateMessage.Performative.INITIALIZE,
+ dialogue_reference=state_update_dialogues.new_self_initiated_dialogue_reference(),
amount_by_currency_id=tac_msg.amount_by_currency_id,
quantities_by_good_id=tac_msg.quantities_by_good_id,
exchange_params_by_currency_id=tac_msg.exchange_params_by_currency_id,
utility_params_by_good_id=tac_msg.utility_params_by_good_id,
- tx_fee=tac_msg.tx_fee,
)
+ self.context.shared_state["fee_by_currency_id"] = tac_msg.fee_by_currency_id
+ state_update_msg.counterparty = "decision_maker"
+ state_update_dialogue = cast(
+ Optional[StateUpdateDialogue],
+ state_update_dialogues.update(state_update_msg),
+ )
+ assert state_update_dialogue is not None, "StateUpdateDialogue not created."
+ game = cast(Game, self.context.game)
+ game.state_update_dialogue = state_update_dialogue
self.context.decision_maker_message_queue.put_nowait(state_update_msg)
def _on_cancelled(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
@@ -397,11 +377,16 @@ def _on_cancelled(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
:param tac_dialogue: the tac dialogue
:return: None
"""
- self.context.logger.info(
- "[{}]: Received cancellation from the controller.".format(
- self.context.agent_name
+ game = cast(Game, self.context.game)
+ if game.phase.value not in [Phase.GAME_REGISTRATION.value, Phase.GAME.value]:
+ self.context.logger.warning(
+ "we do not expect a start message in game phase={}".format(
+ game.phase.value
+ )
)
- )
+ return
+
+ self.context.logger.info("received cancellation from the controller.")
game = cast(Game, self.context.game)
game.update_game_phase(Phase.POST_GAME)
self.context.is_active = False
@@ -417,20 +402,37 @@ def _on_transaction_confirmed(
:param tac_dialogue: the tac dialogue
:return: None
"""
+ game = cast(Game, self.context.game)
+ if game.phase.value != Phase.GAME.value:
+ self.context.logger.warning(
+ "we do not expect a tranasaction in game phase={}".format(
+ game.phase.value
+ )
+ )
+ return
+
self.context.logger.info(
- "[{}]: Received transaction confirmation from the controller: transaction_id={}".format(
- self.context.agent_name, tac_msg.tx_id[-10:]
+ "received transaction confirmation from the controller: transaction_id={}".format(
+ tac_msg.transaction_id
)
)
+ state_update_dialogue = game.state_update_dialogue
+ last_msg = state_update_dialogue.last_message
+ assert last_msg is not None, "Could not retrieve last message."
state_update_msg = StateUpdateMessage(
performative=StateUpdateMessage.Performative.APPLY,
+ dialogue_reference=state_update_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_msg.message_id + 1,
+ target=last_msg.message_id,
amount_by_currency_id=tac_msg.amount_by_currency_id,
quantities_by_good_id=tac_msg.quantities_by_good_id,
)
+ state_update_msg.counterparty = "decision_maker"
+ state_update_dialogue.update(state_update_msg)
self.context.decision_maker_message_queue.put_nowait(state_update_msg)
if "confirmed_tx_ids" not in self.context.shared_state.keys():
self.context.shared_state["confirmed_tx_ids"] = []
- self.context.shared_state["confirmed_tx_ids"].append(tac_msg.tx_id)
+ self.context.shared_state["confirmed_tx_ids"].append(tac_msg.transaction_id)
def _handle_invalid(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> None:
"""
@@ -440,148 +442,8 @@ def _handle_invalid(self, tac_msg: TacMessage, tac_dialogue: TacDialogue) -> Non
:param tac_dialogue: the tac dialogue
:return: None
"""
- game = cast(Game, self.context.game)
- self.context.logger.warning(
- "[{}]: cannot handle tac message of performative={} in dialogue={} during game_phase={}.".format(
- self.context.agent_name, tac_msg.performative, tac_dialogue, game.phase,
- )
- )
-
-
-class SigningHandler(Handler):
- """This class implements the transaction handler."""
-
- SUPPORTED_PROTOCOL = SigningMessage.protocol_id # type: Optional[ProtocolId]
-
- def setup(self) -> None:
- """
- Implement the setup.
-
- :return: None
- """
- pass
-
- def handle(self, message: Message) -> None:
- """
- Dispatch message to relevant handler and respond.
-
- :param message: the message
- :return: None
- """
- signing_msg = cast(SigningMessage, message)
-
- # recover dialogue
- signing_dialogues = cast(SigningDialogues, self.context.signing_dialogues)
- signing_dialogue = cast(
- Optional[SigningDialogue], signing_dialogues.update(signing_msg)
- )
- if signing_dialogue is None:
- self._handle_unidentified_dialogue(signing_msg)
- return
-
- # handle message
- if signing_msg.performative is SigningMessage.Performative.SIGNED_TRANSACTION:
- self._handle_signed_transaction(signing_msg, signing_dialogue)
- elif signing_msg.performative is SigningMessage.Performative.ERROR:
- self._handle_error(signing_msg, signing_dialogue)
- else:
- self._handle_invalid(signing_msg, signing_dialogue)
-
- def teardown(self) -> None:
- """
- Implement the handler teardown.
-
- :return: None
- """
- pass
-
- def _handle_unidentified_dialogue(self, signing_msg: SigningMessage) -> None:
- """
- Handle an unidentified dialogue.
-
- :param msg: the message
- """
- self.context.logger.info(
- "[{}]: received invalid signing message={}, unidentified dialogue.".format(
- self.context.agent_name, signing_msg
- )
- )
-
- def _handle_signed_transaction(
- self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
- ) -> None:
- """
- Handle an oef search message.
-
- :param signing_msg: the signing message
- :param signing_dialogue: the dialogue
- :return: None
- """
- # TODO: Need to modify here and add the contract option in case we are using one.
- self.context.logger.info(
- "[{}]: transaction confirmed by decision maker, sending to controller.".format(
- self.context.agent_name
- )
- )
- game = cast(Game, self.context.game)
- tx_counterparty_signature = cast(
- str, signing_msg.skill_callback_info.get("tx_counterparty_signature")
- )
- tx_counterparty_id = cast(
- str, signing_msg.skill_callback_info.get("tx_counterparty_id")
- )
- tx_id = cast(str, signing_msg.skill_callback_info.get("tx_id"))
- if (tx_counterparty_signature is not None) and (tx_counterparty_id is not None):
- # tx_id = tx_message.tx_id + "_" + tx_counterparty_id
- msg = TacMessage(
- performative=TacMessage.Performative.TRANSACTION,
- tx_id=tx_id,
- tx_sender_addr=signing_msg.terms.sender_address,
- tx_counterparty_addr=signing_msg.terms.counterparty_address,
- amount_by_currency_id=signing_msg.terms.amount_by_currency_id,
- is_sender_payable_tx_fee=signing_msg.terms.is_sender_payable_tx_fee,
- quantities_by_good_id=signing_msg.terms.quantities_by_good_id,
- tx_sender_signature=signing_msg.signed_transaction.body,
- tx_counterparty_signature=tx_counterparty_signature,
- tx_nonce=signing_msg.terms.nonce,
- )
- msg.counterparty = game.conf.controller_addr
- self.context.outbox.put_message(message=msg)
- else:
- self.context.logger.warning(
- "[{}]: transaction has no counterparty id or signature!".format(
- self.context.agent_name
- )
- )
-
- def _handle_error(
- self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
- ) -> None:
- """
- Handle an oef search message.
-
- :param signing_msg: the signing message
- :param signing_dialogue: the dialogue
- :return: None
- """
- self.context.logger.info(
- "[{}]: transaction signing was not successful. Error_code={} in dialogue={}".format(
- self.context.agent_name, signing_msg.error_code, signing_dialogue
- )
- )
-
- def _handle_invalid(
- self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue
- ) -> None:
- """
- Handle an oef search message.
-
- :param signing_msg: the signing message
- :param signing_dialogue: the dialogue
- :return: None
- """
self.context.logger.warning(
- "[{}]: cannot handle signing message of performative={} in dialogue={}.".format(
- self.context.agent_name, signing_msg.performative, signing_dialogue
+ "cannot handle tac message of performative={} in dialogue={}.".format(
+ tac_msg.performative, tac_dialogue
)
)
diff --git a/packages/fetchai/skills/tac_participation/skill.yaml b/packages/fetchai/skills/tac_participation/skill.yaml
index 0cfaf005fd..43dec3b7c3 100644
--- a/packages/fetchai/skills/tac_participation/skill.yaml
+++ b/packages/fetchai/skills/tac_participation/skill.yaml
@@ -1,35 +1,36 @@
name: tac_participation
author: fetchai
-version: 0.4.0
+version: 0.5.0
description: The tac participation skill implements the logic for an AEA to participate
in the TAC.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmcVpVrbV54Aogmowu6AomDiVMrVMo9BUvwKt9V1bJpBwp
- behaviours.py: QmbTf28S46E5w1ytYAcRCZnrVxZ8DcVYAWn1QdNnHvZVLL
- dialogues.py: QmZadrW961YwRQuDveoSFSVA7NjVVh2ZuvmbyRke2EqseF
- game.py: QmXiKRfkEAbKZ84nauAwQcXuAekU4hD7kMsqskgWBGopAU
- handlers.py: QmerbCSEoSVUsVXeN8bwKq4iZk4db3sjsurtfNoGN9Gtfv
+ behaviours.py: QmZo3d94G3q5wd9DNMN3TdH2DqpKXxMyti7sRrgYt28hrM
+ dialogues.py: QmV9NMmkCoNS3itj3cgRuKi3bTCrmae4cQ3X1tTyXx25Bj
+ game.py: QmVudLRDif5sawxRMmTPzdVhABk1Q3sGNmctNgs2c1QqSJ
+ handlers.py: QmcBhfgj8NSyisXEFedyiHmNXgEGXqyvziAeRpbkPHgvjD
fingerprint_ignore_patterns: []
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/oef_search:0.3.0
-- fetchai/tac:0.3.0
+- fetchai/oef_search:0.4.0
+- fetchai/tac:0.4.0
skills: []
behaviours:
- tac:
+ tac_search:
args:
tick_interval: 5
class_name: TacSearchBehaviour
+ transaction_processing:
+ args:
+ tick_interval: 2
+ class_name: TransactionProcessBehaviour
handlers:
oef:
args: {}
class_name: OefSearchHandler
- signing:
- args: {}
- class_name: SigningHandler
tac:
args: {}
class_name: TacHandler
@@ -39,13 +40,21 @@ models:
expected_version_id: v1
is_using_contract: false
ledger_id: ethereum
+ location:
+ latitude: 0.127
+ longitude: 51.5194
+ search_query:
+ constraint_type: ==
+ search_key: tac
+ search_value: v1
+ search_radius: 5.0
class_name: Game
oef_search_dialogues:
args: {}
class_name: OefSearchDialogues
- signing_dialogues:
+ state_update_dialogues:
args: {}
- class_name: SigningDialogues
+ class_name: StateUpdateDialogues
tac_dialogues:
args: {}
class_name: TacDialogues
diff --git a/packages/fetchai/skills/thermometer/skill.yaml b/packages/fetchai/skills/thermometer/skill.yaml
index ebf8c4d215..5c475b6493 100644
--- a/packages/fetchai/skills/thermometer/skill.yaml
+++ b/packages/fetchai/skills/thermometer/skill.yaml
@@ -1,6 +1,6 @@
name: thermometer
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The thermometer skill implements the functionality to sell data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -13,12 +13,12 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_seller:0.8.0
+- fetchai/generic_seller:0.9.0
behaviours:
service_registration:
args:
diff --git a/packages/fetchai/skills/thermometer_client/skill.yaml b/packages/fetchai/skills/thermometer_client/skill.yaml
index 93032c661b..edc4c944ad 100644
--- a/packages/fetchai/skills/thermometer_client/skill.yaml
+++ b/packages/fetchai/skills/thermometer_client/skill.yaml
@@ -1,6 +1,6 @@
name: thermometer_client
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The thermometer client skill implements the skill to purchase temperature
data.
license: Apache-2.0
@@ -14,12 +14,12 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_buyer:0.7.0
+- fetchai/generic_buyer:0.8.0
behaviours:
search:
args:
diff --git a/packages/fetchai/skills/weather_client/skill.yaml b/packages/fetchai/skills/weather_client/skill.yaml
index d9db213585..d0c42eb44a 100644
--- a/packages/fetchai/skills/weather_client/skill.yaml
+++ b/packages/fetchai/skills/weather_client/skill.yaml
@@ -1,6 +1,6 @@
name: weather_client
author: fetchai
-version: 0.6.0
+version: 0.7.0
description: The weather client skill implements the skill to purchase weather data.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
@@ -13,12 +13,12 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_buyer:0.7.0
+- fetchai/generic_buyer:0.8.0
behaviours:
search:
args:
diff --git a/packages/fetchai/skills/weather_station/skill.yaml b/packages/fetchai/skills/weather_station/skill.yaml
index e27797ecef..d5ac943b49 100644
--- a/packages/fetchai/skills/weather_station/skill.yaml
+++ b/packages/fetchai/skills/weather_station/skill.yaml
@@ -1,6 +1,6 @@
name: weather_station
author: fetchai
-version: 0.7.0
+version: 0.8.0
description: The weather station skill implements the functionality to sell weather
data.
license: Apache-2.0
@@ -17,12 +17,12 @@ fingerprint_ignore_patterns:
- '*.db'
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills:
-- fetchai/generic_seller:0.8.0
+- fetchai/generic_seller:0.9.0
behaviours:
service_registration:
args:
diff --git a/packages/hashes.csv b/packages/hashes.csv
index 60746b6d53..50fc33d137 100644
--- a/packages/hashes.csv
+++ b/packages/hashes.csv
@@ -1,73 +1,73 @@
-fetchai/agents/aries_alice,QmacrJbA9Ei9mS6XTD4xv53hZydFqDJzGswJMJuRCSen9h
-fetchai/agents/aries_faber,QmaTfqf2Ke3hWrzwsHBTaxgVeazLA3m5BYfU1XmAj7h7n9
-fetchai/agents/car_data_buyer,Qmb4YCcJ51M1bVjkBcJsLTcMYBo7FJWWnAzwpUVGFRz1BR
-fetchai/agents/car_detector,QmRPBPo2vjcwHzmTaZDSy2JiRQ1vmcE5Dpi72TcUMRehyg
-fetchai/agents/erc1155_client,Qmegev5efyDN6qf7fVDNV2KcDdWTyRtXiupvTh8o5hu6Y7
-fetchai/agents/erc1155_deployer,QmUGwqvJEntwcrSTj5hnBBjunzpJhjcUUDf76zqL5Zopgs
-fetchai/agents/generic_buyer,QmeQeBKuHy5vUE3byJ7er9E5BhrjYABjRpLRV3x9svoyfq
-fetchai/agents/generic_seller,QmQaSKyhoAPqNKhAqEhDaRTseSDMKfZZMxuxCeUXMDRFc3
-fetchai/agents/gym_aea,QmYPdX62wJ92CENCyL1s4jabJgb9TPjcoMujogSHc29Y5S
-fetchai/agents/ml_data_provider,QmbbNx4QQscw85EuVxNHGFWaxWxgKxHzqxKi2dCZ2u4B4z
-fetchai/agents/ml_model_trainer,QmRGaCh5QYAySPyPL5wyvgxsyrRGwscd17T4eSJ1rciBcu
-fetchai/agents/my_first_aea,QmcaigCyMziXfBjFER7aQhMZnHtsGytii9QFehRQuiA44N
-fetchai/agents/simple_service_registration,QmbavaDU7t2MUpQYwtHu76nvLN2mSTgA8YeW8EQ7GMbehF
-fetchai/agents/tac_controller,QmbphSNH9YBBEfhB1Sa8BadZscscnJ9RVjv7epjTdGbcBG
-fetchai/agents/tac_controller_contract,QmYT57WS4y6jPRkF3RpB7rHW4n4XL4rx83hF6YXyMZw1M1
-fetchai/agents/tac_participant,QmQJDTm92TzqD725cWeFt53J85psv6JVuvxJucMDiifW4k
-fetchai/agents/thermometer_aea,QmbB54sVDmKsn9MfAoWqsLEfR5FbdEvL4ffCwLNhujAWjs
-fetchai/agents/thermometer_client,QmXjQpq9WnhS7d8Dr57zN3RhJ9z2NpPJcEgknRPU88fUVs
-fetchai/agents/weather_client,QmXibCD5eAJVCxJctC3Pc8ibGbSMcENWu31utxPUe9LLNY
-fetchai/agents/weather_station,Qme4kTkGnGQdJ2TSrKeQmmaZJYqPPT7i7L3Nftgckuh2Zq
-fetchai/connections/gym,QmXpTer28dVvxeXqsXzaBqX551QToh9w5KJC2oXcStpKJG
-fetchai/connections/http_client,QmUjtATHombNqbwHRonc3pLUTfuvQJBxqGAj4K5zKT8beQ
-fetchai/connections/http_server,QmXuGssPAahvRXHNmYrvtqYokgeCqavoiK7x9zmjQT8w23
-fetchai/connections/ledger,QmVXceMJCioA1Hro9aJgBwrF9yLgToaVXifDz6EVo6vTXn
-fetchai/connections/local,QmZKciQTgE8LLHsgQX4F5Ecc7rNPp9BBSWQHEEe7jEMEmJ
-fetchai/connections/oef,QmWcT6NA3jCsngAiEuCjLtWumGKScS6PrjngvGgLJXg9TK
-fetchai/connections/p2p_client,Qmd47ry6ZCEzkT9pCo96irv9x5D1EcqSiMkhCgXPykaDbz
-fetchai/connections/p2p_libp2p,QmQE7eUsiMJJ61ruqxgUGrpbTdoBQfusxkmuXTManufeWN
-fetchai/connections/p2p_libp2p_client,QmZ1MQEacF6EEqfWaD7gAauwvk44eQfxzi6Ew23Wu3vPeP
-fetchai/connections/p2p_stub,QmTFcniXvpUw5hR27SN1W1iLcW8eGsMzFvzPQ4s3g3bw3H
-fetchai/connections/scaffold,QmTzEeEydjohZNTsAJnoGMtzTgCyzMBQCYgbTBLfqWtw5w
-fetchai/connections/soef,QmamP24iyoN9xMNCShTkYgKyQg9cfMgcHRZyopeDis9nmD
-fetchai/connections/stub,QmWP6tgcttnUY86ynAseyHuuFT85edT31QPSyideVveiyj
-fetchai/connections/tcp,Qmec7QAC2xzvcyvcciNnkBzrv2rWt61jxA7H1KxKvCSbc1
-fetchai/connections/webhook,QmZqPmyD36hmowzUrV4MsjXjXM6GXYJuZjKg9r1XUMeGxW
-fetchai/contracts/erc1155,QmPEae32YqmCmB7nAzoLokosvnu3u8ZN75xouzZEBvE5zM
+fetchai/agents/aries_alice,QmVU2GVL6bSitqAwe7kdy9XqixBpS9QwBDH7SWW4cEAaE1
+fetchai/agents/aries_faber,QmU1VCNmYgWU8kyZ4L2ip4UfZEi8ZVRQKvMx32Hyswwgr1
+fetchai/agents/car_data_buyer,QmP5XTu5bbRGNRx4k4NB2iVpSx5gRAziNn5cVqiByq9NV5
+fetchai/agents/car_detector,QmRBFJ5EFm8HYzqRhhcYpHcwYWKv5dbzqQTHToXwJpVPs4
+fetchai/agents/erc1155_client,QmUqtsVGejFWmMVe7nEjuMZmgsRa5EGsjprjS7CjW9LQug
+fetchai/agents/erc1155_deployer,QmVqL2HdwN2uGx6rzt3y4ZsEThuMzmpdAz89PGudgJVQYJ
+fetchai/agents/generic_buyer,QmSw5UYvB2srkr9ety7FF9yyPfpvefQLeUZoDqNsDPY9hf
+fetchai/agents/generic_seller,Qma9wX7T63v15kWbER3UvVJqVPMzfje8JcUzFyFDSycYyC
+fetchai/agents/gym_aea,QmYiWRUjjFVk7QvpzQpTonN2sfPTXCYZprThwNpveQ8Lgo
+fetchai/agents/ml_data_provider,QmazcospJkSrtbp23EERg3sNmVb6vrVd7NirBThtmChdYF
+fetchai/agents/ml_model_trainer,QmRCLb4WkWiQ8Povx6RaBZzaT241hHSE4DPQwWxsiSf3e9
+fetchai/agents/my_first_aea,Qme2CV8RMJqg3FC7n9iTgSFsdh6PgiWHRMuhX1nAgYYU7M
+fetchai/agents/simple_service_registration,Qmbgyep6iNgjVUhQbc5y9Aeahji58EUEHXWf1WP2NZuDiK
+fetchai/agents/tac_controller,QmePNyf8guJz5oXGT4SkAHPb5NtHPFTAkiHiB6d21iJN1n
+fetchai/agents/tac_controller_contract,QmUpJG6gHACeavn2tf7s7jS5eC2frWPy5PBzmMTAPfkR5a
+fetchai/agents/tac_participant,QmcSePKdWEnpdWQShpmg1owsjbyKs6d5A2KfU9qGbbTGMU
+fetchai/agents/thermometer_aea,QmWkMew1idZTd6KxTy7e8s8U3rbvyhNpSWt2i4XsNJeNg4
+fetchai/agents/thermometer_client,QmcBk27hp6Z88bJgMUgJQcJQEtwD6sMiRKSt5WAGUaMJza
+fetchai/agents/weather_client,QmNPmHyVFy7Tf9wJkHJCL4sm4UeYLT3wXPYa1FYVkyWXq1
+fetchai/agents/weather_station,QmedEK6tRkBrBFbVfv7GBCUiy8iC3TWzNx8U98ebzqbQtG
+fetchai/connections/gym,Qma74nB7YARSNTkS6vPZeDoDrKNH5SQCVomoPQhaQNFrfG
+fetchai/connections/http_client,QmTSyCEfNAbNWkqLVQHPQj1KkQXgAN3eXKpcnwBxxsqWiP
+fetchai/connections/http_server,QmXSBRoWRMcK6vQAxmw2KV7akY3sVKDDm9qmfpjTwkbJQA
+fetchai/connections/ledger,QmRsmyhLZ8JYRob66syAU7JxLHEp1PLij9ppHrC5ja31mb
+fetchai/connections/local,QmUbZPvqa8ThAJ9bUJoFB23td1rnr5Kf7hw9NQ6ptvcaVY
+fetchai/connections/oef,QmedfR2v5uJo5AZeAMncTKgtofcDvaXi3Bgst5DN36bovN
+fetchai/connections/p2p_client,Qma5AYuw824MUyfhiZzcJefo9Uykv25XZc6z38JhS72G1y
+fetchai/connections/p2p_libp2p,QmNmpnCnumRve4wJeHnAMBhMYp39Ppzs3EYJyuNYmSHyJV
+fetchai/connections/p2p_libp2p_client,QmZ6bz3TJ8Z2zvERcCWMSRW3n5YRy2i2b2XYk5syjt7TaK
+fetchai/connections/p2p_stub,QmNi7G92g27qnqJmdLu5cr7CG4unsW4RdNfR2KwagiszzS
+fetchai/connections/scaffold,QmYa1T9HNZcuubhf8p4ytdgr3h27HLjbPYsR4DYLYo24pC
+fetchai/connections/soef,QmbbYKEP4fdTS9EMprVAfSAq55YAudsx9JocbBzzb9L5Fr
+fetchai/connections/stub,Qmdo6c9X53ZKbtiHj3hNbtgFSe4rcyyZLET8TtRJHQVNs5
+fetchai/connections/tcp,QmaVKqs26qi9WHdUTJ9zKPPw5rhQbke48UvNdemZnHMhdL
+fetchai/connections/webhook,QmUCWs3z31xoakJDz9rXNT5TAmLcWpf1CZfnsHuMXUSgiL
+fetchai/contracts/erc1155,QmWMU8adudHWC6ZciZFR8YVnWbZsfugZbQmWwHnKBoDwrM
fetchai/contracts/scaffold,Qme97drP4cwCyPs3zV6WaLz9K7c5ZWRtSWQ25hMUmMjFgo
-fetchai/protocols/contract_api,QmcveAM85xPuhv2Dmo63adnhh5zgFVjPpPYQFEtKWxXvKj
-fetchai/protocols/default,QmXuCJgN7oceBH1RTLjQFbMAF5ZqpxTGaH7Mtx3CQKMNSn
-fetchai/protocols/fipa,QmSjtK4oegnfH7DUVAaFP1wBAz4B7M3eW51NgU12YpvnTy
-fetchai/protocols/gym,QmaoqyKo6yYmXNerWfac5W8etwgHtozyiruH7KRW9hS3Ef
-fetchai/protocols/http,Qma9MMqaJv4C3xWkcpukom3hxpJ8UiWBoao3C3mAgAf4Z3
-fetchai/protocols/ledger_api,QmPKixWAP333wRsXrFL7fHrdoaRxrXxHwbqG9gnkaXmQrR
-fetchai/protocols/ml_trade,QmQH9j4bN7Nc5M8JM6z3vK4DsQxGoKbxVHJt4NgV5bjvG3
-fetchai/protocols/oef_search,QmepRaMYYjowyb2ZPKYrfcJj2kxUs6CDSxqvzJM9w22fGN
-fetchai/protocols/scaffold,QmPSZhXhrqFUHoMVXpw7AFFBzPgGyX5hB2GDafZFWdziYQ
-fetchai/protocols/signing,QmXKdJ7wtSPP7qrn8yuCHZZRC6FQavdcpt2Sq4tHhFJoZY
-fetchai/protocols/state_update,QmR5hccpJta4x574RXwheeqLk1PwXBZZ23nd3LS432jFxp
-fetchai/protocols/tac,QmSWJcpfZnhSapGQbyCL9hBGCHSBB7qKrmMBHjzvCXE3mf
-fetchai/skills/aries_alice,QmVJsSTKgdRFpGSeXa642RD3GxZ4UxdykzuL9c4jjEWB8M
-fetchai/skills/aries_faber,QmcqRhcdZ3v42bd9gX2wMVB81Xq7tztumknxcWeKYJm6cB
-fetchai/skills/carpark_client,QmWJWwBKERdz4r4f6aHxsZtoXKHrsW4weaVKYcnLA1xph3
-fetchai/skills/carpark_detection,QmREVHt2N4k2PMsyh3LScqz7g5noUNM6md9cxr8VfP7HxX
-fetchai/skills/echo,QmeSr4j8W9enijZvgeE3vXeWcEj9sS8fo6vNFRpyAMnZey
-fetchai/skills/erc1155_client,QmYHeQTJEyieViE1j6s6wS43DmrgXfc3NoG7n61JsANizd
-fetchai/skills/erc1155_deploy,QmU9Un4ktCcvEqBRHx89BKQm6VjGNKL5LDQaWwbXxGp8Hw
-fetchai/skills/error,QmVirmcRGj6bc2i6iJZ2zoWGCfsCZMoGmZAXYq5aaYAqNb
-fetchai/skills/generic_buyer,QmSYDHpe1AZpCEig7JKrjTMvCpqPo2E3Dyv4S9p1gzSeNw
-fetchai/skills/generic_seller,Qmf9fg8nChsg2Sq9o7NpUxGhCFCQaUcygJ68GLebi3As6D
-fetchai/skills/gym,QmbeF2SzEcK6Db62W1i6EZTsJqJReWmp9ZouLCnSqdsYou
-fetchai/skills/http_echo,QmP5NXoCvXC9oxxJY4y846wmEhwP9NQS6pPKyN4knpfZTG
-fetchai/skills/ml_data_provider,QmQtoSEhnrUT32tooovwsNSeYiNVtpyn64L5X584TrhctD
-fetchai/skills/ml_train,QmeQwZSko3qxsmt2vqnBhJ9JX9dbKt6gM91Jqif1SQFedr
-fetchai/skills/scaffold,QmUG5Dwo3Sw6bTn38PLVEEU6tyEAKffUjWjPRDL3XjKaDQ
-fetchai/skills/simple_service_registration,QmNm3RvVyVRY94kwX7eqWkf1f8rPxPtWBywACPU13YKwxU
-fetchai/skills/tac_control,QmPsmfi72nafUMcGyzGPfBgRRy8cPkSB9n8VkyrnXMfwWV
-fetchai/skills/tac_control_contract,QmbSunYrCRE87dLK4G56RByY4dCWsmNRURu8Dj4ZpBgpKb
-fetchai/skills/tac_negotiation,Qmc5drAe2jhLwGNP43iDjoP3s8VAaXFwSkxuu4wJ4WMSem
-fetchai/skills/tac_participation,QmQi9zwYyxhjVjff24D2pjCJE96xae7zzv7231iqvn85tv
-fetchai/skills/thermometer,QmRkKxbmQBdmYGXXuLgNhBqsX8KEpUC3TmfbZTJ5r9LyB3
-fetchai/skills/thermometer_client,QmP7J7iurvq98Nrp31C3XDc3E3sNf9Tq3ytrELE2VCoedq
-fetchai/skills/weather_client,QmZeHxAXWh8RTToDAoa8zwC6aoRZjNLV3tV51H6UDfTxJo
-fetchai/skills/weather_station,QmV2YiH4spJKjXoWRxyicMQJNhpzRB3iLcVcpCcWyJWxs1
+fetchai/protocols/contract_api,QmXBKagx4cmBr3xQE3yJGn3Mund2RxHK9TfASqoSu2Uz34
+fetchai/protocols/default,Qmd1Gy5oEk89zVYdjib37wKp7whTuSD9pFYJwa14AKfUin
+fetchai/protocols/fipa,QmPMRERu7BreF1tHy6nfLjUPS3thTCM1WrRsfAQZRUEQbb
+fetchai/protocols/gym,QmNShFTSARmkSXAZ9HvVWiX5DKdutKkZRC6g1NaqtGpzoi
+fetchai/protocols/http,QmTpZ8GjMpDv9nvfWL4cRwUxDcmzvNqsT1z76TzsyeBUkh
+fetchai/protocols/ledger_api,QmSob4wjYMMi74mNkMP2UpCTozt1WTjAfheoWficeB5TcR
+fetchai/protocols/ml_trade,QmcwQb6zEWFSEDt8jDPkTLfe9LKodCHai1xjNtGKnAmykx
+fetchai/protocols/oef_search,QmNnbw8CxFdUQ7E1K3ytKueq2gwPhpEXhaH7MVaxYjqV3U
+fetchai/protocols/scaffold,QmZ1fUdPutYFwaAwjMU4SCLu9ubKxTx3y59PAFyRuHw7BZ
+fetchai/protocols/signing,QmWfFpFhsbmN5dyLmmEzDUMjQRXLU5ni48YzsVaesuGGer
+fetchai/protocols/state_update,QmTwnydQvg7aMeSDnUA5j3nDPYuHvtbbyo26xERM4bV3zC
+fetchai/protocols/tac,QmSMMV9nfk2H7qua78izpmZwUgaccDbC9nty1ppiATJcvW
+fetchai/skills/aries_alice,QmcPob8KpEcMt236ufTCiqiZi6FTob9s12Nqg8s28WWVKP
+fetchai/skills/aries_faber,QmemjoaPWQyfoF7Pe4FB34KQwGP5KrA6KfRnFeqEepTmWZ
+fetchai/skills/carpark_client,QmT9wRwQYby6zuNX5Lyz7Bm8KvLhmaCcpa35PsWFNkhuso
+fetchai/skills/carpark_detection,QmScZT6oDae5BDfJ4Wq6nfH38ao5DZg22Cmkxp58iGTJDF
+fetchai/skills/echo,QmcfWAcwy9Mu1EJ8ae5LKRCPhtKNwRfEzQtgYx1VKuXQCr
+fetchai/skills/erc1155_client,QmbGnkLHWLXcpHdFnUWnNE3EuQVezZbwWBeV9WJhiEmfck
+fetchai/skills/erc1155_deploy,QmfSfzFxo7TCw8NC93GXHvFw1AFFmL9zusymHaGLrbur1w
+fetchai/skills/error,QmawE9AV4DnQiVHhzdUcEUQd9PToz4iL861VSc3KNpF1VB
+fetchai/skills/generic_buyer,QmNhAqXy18qmAiX8Pb3MUJBLj9ZctTtWodvyM4AE6Mz1mQ
+fetchai/skills/generic_seller,QmP9YAaYLcRYG5wMQf2KBfG7h4yNHAn5j8qtRCJiDkEXJM
+fetchai/skills/gym,QmP3qriWyccRu2kCBtAVLuM6ve79ifmA5iFLagWdQFHAcx
+fetchai/skills/http_echo,QmcV8bDeVdb51hQR9uigSiqJPzAkFPz7hqPzs6wcM8nVS5
+fetchai/skills/ml_data_provider,QmQP9ZsPJoxwAGpZCaz2uNqVuaUGtYo3R8wPFVgnMHZ63f
+fetchai/skills/ml_train,QmXSnVw2FDUXefsgAwJaxxzhn27ViQS5x1s1ytEoZx7pmy
+fetchai/skills/scaffold,QmPZfCsZDYvffThjzr8n2yYJFJ881wm8YsbBc1FKdjDXKR
+fetchai/skills/simple_service_registration,QmSRGtSxU5EUZyGmmUGbxUyFdCYpQvmD3Vv3ihgY4aMJqf
+fetchai/skills/tac_control,Qmc8Vj5FyzrbeopDrguUJfd4s5iEAN13FLJwZu12MhBTgs
+fetchai/skills/tac_control_contract,QmWhGcvhDwi7DBByVMQSATKXxNCxAU5a1B8HhEhx8RK8Bm
+fetchai/skills/tac_negotiation,QmTV8Bap864XJmjiHfDdfVT1ojQKEuYmzd63AabXCqDfRB
+fetchai/skills/tac_participation,QmPFhsDaS6QA1NBxuNUKMwAhC6eep3K8bnNkChN3LowDf2
+fetchai/skills/thermometer,QmcNUpps3wPxWAs3a31DTY3nzVJmfz1AL4bNSXAj1NBWMM
+fetchai/skills/thermometer_client,Qmc7Vp6xAm96k5NZ5AmU7fDFYNqb6FSsZXnBrGpbxsU6RZ
+fetchai/skills/weather_client,QmX4K3XadNyuq6gvjdvVV3LQEnXueRHhukpgFYUD9JTsWY
+fetchai/skills/weather_station,QmaoRHkEbmVm1zBtc3FSLjmBVfw3Xn6AvwzHjeniQ6wM3V
diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py
index 343fb075b1..9c9c58ec06 100755
--- a/scripts/generate_api_docs.py
+++ b/scripts/generate_api_docs.py
@@ -141,9 +141,21 @@ def generate_api_docs():
save_to_file(path, text)
+def install(package: str) -> int:
+ """
+ Install a PyPI package by calling pip.
+
+ :param package: the package name and version specifier.
+ :return: the return code.
+ """
+ return subprocess.check_call( # nosec
+ [sys.executable, "-m", "pip", "install", package]
+ )
+
+
if __name__ == "__main__":
res = shutil.which("pydoc-markdown")
if res is None:
- print("Please install pydoc-markdown first: `pip install pydoc-markdown`")
+ install("pydoc-markdown==3.3.0")
sys.exit(1)
generate_api_docs()
diff --git a/scripts/generate_ipfs_hashes.py b/scripts/generate_ipfs_hashes.py
index b7185d641d..3760fc1368 100755
--- a/scripts/generate_ipfs_hashes.py
+++ b/scripts/generate_ipfs_hashes.py
@@ -199,6 +199,14 @@ def __init__(self, timeout: float = 10.0):
res = shutil.which("ipfs")
if res is None:
raise Exception("Please install IPFS first!")
+ process = subprocess.Popen( # nosec
+ ["ipfs", "--version"], stdout=subprocess.PIPE, env=os.environ.copy(),
+ )
+ output, _ = process.communicate()
+ if b"0.4.23" not in output:
+ raise Exception(
+ "Please ensure you have version 0.4.23 of IPFS daemon installed."
+ )
self.process = None # type: Optional[subprocess.Popen]
def __enter__(self):
@@ -442,14 +450,14 @@ def check_same_ipfs_hash(
:param all_expected_hashes: the dictionary of all the expected hashes.
:return: True if the IPFS hash match, False otherwise.
"""
- if configuration.name in [
- "erc1155",
- "carpark_detection",
- "p2p_libp2p",
- "Agent0",
- "dummy",
- ]:
- return True # TODO: fix
+ # if configuration.name in [
+ # "erc1155",
+ # "carpark_detection",
+ # "p2p_libp2p",
+ # "Agent0",
+ # "dummy",
+ # ]:
+ # return True # packages with nested dirs or symlinks, kept for reference
key, actual_hash, result_list = ipfs_hashing(client, configuration, package_type)
expected_hash = all_expected_hashes[key]
result = actual_hash == expected_hash
diff --git a/scripts/update_package_versions.py b/scripts/update_package_versions.py
index 23b82bd917..fd5b659e78 100644
--- a/scripts/update_package_versions.py
+++ b/scripts/update_package_versions.py
@@ -186,8 +186,12 @@ def process_packages(
is_bumped = False
for type_ in TYPES:
for key, value in last_by_type[type_].items():
+ if key == "scaffold":
+ print("Package `{}` of type `{}` is never bumped!".format(key, type_))
+ continue
if key not in now_by_type[type_]:
print("Package `{}` of type `{}` no longer present!".format(key, type_))
+ continue
if now_by_type[type_][key] == value:
print(
"Package `{}` of type `{}` has not changed since last release!".format(
@@ -291,7 +295,6 @@ def process_package(type_: str, name: str) -> bool:
def run_once() -> bool:
"""Run the upgrade logic once."""
- check_if_running_allowed()
last = get_hashes_from_last_release()
now = get_hashes_from_current_release()
last_by_type = split_hashes_by_type(last)
@@ -301,6 +304,12 @@ def run_once() -> bool:
if __name__ == "__main__":
+ """
+ First, check all hashes are up to date, exit if not.
+ Then, run the bumping algo, re-hashing upon each bump.
+ """
+ run_hashing()
+ check_if_running_allowed()
while run_once():
run_hashing()
sys.exit(0)
diff --git a/setup.cfg b/setup.cfg
index eb82eeb645..a61724d70b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -118,6 +118,9 @@ ignore_missing_imports = True
[mypy-tests/data/generator/t_protocol/*]
ignore_errors = True
+[mypy-tests/data/generator/t_protocol_no_ct/*]
+ignore_errors = True
+
[mypy-tests/data/dummy_aea/vendor/*]
ignore_errors = True
diff --git a/setup.py b/setup.py
index cd7ad757da..ca796e3642 100644
--- a/setup.py
+++ b/setup.py
@@ -88,7 +88,7 @@ def parse_readme():
replacement = raw_url_root + r"\g<0>"
readme = re.sub(r"(?<=
MagicMock:
"""
diff --git a/tests/common/utils.py b/tests/common/utils.py
index 2fc3cdb938..abdddc2531 100644
--- a/tests/common/utils.py
+++ b/tests/common/utils.py
@@ -86,6 +86,11 @@ def setup(self) -> "AeaTool":
self.aea.start_setup()
return self
+ def teardown(self) -> "AeaTool":
+ """Call AEA.teardown."""
+ self.aea.teardown()
+ return self
+
def wait_outbox_empty(
self, sleep: float = DEFAULT_SLEEP, timeout: float = DEFAULT_TIMEOUT
) -> "AeaTool":
@@ -264,6 +269,7 @@ def wrap(*args, **kwargs) -> Any:
@contextmanager
def run_in_thread(fn, timeout=10, on_exit=None, **kwargs):
+ """Run a function in contextmanager and test and awaits it completed."""
thread = Thread(target=fn, **kwargs)
thread.daemon = True
thread.start()
@@ -278,6 +284,7 @@ def run_in_thread(fn, timeout=10, on_exit=None, **kwargs):
def wait_for_condition(condition_checker, timeout=2, error_msg="Timeout"):
+ """Wait for condition occures in selected timeout."""
start_time = time.time()
while not condition_checker():
diff --git a/tests/conftest.py b/tests/conftest.py
index 162796ae29..a4278974c5 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -16,6 +16,7 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
"""Conftest module for Pytest."""
import asyncio
import inspect
@@ -58,7 +59,7 @@
DEFAULT_SKILL_CONFIG_FILE as SKILL_YAML,
PublicId,
)
-from aea.configurations.constants import DEFAULT_CONNECTION
+from aea.configurations.constants import DEFAULT_CONNECTION, DEFAULT_LEDGER
from aea.connections.base import Connection
from aea.connections.stub.connection import StubConnection
from aea.contracts import Contract, contract_registry
@@ -71,6 +72,7 @@
FETCHAI_PRIVATE_KEY_FILE,
)
from aea.crypto.registries import make_crypto
+from aea.crypto.wallet import CryptoStore
from aea.identity.base import Identity
from aea.mail.base import Address
from aea.test_tools.click_testing import CliRunner as ImportedCliRunner
@@ -128,6 +130,8 @@
ETHEREUM = _ETHEREUM
FETCHAI = _FETCHAI
+COSMOS_PRIVATE_KEY_FILE_CONNECTION = "cosmos_connection_private_key.txt"
+
# private keys with value on testnet
COSMOS_PRIVATE_KEY_PATH = os.path.join(
ROOT_DIR, "tests", "data", COSMOS_PRIVATE_KEY_FILE
@@ -174,6 +178,8 @@
"log_file": "libp2p_node.log",
"public_uri": "127.0.0.1:9001",
}
+PUBLIC_DHT_P2P_MADDR_1 = "/dns4/agents-p2p-dht.sandbox.fetch-ai.com/tcp/9000/p2p/16Uiu2HAkw1ypeQYQbRFV5hKUxGRHocwU5ohmVmCnyJNg36tnPFdx"
+PUBLIC_DHT_P2P_MADDR_2 = "/dns4/agents-p2p-dht.sandbox.fetch-ai.com/tcp/9001/p2p/16Uiu2HAmVWnopQAqq4pniYLw44VRvYxBUoRHqjz1Hh2SoCyjbyRW"
# testnets
COSMOS_TESTNET_CONFIG = {"address": "https://rest-agent-land.prod.fetch-ai.com:443"}
@@ -190,7 +196,7 @@
UNKNOWN_SKILL_PUBLIC_ID = PublicId("unknown_author", "unknown_skill", "0.1.0")
LOCAL_CONNECTION_PUBLIC_ID = PublicId("fetchai", "local", "0.1.0")
P2P_CLIENT_CONNECTION_PUBLIC_ID = PublicId("fetchai", "p2p_client", "0.1.0")
-HTTP_CLIENT_CONNECTION_PUBLIC_ID = PublicId.from_str("fetchai/http_client:0.5.0")
+HTTP_CLIENT_CONNECTION_PUBLIC_ID = PublicId.from_str("fetchai/http_client:0.6.0")
HTTP_PROTOCOL_PUBLIC_ID = PublicId("fetchai", "http", "0.1.0")
STUB_CONNECTION_PUBLIC_ID = DEFAULT_CONNECTION
DUMMY_PROTOCOL_PUBLIC_ID = PublicId("dummy_author", "dummy", "0.1.0")
@@ -199,10 +205,11 @@
MAX_FLAKY_RERUNS = 3
MAX_FLAKY_RERUNS_ETH = 1
-MAX_FLAKY_RERUNS_INTEGRATION = 2
+MAX_FLAKY_RERUNS_INTEGRATION = 1
FETCHAI_PREF = os.path.join(ROOT_DIR, "packages", "fetchai")
-PROTOCOL_SPECS_PREF = os.path.join(ROOT_DIR, "examples", "protocol_specification_ex")
+PROTOCOL_SPECS_PREF_1 = os.path.join(ROOT_DIR, "examples", "protocol_specification_ex")
+PROTOCOL_SPECS_PREF_2 = os.path.join(ROOT_DIR, "tests", "data")
contract_config_files = [
os.path.join(ROOT_DIR, "aea", "contracts", "scaffold", CONTRACT_YAML),
@@ -303,18 +310,9 @@
]
protocol_specification_files = [
- os.path.join(PROTOCOL_SPECS_PREF, "contract_api.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "default.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "fipa.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "gym.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "http.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "ledger_api.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "ml_trade.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "oef_search.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "sample.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "signing.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "state_update.yaml",),
- os.path.join(PROTOCOL_SPECS_PREF, "tac.yaml",),
+ os.path.join(PROTOCOL_SPECS_PREF_1, "sample.yaml",),
+ os.path.join(PROTOCOL_SPECS_PREF_2, "sample_specification.yaml",),
+ os.path.join(PROTOCOL_SPECS_PREF_2, "sample_specification_no_custom_types.yaml",),
]
@@ -350,6 +348,7 @@ def action_for_platform(platform_name: str, skip: bool = True) -> Callable:
def decorator(pytest_func):
"""
For the sake of clarity, assume the chosen platform for the action is "Windows".
+
If the following condition is true:
- the current system is not Windows (is_different) AND we want to skip it (skip)
OR
@@ -378,7 +377,12 @@ def action(*args, **kwargs):
return type(
pytest_func.__name__,
(pytest_func,),
- {"setup_class": action, "setup": action, "setUp": action},
+ {
+ "setup_class": action,
+ "setup": action,
+ "setUp": action,
+ "_skipped": True,
+ },
)
@wraps(pytest_func)
@@ -784,15 +788,16 @@ def _make_libp2p_connection(
entry_peers: Optional[Sequence[MultiAddr]] = None,
delegate_port: int = 11234,
delegate_host: str = "127.0.0.1",
+ node_key_file: Optional[str] = None,
) -> P2PLibp2pConnection:
log_file = "libp2p_node_{}.log".format(port)
if os.path.exists(log_file):
os.remove(log_file)
- crypto = make_crypto(FETCHAI)
+ crypto = make_crypto(COSMOS)
identity = Identity("", address=crypto.address)
if relay and delegate:
configuration = ConnectionConfig(
- node_key_file=None,
+ node_key_file=node_key_file,
local_uri="{}:{}".format(host, port),
public_uri="{}:{}".format(host, port),
entry_peers=entry_peers,
@@ -802,7 +807,7 @@ def _make_libp2p_connection(
)
elif relay and not delegate:
configuration = ConnectionConfig(
- node_key_file=None,
+ node_key_file=node_key_file,
local_uri="{}:{}".format(host, port),
public_uri="{}:{}".format(host, port),
entry_peers=entry_peers,
@@ -811,7 +816,7 @@ def _make_libp2p_connection(
)
else:
configuration = ConnectionConfig(
- node_key_file=None,
+ node_key_file=node_key_file,
local_uri="{}:{}".format(host, port),
entry_peers=entry_peers,
log_file=log_file,
@@ -823,7 +828,7 @@ def _make_libp2p_connection(
def _make_libp2p_client_connection(
node_port: int = 11234, node_host: str = "127.0.0.1"
) -> P2PLibp2pClientConnection:
- crypto = make_crypto(FETCHAI)
+ crypto = make_crypto(COSMOS)
identity = Identity("", address=crypto.address)
configuration = ConnectionConfig(
client_key_file=None,
@@ -839,7 +844,7 @@ def libp2p_log_on_failure(fn: Callable) -> Callable:
:return: decorated method.
"""
-
+ # for pydcostyle
@wraps(fn)
def wrapper(self, *args, **kwargs):
try:
@@ -857,7 +862,7 @@ def wrapper(self, *args, **kwargs):
def libp2p_log_on_failure_all(cls):
"""
- Decorate every method of a class with `libp2p_log_on_failure`
+ Decorate every method of a class with `libp2p_log_on_failure`.
:return: class with decorated methods.
"""
@@ -879,7 +884,7 @@ def libp2p_log_on_failure_all(cls):
return cls
-def do_for_all(method_decorator):
+def _do_for_all(method_decorator):
def class_decorator(cls):
class GetAttributeMetaClass(type):
def __getattribute__(cls, name):
@@ -909,6 +914,22 @@ def __init__(self):
super().__init__("CWD was not restored")
+@pytest.fixture(scope="class", autouse=True)
+def aea_testcase_teardown_check(request):
+ """Check BaseAEATestCase.teardown_class for BaseAEATestCase based test cases."""
+ from aea.test_tools.test_cases import BaseAEATestCase # cause circular import
+
+ yield
+ if (
+ request.cls
+ and issubclass(request.cls, BaseAEATestCase)
+ and getattr(request.cls, "_skipped", False) is False
+ ):
+ assert getattr(
+ request.cls, "_is_teardown_class_called", None
+ ), "No BaseAEATestCase.teardown_class was called!"
+
+
@pytest.fixture(scope="class", autouse=True)
def check_test_class_cwd():
"""Check test case class restore CWD."""
@@ -929,6 +950,7 @@ def check_test_cwd(request):
old_cwd = os.getcwd()
yield
if old_cwd != os.getcwd():
+ os.chdir(ROOT_DIR)
raise CwdException()
@@ -947,11 +969,29 @@ def check_test_threads(request):
assert num_threads >= new_num_threads, "Non closed threads!"
+@pytest.fixture()
+async def ledger_apis_connection(request):
+ """Make a connection."""
+ crypto = make_crypto(DEFAULT_LEDGER)
+ identity = Identity("name", crypto.address)
+ crypto_store = CryptoStore()
+ directory = Path(ROOT_DIR, "packages", "fetchai", "connections", "ledger")
+ connection = Connection.from_dir(
+ directory, identity=identity, crypto_store=crypto_store
+ )
+ connection = cast(Connection, connection)
+ connection._logger = logging.getLogger("aea.packages.fetchai.connections.ledger")
+ await connection.connect()
+ yield connection
+ await connection.disconnect()
+
+
@pytest.fixture()
def erc1155_contract():
"""
- Instantiate an ERC1155 contract instance. As a side effect,
- register it to the registry, if not already registered.
+ Instantiate an ERC1155 contract instance.
+
+ As a side effect, register it to the registry, if not already registered.
"""
directory = Path(ROOT_DIR, "packages", "fetchai", "contracts", "erc1155")
configuration = ComponentConfiguration.load(ComponentType.CONTRACT, directory)
diff --git a/tests/data/aea-config.example.yaml b/tests/data/aea-config.example.yaml
index 17aa34e0fb..8421e05e94 100644
--- a/tests/data/aea-config.example.yaml
+++ b/tests/data/aea-config.example.yaml
@@ -7,16 +7,16 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/oef:0.6.0
+- fetchai/oef:0.7.0
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
-- fetchai/default:0.3.0
-- fetchai/tac:0.3.0
-- fetchai/fipa:0.4.0
+- fetchai/oef_search:0.4.0
+- fetchai/default:0.4.0
+- fetchai/tac:0.4.0
+- fetchai/fipa:0.5.0
skills:
-- fetchai/echo:0.3.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/echo:0.4.0
+default_connection: fetchai/oef:0.7.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/tests/data/aea-config.example_w_keys.yaml b/tests/data/aea-config.example_w_keys.yaml
index e685d96b53..385a9a65e1 100644
--- a/tests/data/aea-config.example_w_keys.yaml
+++ b/tests/data/aea-config.example_w_keys.yaml
@@ -7,16 +7,16 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/oef:0.6.0
+- fetchai/oef:0.7.0
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
-- fetchai/default:0.3.0
-- fetchai/tac:0.3.0
-- fetchai/fipa:0.4.0
+- fetchai/oef_search:0.4.0
+- fetchai/default:0.4.0
+- fetchai/tac:0.4.0
+- fetchai/fipa:0.5.0
skills:
-- fetchai/echo:0.3.0
-default_connection: fetchai/oef:0.6.0
+- fetchai/echo:0.4.0
+default_connection: fetchai/oef:0.7.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/tests/data/dependencies_skill/skill.yaml b/tests/data/dependencies_skill/skill.yaml
index 77ca268645..460a5a600e 100644
--- a/tests/data/dependencies_skill/skill.yaml
+++ b/tests/data/dependencies_skill/skill.yaml
@@ -9,7 +9,7 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: []
behaviours: {}
handlers: {}
diff --git a/tests/data/dummy_aea/aea-config.yaml b/tests/data/dummy_aea/aea-config.yaml
index a32248463d..7f1679e540 100644
--- a/tests/data/dummy_aea/aea-config.yaml
+++ b/tests/data/dummy_aea/aea-config.yaml
@@ -7,16 +7,16 @@ aea_version: '>=0.5.0, <0.6.0'
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/local:0.4.0
+- fetchai/local:0.5.0
contracts:
-- fetchai/erc1155:0.6.0
+- fetchai/erc1155:0.7.0
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
skills:
- dummy_author/dummy:0.1.0
-- fetchai/error:0.3.0
-default_connection: fetchai/local:0.4.0
+- fetchai/error:0.4.0
+default_connection: fetchai/local:0.5.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/tests/data/dummy_connection/connection.py b/tests/data/dummy_connection/connection.py
index 5d41819b92..6fc43e633a 100644
--- a/tests/data/dummy_connection/connection.py
+++ b/tests/data/dummy_connection/connection.py
@@ -24,7 +24,7 @@
from typing import Optional
from aea.configurations.base import ConnectionConfig, PublicId
-from aea.connections.base import Connection
+from aea.connections.base import Connection, ConnectionStates
from aea.crypto.wallet import CryptoStore
from aea.identity.base import Identity
from aea.mail.base import Envelope
@@ -38,18 +38,18 @@ class DummyConnection(Connection):
def __init__(self, **kwargs):
"""Initialize."""
super().__init__(**kwargs)
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
self._queue = None
async def connect(self, *args, **kwargs):
"""Connect."""
self._queue = asyncio.Queue(loop=self.loop)
- self.connection_status.is_connected = True
+ self._state.set(ConnectionStates.connected)
async def disconnect(self, *args, **kwargs):
"""Disconnect."""
await self._queue.put(None)
- self.connection_status.is_connected = False
+ self._state.set(ConnectionStates.disconnected)
async def send(self, envelope: "Envelope"):
"""Send an envelope."""
@@ -77,16 +77,20 @@ def put(self, envelope: Envelope):
@classmethod
def from_config(
- cls, configuration: ConnectionConfig, identity: Identity, cryptos: CryptoStore
+ cls,
+ configuration: ConnectionConfig,
+ identity: Identity,
+ crypto_store: CryptoStore,
+ **kwargs
) -> "Connection":
"""
Get the dummy connection from the connection configuration.
:param configuration: the connection configuration.
:param identity: the identity object.
- :param cryptos: object to access the connection crypto objects.
+ :param crypto_store: object to access the connection crypto objects.
:return: the connection object
"""
return DummyConnection(
- configuration=configuration, identity=identity, cryptos=cryptos
+ configuration=configuration, identity=identity, crypto_store=crypto_store
)
diff --git a/tests/data/dummy_connection/connection.yaml b/tests/data/dummy_connection/connection.yaml
index 69f48d77fd..6b3aa6a82e 100644
--- a/tests/data/dummy_connection/connection.yaml
+++ b/tests/data/dummy_connection/connection.yaml
@@ -6,14 +6,14 @@ license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
__init__.py: QmbjcWHRhRiYMqZbgeGkEGVYi8hQ1HnYM8pBYugGKx9YnK
- connection.py: QmXriASvrroCAKRteP9wUdhAUxH1iZgVTAriGY6ApL3iJc
+ connection.py: QmYn4mpVJTjKUUU9sCDGQHsTzYPeK4mTjwEHepHQddMMjs
fingerprint_ignore_patterns: []
protocols: []
class_name: DummyConnection
config: {}
excluded_protocols: []
restricted_to_protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
dependencies:
dep1:
version: ==1.0.0
diff --git a/tests/data/dummy_skill/skill.yaml b/tests/data/dummy_skill/skill.yaml
index d9ee43dd29..45d8a26ed6 100644
--- a/tests/data/dummy_skill/skill.yaml
+++ b/tests/data/dummy_skill/skill.yaml
@@ -15,7 +15,7 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: []
behaviours:
dummy:
diff --git a/tests/data/generator/t_protocol/custom_types.py b/tests/data/generator/t_protocol/custom_types.py
index ca6d72d843..0a2feeda2c 100644
--- a/tests/data/generator/t_protocol/custom_types.py
+++ b/tests/data/generator/t_protocol/custom_types.py
@@ -67,8 +67,8 @@ def encode(data_model_protobuf_object, data_model_object: "DataModel") -> None:
data_model_protobuf_object.list_field.extend(data_model_object.list_field)
data_model_protobuf_object.dict_field.update(data_model_object.dict_field)
- @staticmethod
- def decode(data_model_protobuf_object) -> "DataModel":
+ @classmethod
+ def decode(cls, data_model_protobuf_object) -> "DataModel":
"""
Decode a protocol buffer object that corresponds with this class into an instance of this class.
diff --git a/tests/data/generator/t_protocol/dialogues.py b/tests/data/generator/t_protocol/dialogues.py
new file mode 100644
index 0000000000..d7e60880ab
--- /dev/null
+++ b/tests/data/generator/t_protocol/dialogues.py
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2020 fetchai
+#
+# 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 classes required for t_protocol dialogue management.
+
+- TProtocolDialogue: The dialogue class maintains state of a dialogue and manages it.
+- TProtocolDialogues: The dialogues class keeps track of all dialogues.
+"""
+
+from abc import ABC
+from typing import Dict, FrozenSet, Optional, cast
+
+from aea.helpers.dialogue.base import Dialogue, DialogueLabel, Dialogues
+from aea.mail.base import Address
+from aea.protocols.base import Message
+
+from tests.data.generator.t_protocol.message import TProtocolMessage
+
+
+class TProtocolDialogue(Dialogue):
+ """The t_protocol dialogue class maintains state of a dialogue and manages it."""
+
+ INITIAL_PERFORMATIVES = frozenset(
+ {
+ TProtocolMessage.Performative.PERFORMATIVE_CT,
+ TProtocolMessage.Performative.PERFORMATIVE_PT,
+ }
+ )
+ TERMINAL_PERFORMATIVES = frozenset(
+ {
+ TProtocolMessage.Performative.PERFORMATIVE_MT,
+ TProtocolMessage.Performative.PERFORMATIVE_O,
+ TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS,
+ }
+ )
+ VALID_REPLIES = {
+ TProtocolMessage.Performative.PERFORMATIVE_CT: frozenset(
+ {TProtocolMessage.Performative.PERFORMATIVE_PCT}
+ ),
+ TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS: frozenset(
+ {TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS}
+ ),
+ TProtocolMessage.Performative.PERFORMATIVE_MT: frozenset(),
+ TProtocolMessage.Performative.PERFORMATIVE_O: frozenset(),
+ TProtocolMessage.Performative.PERFORMATIVE_PCT: frozenset(
+ {
+ TProtocolMessage.Performative.PERFORMATIVE_MT,
+ TProtocolMessage.Performative.PERFORMATIVE_O,
+ }
+ ),
+ TProtocolMessage.Performative.PERFORMATIVE_PMT: frozenset(
+ {
+ TProtocolMessage.Performative.PERFORMATIVE_MT,
+ TProtocolMessage.Performative.PERFORMATIVE_O,
+ }
+ ),
+ TProtocolMessage.Performative.PERFORMATIVE_PT: frozenset(
+ {TProtocolMessage.Performative.PERFORMATIVE_PMT}
+ ),
+ }
+
+ class Role(Dialogue.Role):
+ """This class defines the agent's role in a t_protocol dialogue."""
+
+ ROLE_1 = "role_1"
+ ROLE_2 = "role_2"
+
+ class EndState(Dialogue.EndState):
+ """This class defines the end states of a t_protocol dialogue."""
+
+ END_STATE_1 = 0
+ END_STATE_2 = 1
+ END_STATE_3 = 2
+
+ def __init__(
+ self,
+ dialogue_label: DialogueLabel,
+ agent_address: Optional[Address] = None,
+ role: Optional[Dialogue.Role] = None,
+ ) -> None:
+ """
+ Initialize a dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param agent_address: the address of the agent for whom this dialogue is maintained
+ :param role: the role of the agent this dialogue is maintained for
+ :return: None
+ """
+ Dialogue.__init__(
+ self,
+ dialogue_label=dialogue_label,
+ agent_address=agent_address,
+ role=role,
+ rules=Dialogue.Rules(
+ cast(FrozenSet[Message.Performative], self.INITIAL_PERFORMATIVES),
+ cast(FrozenSet[Message.Performative], self.TERMINAL_PERFORMATIVES),
+ cast(
+ Dict[Message.Performative, FrozenSet[Message.Performative]],
+ self.VALID_REPLIES,
+ ),
+ ),
+ )
+
+ def is_valid(self, message: Message) -> bool:
+ """
+ Check whether 'message' is a valid next message in the dialogue.
+
+ These rules capture specific constraints designed for dialogues which are instances of a concrete sub-class of this class.
+ Override this method with your additional dialogue rules.
+
+ :param message: the message to be validated
+ :return: True if valid, False otherwise
+ """
+ return True
+
+
+class TProtocolDialogues(Dialogues, ABC):
+ """This class keeps track of all t_protocol dialogues."""
+
+ END_STATES = frozenset(
+ {
+ TProtocolDialogue.EndState.END_STATE_1,
+ TProtocolDialogue.EndState.END_STATE_2,
+ TProtocolDialogue.EndState.END_STATE_3,
+ }
+ )
+
+ def __init__(self, agent_address: Address) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Dialogues.__init__(
+ self,
+ agent_address=agent_address,
+ end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),
+ )
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> TProtocolDialogue:
+ """
+ Create an instance of t_protocol dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = TProtocolDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/tests/data/generator/t_protocol/message.py b/tests/data/generator/t_protocol/message.py
index 576e9c0d3d..b98a955ed9 100644
--- a/tests/data/generator/t_protocol/message.py
+++ b/tests/data/generator/t_protocol/message.py
@@ -28,7 +28,7 @@
from tests.data.generator.t_protocol.custom_types import DataModel as CustomDataModel
-logger = logging.getLogger("packages.fetchai.protocols.t_protocol.message")
+logger = logging.getLogger("aea.packages.fetchai.protocols.t_protocol.message")
DEFAULT_BODY_SIZE = 4
@@ -36,7 +36,7 @@
class TProtocolMessage(Message):
"""A protocol for testing purposes."""
- protocol_id = ProtocolId("fetchai", "t_protocol", "0.1.0")
+ protocol_id = ProtocolId.from_str("fetchai/t_protocol:0.1.0")
DataModel = CustomDataModel
@@ -106,7 +106,7 @@ def message_id(self) -> int:
return cast(int, self.get("message_id"))
@property
- def performative(self) -> Performative: # noqa: F821
+ def performative(self) -> Performative: # type: ignore # noqa: F821
"""Get the performative of the message."""
assert self.is_set("performative"), "performative is not set."
return cast(TProtocolMessage.Performative, self.get("performative"))
@@ -135,6 +135,14 @@ def content_ct(self) -> CustomDataModel:
assert self.is_set("content_ct"), "'content_ct' content is not set."
return cast(CustomDataModel, self.get("content_ct"))
+ @property
+ def content_dict_bool_bool(self) -> Dict[bool, bool]:
+ """Get the 'content_dict_bool_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_bool"
+ ), "'content_dict_bool_bool' content is not set."
+ return cast(Dict[bool, bool], self.get("content_dict_bool_bool"))
+
@property
def content_dict_bool_bytes(self) -> Dict[bool, bytes]:
"""Get the 'content_dict_bool_bytes' content from the message."""
@@ -143,6 +151,86 @@ def content_dict_bool_bytes(self) -> Dict[bool, bytes]:
), "'content_dict_bool_bytes' content is not set."
return cast(Dict[bool, bytes], self.get("content_dict_bool_bytes"))
+ @property
+ def content_dict_bool_float(self) -> Dict[bool, float]:
+ """Get the 'content_dict_bool_float' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_float"
+ ), "'content_dict_bool_float' content is not set."
+ return cast(Dict[bool, float], self.get("content_dict_bool_float"))
+
+ @property
+ def content_dict_bool_int(self) -> Dict[bool, int]:
+ """Get the 'content_dict_bool_int' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_int"
+ ), "'content_dict_bool_int' content is not set."
+ return cast(Dict[bool, int], self.get("content_dict_bool_int"))
+
+ @property
+ def content_dict_bool_str(self) -> Dict[bool, str]:
+ """Get the 'content_dict_bool_str' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_str"
+ ), "'content_dict_bool_str' content is not set."
+ return cast(Dict[bool, str], self.get("content_dict_bool_str"))
+
+ @property
+ def content_dict_int_bool(self) -> Dict[int, bool]:
+ """Get the 'content_dict_int_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_int_bool"
+ ), "'content_dict_int_bool' content is not set."
+ return cast(Dict[int, bool], self.get("content_dict_int_bool"))
+
+ @property
+ def content_dict_int_bytes(self) -> Dict[int, bytes]:
+ """Get the 'content_dict_int_bytes' content from the message."""
+ assert self.is_set(
+ "content_dict_int_bytes"
+ ), "'content_dict_int_bytes' content is not set."
+ return cast(Dict[int, bytes], self.get("content_dict_int_bytes"))
+
+ @property
+ def content_dict_int_float(self) -> Dict[int, float]:
+ """Get the 'content_dict_int_float' content from the message."""
+ assert self.is_set(
+ "content_dict_int_float"
+ ), "'content_dict_int_float' content is not set."
+ return cast(Dict[int, float], self.get("content_dict_int_float"))
+
+ @property
+ def content_dict_int_int(self) -> Dict[int, int]:
+ """Get the 'content_dict_int_int' content from the message."""
+ assert self.is_set(
+ "content_dict_int_int"
+ ), "'content_dict_int_int' content is not set."
+ return cast(Dict[int, int], self.get("content_dict_int_int"))
+
+ @property
+ def content_dict_int_str(self) -> Dict[int, str]:
+ """Get the 'content_dict_int_str' content from the message."""
+ assert self.is_set(
+ "content_dict_int_str"
+ ), "'content_dict_int_str' content is not set."
+ return cast(Dict[int, str], self.get("content_dict_int_str"))
+
+ @property
+ def content_dict_str_bool(self) -> Dict[str, bool]:
+ """Get the 'content_dict_str_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_str_bool"
+ ), "'content_dict_str_bool' content is not set."
+ return cast(Dict[str, bool], self.get("content_dict_str_bool"))
+
+ @property
+ def content_dict_str_bytes(self) -> Dict[str, bytes]:
+ """Get the 'content_dict_str_bytes' content from the message."""
+ assert self.is_set(
+ "content_dict_str_bytes"
+ ), "'content_dict_str_bytes' content is not set."
+ return cast(Dict[str, bytes], self.get("content_dict_str_bytes"))
+
@property
def content_dict_str_float(self) -> Dict[str, float]:
"""Get the 'content_dict_str_float' content from the message."""
@@ -151,6 +239,22 @@ def content_dict_str_float(self) -> Dict[str, float]:
), "'content_dict_str_float' content is not set."
return cast(Dict[str, float], self.get("content_dict_str_float"))
+ @property
+ def content_dict_str_int(self) -> Dict[str, int]:
+ """Get the 'content_dict_str_int' content from the message."""
+ assert self.is_set(
+ "content_dict_str_int"
+ ), "'content_dict_str_int' content is not set."
+ return cast(Dict[str, int], self.get("content_dict_str_int"))
+
+ @property
+ def content_dict_str_str(self) -> Dict[str, str]:
+ """Get the 'content_dict_str_str' content from the message."""
+ assert self.is_set(
+ "content_dict_str_str"
+ ), "'content_dict_str_str' content is not set."
+ return cast(Dict[str, str], self.get("content_dict_str_str"))
+
@property
def content_float(self) -> float:
"""Get the 'content_float' content from the message."""
@@ -220,37 +324,9 @@ def content_o_list_bytes(self) -> Optional[Tuple[bytes, ...]]:
return cast(Optional[Tuple[bytes, ...]], self.get("content_o_list_bytes"))
@property
- def content_o_set_float(self) -> Optional[FrozenSet[float]]:
- """Get the 'content_o_set_float' content from the message."""
- return cast(Optional[FrozenSet[float]], self.get("content_o_set_float"))
-
- @property
- def content_o_union(
- self,
- ) -> Optional[
- Union[
- str,
- Dict[str, int],
- FrozenSet[int],
- FrozenSet[bytes],
- Tuple[bool, ...],
- Dict[str, float],
- ]
- ]:
- """Get the 'content_o_union' content from the message."""
- return cast(
- Optional[
- Union[
- str,
- Dict[str, int],
- FrozenSet[int],
- FrozenSet[bytes],
- Tuple[bool, ...],
- Dict[str, float],
- ]
- ],
- self.get("content_o_union"),
- )
+ def content_o_set_int(self) -> Optional[FrozenSet[int]]:
+ """Get the 'content_o_set_int' content from the message."""
+ return cast(Optional[FrozenSet[int]], self.get("content_o_set_int"))
@property
def content_set_bool(self) -> FrozenSet[bool]:
@@ -511,7 +587,102 @@ def _is_consistent(self) -> bool:
type(element) == str for element in self.content_list_str
), "Invalid type for tuple elements in content 'content_list_str'. Expected 'str'."
elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_PMT:
- expected_nb_of_contents = 2
+ expected_nb_of_contents = 15
+ assert (
+ type(self.content_dict_int_bytes) == dict
+ ), "Invalid type for content 'content_dict_int_bytes'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_bytes)
+ )
+ for (
+ key_of_content_dict_int_bytes,
+ value_of_content_dict_int_bytes,
+ ) in self.content_dict_int_bytes.items():
+ assert (
+ type(key_of_content_dict_int_bytes) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_bytes'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_bytes)
+ )
+ assert (
+ type(value_of_content_dict_int_bytes) == bytes
+ ), "Invalid type for dictionary values in content 'content_dict_int_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(value_of_content_dict_int_bytes)
+ )
+ assert (
+ type(self.content_dict_int_int) == dict
+ ), "Invalid type for content 'content_dict_int_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_int)
+ )
+ for (
+ key_of_content_dict_int_int,
+ value_of_content_dict_int_int,
+ ) in self.content_dict_int_int.items():
+ assert (
+ type(key_of_content_dict_int_int) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_int'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_int)
+ )
+ assert (
+ type(value_of_content_dict_int_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_int_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_int_int)
+ )
+ assert (
+ type(self.content_dict_int_float) == dict
+ ), "Invalid type for content 'content_dict_int_float'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_float)
+ )
+ for (
+ key_of_content_dict_int_float,
+ value_of_content_dict_int_float,
+ ) in self.content_dict_int_float.items():
+ assert (
+ type(key_of_content_dict_int_float) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_float'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_float)
+ )
+ assert (
+ type(value_of_content_dict_int_float) == float
+ ), "Invalid type for dictionary values in content 'content_dict_int_float'. Expected 'float'. Found '{}'.".format(
+ type(value_of_content_dict_int_float)
+ )
+ assert (
+ type(self.content_dict_int_bool) == dict
+ ), "Invalid type for content 'content_dict_int_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_bool)
+ )
+ for (
+ key_of_content_dict_int_bool,
+ value_of_content_dict_int_bool,
+ ) in self.content_dict_int_bool.items():
+ assert (
+ type(key_of_content_dict_int_bool) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_bool'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_bool)
+ )
+ assert (
+ type(value_of_content_dict_int_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_int_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_int_bool)
+ )
+ assert (
+ type(self.content_dict_int_str) == dict
+ ), "Invalid type for content 'content_dict_int_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_str)
+ )
+ for (
+ key_of_content_dict_int_str,
+ value_of_content_dict_int_str,
+ ) in self.content_dict_int_str.items():
+ assert (
+ type(key_of_content_dict_int_str) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_str'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_str)
+ )
+ assert (
+ type(value_of_content_dict_int_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_int_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_int_str)
+ )
assert (
type(self.content_dict_bool_bytes) == dict
), "Invalid type for content 'content_dict_bool_bytes'. Expected 'dict'. Found '{}'.".format(
@@ -531,6 +702,120 @@ def _is_consistent(self) -> bool:
), "Invalid type for dictionary values in content 'content_dict_bool_bytes'. Expected 'bytes'. Found '{}'.".format(
type(value_of_content_dict_bool_bytes)
)
+ assert (
+ type(self.content_dict_bool_int) == dict
+ ), "Invalid type for content 'content_dict_bool_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_int)
+ )
+ for (
+ key_of_content_dict_bool_int,
+ value_of_content_dict_bool_int,
+ ) in self.content_dict_bool_int.items():
+ assert (
+ type(key_of_content_dict_bool_int) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_int'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_int)
+ )
+ assert (
+ type(value_of_content_dict_bool_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_bool_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_bool_int)
+ )
+ assert (
+ type(self.content_dict_bool_float) == dict
+ ), "Invalid type for content 'content_dict_bool_float'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_float)
+ )
+ for (
+ key_of_content_dict_bool_float,
+ value_of_content_dict_bool_float,
+ ) in self.content_dict_bool_float.items():
+ assert (
+ type(key_of_content_dict_bool_float) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_float'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_float)
+ )
+ assert (
+ type(value_of_content_dict_bool_float) == float
+ ), "Invalid type for dictionary values in content 'content_dict_bool_float'. Expected 'float'. Found '{}'.".format(
+ type(value_of_content_dict_bool_float)
+ )
+ assert (
+ type(self.content_dict_bool_bool) == dict
+ ), "Invalid type for content 'content_dict_bool_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_bool)
+ )
+ for (
+ key_of_content_dict_bool_bool,
+ value_of_content_dict_bool_bool,
+ ) in self.content_dict_bool_bool.items():
+ assert (
+ type(key_of_content_dict_bool_bool) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_bool)
+ )
+ assert (
+ type(value_of_content_dict_bool_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_bool_bool)
+ )
+ assert (
+ type(self.content_dict_bool_str) == dict
+ ), "Invalid type for content 'content_dict_bool_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_str)
+ )
+ for (
+ key_of_content_dict_bool_str,
+ value_of_content_dict_bool_str,
+ ) in self.content_dict_bool_str.items():
+ assert (
+ type(key_of_content_dict_bool_str) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_str'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_str)
+ )
+ assert (
+ type(value_of_content_dict_bool_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_bool_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_bool_str)
+ )
+ assert (
+ type(self.content_dict_str_bytes) == dict
+ ), "Invalid type for content 'content_dict_str_bytes'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_bytes)
+ )
+ for (
+ key_of_content_dict_str_bytes,
+ value_of_content_dict_str_bytes,
+ ) in self.content_dict_str_bytes.items():
+ assert (
+ type(key_of_content_dict_str_bytes) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_bytes'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_bytes)
+ )
+ assert (
+ type(value_of_content_dict_str_bytes) == bytes
+ ), "Invalid type for dictionary values in content 'content_dict_str_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(value_of_content_dict_str_bytes)
+ )
+ assert (
+ type(self.content_dict_str_int) == dict
+ ), "Invalid type for content 'content_dict_str_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_int)
+ )
+ for (
+ key_of_content_dict_str_int,
+ value_of_content_dict_str_int,
+ ) in self.content_dict_str_int.items():
+ assert (
+ type(key_of_content_dict_str_int) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_int'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_int)
+ )
+ assert (
+ type(value_of_content_dict_str_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_str_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_str_int)
+ )
assert (
type(self.content_dict_str_float) == dict
), "Invalid type for content 'content_dict_str_float'. Expected 'dict'. Found '{}'.".format(
@@ -550,6 +835,44 @@ def _is_consistent(self) -> bool:
), "Invalid type for dictionary values in content 'content_dict_str_float'. Expected 'float'. Found '{}'.".format(
type(value_of_content_dict_str_float)
)
+ assert (
+ type(self.content_dict_str_bool) == dict
+ ), "Invalid type for content 'content_dict_str_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_bool)
+ )
+ for (
+ key_of_content_dict_str_bool,
+ value_of_content_dict_str_bool,
+ ) in self.content_dict_str_bool.items():
+ assert (
+ type(key_of_content_dict_str_bool) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_bool'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_bool)
+ )
+ assert (
+ type(value_of_content_dict_str_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_str_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_str_bool)
+ )
+ assert (
+ type(self.content_dict_str_str) == dict
+ ), "Invalid type for content 'content_dict_str_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_str)
+ )
+ for (
+ key_of_content_dict_str_str,
+ value_of_content_dict_str_str,
+ ) in self.content_dict_str_str.items():
+ assert (
+ type(key_of_content_dict_str_str) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_str'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_str)
+ )
+ assert (
+ type(value_of_content_dict_str_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_str_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_str_str)
+ )
elif self.performative == TProtocolMessage.Performative.PERFORMATIVE_MT:
expected_nb_of_contents = 2
assert (
@@ -642,19 +965,17 @@ def _is_consistent(self) -> bool:
), "Invalid type for content 'content_o_bool'. Expected 'bool'. Found '{}'.".format(
type(content_o_bool)
)
- if self.is_set("content_o_set_float"):
+ if self.is_set("content_o_set_int"):
expected_nb_of_contents += 1
- content_o_set_float = cast(
- FrozenSet[float], self.content_o_set_float
- )
+ content_o_set_int = cast(FrozenSet[int], self.content_o_set_int)
assert (
- type(content_o_set_float) == frozenset
- ), "Invalid type for content 'content_o_set_float'. Expected 'frozenset'. Found '{}'.".format(
- type(content_o_set_float)
+ type(content_o_set_int) == frozenset
+ ), "Invalid type for content 'content_o_set_int'. Expected 'frozenset'. Found '{}'.".format(
+ type(content_o_set_int)
)
assert all(
- type(element) == float for element in content_o_set_float
- ), "Invalid type for frozenset elements in content 'content_o_set_float'. Expected 'float'."
+ type(element) == int for element in content_o_set_int
+ ), "Invalid type for frozenset elements in content 'content_o_set_int'. Expected 'int'."
if self.is_set("content_o_list_bytes"):
expected_nb_of_contents += 1
content_o_list_bytes = cast(
@@ -692,46 +1013,6 @@ def _is_consistent(self) -> bool:
), "Invalid type for dictionary values in content 'content_o_dict_str_int'. Expected 'int'. Found '{}'.".format(
type(value_of_content_o_dict_str_int)
)
- if self.is_set("content_o_union"):
- expected_nb_of_contents += 1
- content_o_union = cast(
- Union[
- str,
- Dict[str, int],
- FrozenSet[int],
- FrozenSet[bytes],
- Tuple[bool, ...],
- Dict[str, float],
- ],
- self.content_o_union,
- )
- assert (
- type(content_o_union) == dict
- or type(content_o_union) == frozenset
- or type(content_o_union) == str
- or type(content_o_union) == tuple
- ), "Invalid type for content 'content_o_union'. Expected either of '['dict', 'frozenset', 'str', 'tuple']'. Found '{}'.".format(
- type(content_o_union)
- )
- if type(content_o_union) == frozenset:
- assert all(
- type(element) == bytes for element in content_o_union
- ) or all(
- type(element) == int for element in content_o_union
- ), "Invalid type for frozenset elements in content 'content_o_union'. Expected either 'bytes' or 'int'."
- if type(content_o_union) == tuple:
- assert all(
- type(element) == bool for element in content_o_union
- ), "Invalid type for tuple elements in content 'content_o_union'. Expected 'bool'."
- if type(content_o_union) == dict:
- for (
- key_of_content_o_union,
- value_of_content_o_union,
- ) in content_o_union.items():
- assert (
- type(key_of_content_o_union) == str
- and type(value_of_content_o_union) == float
- ), "Invalid type for dictionary key, value in content 'content_o_union'. Expected 'str', 'float'."
elif (
self.performative
== TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
diff --git a/tests/data/generator/t_protocol/protocol.yaml b/tests/data/generator/t_protocol/protocol.yaml
index 43a4591d20..a172f6bcd1 100644
--- a/tests/data/generator/t_protocol/protocol.yaml
+++ b/tests/data/generator/t_protocol/protocol.yaml
@@ -5,12 +5,13 @@ description: A protocol for testing purposes.
license: Apache-2.0
aea_version: '>=0.5.0, <0.6.0'
fingerprint:
- __init__.py: QmaarNrn5mcEYupCdQxpzpvH4PY5Wto7rtkjUjmHTUShiH
+ __init__.py: QmTwLir2v2eYMkDeUomf9uL1hrQhjzVTTqrQwamGG5iwn4
custom_types.py: Qmd5CrULVdtcNQLz5R1i9LpJi9Nhzd7nQnwN737FqibgLs
- message.py: QmZDjKrRRrfidEg2rxGC2Qoo4DBaEEfEvLu3bdeBbKL1tf
- serialization.py: QmZDHQcL5KbDLuqm9dsWeS5e3xwBxVC9sBLehWeDGpgysr
- t_protocol.proto: QmNryKk13EDZhx2m4YMFFMF33qEy41u7eNfWuhcadKowJF
- t_protocol_pb2.py: QmfJDyZ8U5Ay81pc991sf7asZ9QCFVUhwEWEXfWyY3yP8h
+ dialogues.py: QmSh74pVsprgNbz4Y2B2EWt4C6tsNDsRfuYcjwJYiu8apz
+ message.py: QmUrAcMnqoBMs1nSDzp8c6fr82qPMgbjGQNdQgxa4YYCxc
+ serialization.py: QmcS33k6rHgCCkhBuQ5kiXVKFMxxEzcZManshPD51MEHbw
+ t_protocol.proto: QmRuYvnojwkyZLzeECH3snomgoMJTB3m48yJiLq8LYsVb8
+ t_protocol_pb2.py: QmXrSgBBJCj8hbGCynKrvdkSDohQzHLPBA2vi5hDHmaGid
fingerprint_ignore_patterns: []
dependencies:
protobuf: {}
diff --git a/tests/data/generator/t_protocol/serialization.py b/tests/data/generator/t_protocol/serialization.py
index 413c2cc8b1..942f766ba8 100644
--- a/tests/data/generator/t_protocol/serialization.py
+++ b/tests/data/generator/t_protocol/serialization.py
@@ -92,10 +92,36 @@ def encode(msg: Message) -> bytes:
t_protocol_msg.performative_pct.CopyFrom(performative)
elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PMT:
performative = t_protocol_pb2.TProtocolMessage.Performative_Pmt_Performative() # type: ignore
+ content_dict_int_bytes = msg.content_dict_int_bytes
+ performative.content_dict_int_bytes.update(content_dict_int_bytes)
+ content_dict_int_int = msg.content_dict_int_int
+ performative.content_dict_int_int.update(content_dict_int_int)
+ content_dict_int_float = msg.content_dict_int_float
+ performative.content_dict_int_float.update(content_dict_int_float)
+ content_dict_int_bool = msg.content_dict_int_bool
+ performative.content_dict_int_bool.update(content_dict_int_bool)
+ content_dict_int_str = msg.content_dict_int_str
+ performative.content_dict_int_str.update(content_dict_int_str)
content_dict_bool_bytes = msg.content_dict_bool_bytes
performative.content_dict_bool_bytes.update(content_dict_bool_bytes)
+ content_dict_bool_int = msg.content_dict_bool_int
+ performative.content_dict_bool_int.update(content_dict_bool_int)
+ content_dict_bool_float = msg.content_dict_bool_float
+ performative.content_dict_bool_float.update(content_dict_bool_float)
+ content_dict_bool_bool = msg.content_dict_bool_bool
+ performative.content_dict_bool_bool.update(content_dict_bool_bool)
+ content_dict_bool_str = msg.content_dict_bool_str
+ performative.content_dict_bool_str.update(content_dict_bool_str)
+ content_dict_str_bytes = msg.content_dict_str_bytes
+ performative.content_dict_str_bytes.update(content_dict_str_bytes)
+ content_dict_str_int = msg.content_dict_str_int
+ performative.content_dict_str_int.update(content_dict_str_int)
content_dict_str_float = msg.content_dict_str_float
performative.content_dict_str_float.update(content_dict_str_float)
+ content_dict_str_bool = msg.content_dict_str_bool
+ performative.content_dict_str_bool.update(content_dict_str_bool)
+ content_dict_str_str = msg.content_dict_str_str
+ performative.content_dict_str_str.update(content_dict_str_str)
t_protocol_msg.performative_pmt.CopyFrom(performative)
elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_MT:
performative = t_protocol_pb2.TProtocolMessage.Performative_Mt_Performative() # type: ignore
@@ -227,10 +253,10 @@ def encode(msg: Message) -> bytes:
performative.content_o_bool_is_set = True
content_o_bool = msg.content_o_bool
performative.content_o_bool = content_o_bool
- if msg.is_set("content_o_set_float"):
- performative.content_o_set_float_is_set = True
- content_o_set_float = msg.content_o_set_float
- performative.content_o_set_float.extend(content_o_set_float)
+ if msg.is_set("content_o_set_int"):
+ performative.content_o_set_int_is_set = True
+ content_o_set_int = msg.content_o_set_int
+ performative.content_o_set_int.extend(content_o_set_int)
if msg.is_set("content_o_list_bytes"):
performative.content_o_list_bytes_is_set = True
content_o_list_bytes = msg.content_o_list_bytes
@@ -239,48 +265,6 @@ def encode(msg: Message) -> bytes:
performative.content_o_dict_str_int_is_set = True
content_o_dict_str_int = msg.content_o_dict_str_int
performative.content_o_dict_str_int.update(content_o_dict_str_int)
- if msg.is_set("content_o_union_type_str"):
- performative.content_o_union_type_str_is_set = True
- content_o_union_type_str = msg.content_o_union_type_str
- performative.content_o_union_type_str = content_o_union_type_str
- if msg.is_set("content_o_union_type_dict_of_str_int"):
- performative.content_o_union_type_dict_of_str_int_is_set = True
- content_o_union_type_dict_of_str_int = (
- msg.content_o_union_type_dict_of_str_int
- )
- performative.content_o_union_type_dict_of_str_int.update(
- content_o_union_type_dict_of_str_int
- )
- if msg.is_set("content_o_union_type_set_of_int"):
- performative.content_o_union_type_set_of_int_is_set = True
- content_o_union_type_set_of_int = msg.content_o_union_type_set_of_int
- performative.content_o_union_type_set_of_int.extend(
- content_o_union_type_set_of_int
- )
- if msg.is_set("content_o_union_type_set_of_bytes"):
- performative.content_o_union_type_set_of_bytes_is_set = True
- content_o_union_type_set_of_bytes = (
- msg.content_o_union_type_set_of_bytes
- )
- performative.content_o_union_type_set_of_bytes.extend(
- content_o_union_type_set_of_bytes
- )
- if msg.is_set("content_o_union_type_list_of_bool"):
- performative.content_o_union_type_list_of_bool_is_set = True
- content_o_union_type_list_of_bool = (
- msg.content_o_union_type_list_of_bool
- )
- performative.content_o_union_type_list_of_bool.extend(
- content_o_union_type_list_of_bool
- )
- if msg.is_set("content_o_union_type_dict_of_str_float"):
- performative.content_o_union_type_dict_of_str_float_is_set = True
- content_o_union_type_dict_of_str_float = (
- msg.content_o_union_type_dict_of_str_float
- )
- performative.content_o_union_type_dict_of_str_float.update(
- content_o_union_type_dict_of_str_float
- )
t_protocol_msg.performative_o.CopyFrom(performative)
elif (
performative_id == TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
@@ -360,6 +344,25 @@ def decode(obj: bytes) -> Message:
content_list_str_tuple = tuple(content_list_str)
performative_content["content_list_str"] = content_list_str_tuple
elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_PMT:
+ content_dict_int_bytes = (
+ t_protocol_pb.performative_pmt.content_dict_int_bytes
+ )
+ content_dict_int_bytes_dict = dict(content_dict_int_bytes)
+ performative_content["content_dict_int_bytes"] = content_dict_int_bytes_dict
+ content_dict_int_int = t_protocol_pb.performative_pmt.content_dict_int_int
+ content_dict_int_int_dict = dict(content_dict_int_int)
+ performative_content["content_dict_int_int"] = content_dict_int_int_dict
+ content_dict_int_float = (
+ t_protocol_pb.performative_pmt.content_dict_int_float
+ )
+ content_dict_int_float_dict = dict(content_dict_int_float)
+ performative_content["content_dict_int_float"] = content_dict_int_float_dict
+ content_dict_int_bool = t_protocol_pb.performative_pmt.content_dict_int_bool
+ content_dict_int_bool_dict = dict(content_dict_int_bool)
+ performative_content["content_dict_int_bool"] = content_dict_int_bool_dict
+ content_dict_int_str = t_protocol_pb.performative_pmt.content_dict_int_str
+ content_dict_int_str_dict = dict(content_dict_int_str)
+ performative_content["content_dict_int_str"] = content_dict_int_str_dict
content_dict_bool_bytes = (
t_protocol_pb.performative_pmt.content_dict_bool_bytes
)
@@ -367,11 +370,43 @@ def decode(obj: bytes) -> Message:
performative_content[
"content_dict_bool_bytes"
] = content_dict_bool_bytes_dict
+ content_dict_bool_int = t_protocol_pb.performative_pmt.content_dict_bool_int
+ content_dict_bool_int_dict = dict(content_dict_bool_int)
+ performative_content["content_dict_bool_int"] = content_dict_bool_int_dict
+ content_dict_bool_float = (
+ t_protocol_pb.performative_pmt.content_dict_bool_float
+ )
+ content_dict_bool_float_dict = dict(content_dict_bool_float)
+ performative_content[
+ "content_dict_bool_float"
+ ] = content_dict_bool_float_dict
+ content_dict_bool_bool = (
+ t_protocol_pb.performative_pmt.content_dict_bool_bool
+ )
+ content_dict_bool_bool_dict = dict(content_dict_bool_bool)
+ performative_content["content_dict_bool_bool"] = content_dict_bool_bool_dict
+ content_dict_bool_str = t_protocol_pb.performative_pmt.content_dict_bool_str
+ content_dict_bool_str_dict = dict(content_dict_bool_str)
+ performative_content["content_dict_bool_str"] = content_dict_bool_str_dict
+ content_dict_str_bytes = (
+ t_protocol_pb.performative_pmt.content_dict_str_bytes
+ )
+ content_dict_str_bytes_dict = dict(content_dict_str_bytes)
+ performative_content["content_dict_str_bytes"] = content_dict_str_bytes_dict
+ content_dict_str_int = t_protocol_pb.performative_pmt.content_dict_str_int
+ content_dict_str_int_dict = dict(content_dict_str_int)
+ performative_content["content_dict_str_int"] = content_dict_str_int_dict
content_dict_str_float = (
t_protocol_pb.performative_pmt.content_dict_str_float
)
content_dict_str_float_dict = dict(content_dict_str_float)
performative_content["content_dict_str_float"] = content_dict_str_float_dict
+ content_dict_str_bool = t_protocol_pb.performative_pmt.content_dict_str_bool
+ content_dict_str_bool_dict = dict(content_dict_str_bool)
+ performative_content["content_dict_str_bool"] = content_dict_str_bool_dict
+ content_dict_str_str = t_protocol_pb.performative_pmt.content_dict_str_str
+ content_dict_str_str_dict = dict(content_dict_str_str)
+ performative_content["content_dict_str_str"] = content_dict_str_str_dict
elif performative_id == TProtocolMessage.Performative.PERFORMATIVE_MT:
if t_protocol_pb.performative_mt.content_union_1_type_DataModel_is_set:
pb2_content_union_1_type_DataModel = (
@@ -464,12 +499,10 @@ def decode(obj: bytes) -> Message:
if t_protocol_pb.performative_o.content_o_bool_is_set:
content_o_bool = t_protocol_pb.performative_o.content_o_bool
performative_content["content_o_bool"] = content_o_bool
- if t_protocol_pb.performative_o.content_o_set_float_is_set:
- content_o_set_float = t_protocol_pb.performative_o.content_o_set_float
- content_o_set_float_frozenset = frozenset(content_o_set_float)
- performative_content[
- "content_o_set_float"
- ] = content_o_set_float_frozenset
+ if t_protocol_pb.performative_o.content_o_set_int_is_set:
+ content_o_set_int = t_protocol_pb.performative_o.content_o_set_int
+ content_o_set_int_frozenset = frozenset(content_o_set_int)
+ performative_content["content_o_set_int"] = content_o_set_int_frozenset
if t_protocol_pb.performative_o.content_o_list_bytes_is_set:
content_o_list_bytes = t_protocol_pb.performative_o.content_o_list_bytes
content_o_list_bytes_tuple = tuple(content_o_list_bytes)
@@ -484,31 +517,6 @@ def decode(obj: bytes) -> Message:
performative_content[
"content_o_dict_str_int"
] = content_o_dict_str_int_dict
- if t_protocol_pb.performative_o.content_o_union_type_str_is_set:
- content_o_union = t_protocol_pb.performative_o.content_o_union_type_str
- performative_content["content_o_union"] = content_o_union
- if t_protocol_pb.performative_o.content_o_union_type_dict_of_str_int_is_set:
- content_o_union = t_protocol_pb.performative_o.content_o_union
- content_o_union_dict = dict(content_o_union)
- performative_content["content_o_union"] = content_o_union_dict
- if t_protocol_pb.performative_o.content_o_union_type_set_of_int_is_set:
- content_o_union = t_protocol_pb.performative_o.content_o_union
- content_o_union_frozenset = frozenset(content_o_union)
- performative_content["content_o_union"] = content_o_union_frozenset
- if t_protocol_pb.performative_o.content_o_union_type_set_of_bytes_is_set:
- content_o_union = t_protocol_pb.performative_o.content_o_union
- content_o_union_frozenset = frozenset(content_o_union)
- performative_content["content_o_union"] = content_o_union_frozenset
- if t_protocol_pb.performative_o.content_o_union_type_list_of_bool_is_set:
- content_o_union = t_protocol_pb.performative_o.content_o_union
- content_o_union_tuple = tuple(content_o_union)
- performative_content["content_o_union"] = content_o_union_tuple
- if (
- t_protocol_pb.performative_o.content_o_union_type_dict_of_str_float_is_set
- ):
- content_o_union = t_protocol_pb.performative_o.content_o_union
- content_o_union_dict = dict(content_o_union)
- performative_content["content_o_union"] = content_o_union_dict
elif (
performative_id == TProtocolMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
):
diff --git a/tests/data/generator/t_protocol/t_protocol.proto b/tests/data/generator/t_protocol/t_protocol.proto
index e14a0309c1..b408c295d7 100644
--- a/tests/data/generator/t_protocol/t_protocol.proto
+++ b/tests/data/generator/t_protocol/t_protocol.proto
@@ -44,8 +44,21 @@ message TProtocolMessage{
}
message Performative_Pmt_Performative{
- map content_dict_bool_bytes = 1;
- map content_dict_str_float = 2;
+ map content_dict_int_bytes = 1;
+ map content_dict_int_int = 2;
+ map content_dict_int_float = 3;
+ map content_dict_int_bool = 4;
+ map content_dict_int_str = 5;
+ map content_dict_bool_bytes = 6;
+ map content_dict_bool_int = 7;
+ map content_dict_bool_float = 8;
+ map content_dict_bool_bool = 9;
+ map content_dict_bool_str = 10;
+ map content_dict_str_bytes = 11;
+ map content_dict_str_int = 12;
+ map content_dict_str_float = 13;
+ map content_dict_str_bool = 14;
+ map content_dict_str_str = 15;
}
message Performative_Mt_Performative{
@@ -74,19 +87,12 @@ message TProtocolMessage{
bool content_o_ct_is_set = 2;
bool content_o_bool = 3;
bool content_o_bool_is_set = 4;
- repeated float content_o_set_float = 5;
- bool content_o_set_float_is_set = 6;
+ repeated int32 content_o_set_int = 5;
+ bool content_o_set_int_is_set = 6;
repeated bytes content_o_list_bytes = 7;
bool content_o_list_bytes_is_set = 8;
map content_o_dict_str_int = 9;
bool content_o_dict_str_int_is_set = 10;
- string content_o_union_type_str = 11;
- map content_o_union_type_dict_of_str_int = 12;
- repeated int32 content_o_union_type_set_of_int = 13;
- repeated bytes content_o_union_type_set_of_bytes = 14;
- repeated bool content_o_union_type_list_of_bool = 15;
- map content_o_union_type_dict_of_str_float = 16;
- bool content_o_union_is_set = 17;
}
message Performative_Empty_Contents_Performative{}
diff --git a/tests/data/generator/t_protocol/t_protocol_pb2.py b/tests/data/generator/t_protocol/t_protocol_pb2.py
index 8cbd680e3d..c021c11aa3 100644
--- a/tests/data/generator/t_protocol/t_protocol_pb2.py
+++ b/tests/data/generator/t_protocol/t_protocol_pb2.py
@@ -1,9 +1,7 @@
+# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: t_protocol.proto
-import sys
-
-_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode("latin1"))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
@@ -19,9 +17,7 @@
package="fetch.aea.TProtocol",
syntax="proto3",
serialized_options=None,
- serialized_pb=_b(
- '\n\x10t_protocol.proto\x12\x13\x66\x65tch.aea.TProtocol"\xdb%\n\x10TProtocolMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12]\n\x0fperformative_ct\x18\x05 \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Ct_PerformativeH\x00\x12u\n\x1bperformative_empty_contents\x18\x06 \x01(\x0b\x32N.fetch.aea.TProtocol.TProtocolMessage.Performative_Empty_Contents_PerformativeH\x00\x12]\n\x0fperformative_mt\x18\x07 \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_PerformativeH\x00\x12[\n\x0eperformative_o\x18\x08 \x01(\x0b\x32\x41.fetch.aea.TProtocol.TProtocolMessage.Performative_O_PerformativeH\x00\x12_\n\x10performative_pct\x18\t \x01(\x0b\x32\x43.fetch.aea.TProtocol.TProtocolMessage.Performative_Pct_PerformativeH\x00\x12_\n\x10performative_pmt\x18\n \x01(\x0b\x32\x43.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_PerformativeH\x00\x12]\n\x0fperformative_pt\x18\x0b \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Pt_PerformativeH\x00\x1a\x9c\x02\n\tDataModel\x12\x13\n\x0b\x62ytes_field\x18\x01 \x01(\x0c\x12\x11\n\tint_field\x18\x02 \x01(\x05\x12\x13\n\x0b\x66loat_field\x18\x03 \x01(\x02\x12\x12\n\nbool_field\x18\x04 \x01(\x08\x12\x11\n\tstr_field\x18\x05 \x01(\t\x12\x11\n\tset_field\x18\x06 \x03(\x05\x12\x12\n\nlist_field\x18\x07 \x03(\t\x12R\n\ndict_field\x18\x08 \x03(\x0b\x32>.fetch.aea.TProtocol.TProtocolMessage.DataModel.DictFieldEntry\x1a\x30\n\x0e\x44ictFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x63\n\x1cPerformative_Ct_Performative\x12\x43\n\ncontent_ct\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x1a\x8c\x01\n\x1cPerformative_Pt_Performative\x12\x15\n\rcontent_bytes\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontent_int\x18\x02 \x01(\x05\x12\x15\n\rcontent_float\x18\x03 \x01(\x02\x12\x14\n\x0c\x63ontent_bool\x18\x04 \x01(\x08\x12\x13\n\x0b\x63ontent_str\x18\x05 \x01(\t\x1a\xa8\x02\n\x1dPerformative_Pct_Performative\x12\x19\n\x11\x63ontent_set_bytes\x18\x01 \x03(\x0c\x12\x17\n\x0f\x63ontent_set_int\x18\x02 \x03(\x05\x12\x19\n\x11\x63ontent_set_float\x18\x03 \x03(\x02\x12\x18\n\x10\x63ontent_set_bool\x18\x04 \x03(\x08\x12\x17\n\x0f\x63ontent_set_str\x18\x05 \x03(\t\x12\x1a\n\x12\x63ontent_list_bytes\x18\x06 \x03(\x0c\x12\x18\n\x10\x63ontent_list_int\x18\x07 \x03(\x05\x12\x1a\n\x12\x63ontent_list_float\x18\x08 \x03(\x02\x12\x19\n\x11\x63ontent_list_bool\x18\t \x03(\x08\x12\x18\n\x10\x63ontent_list_str\x18\n \x03(\t\x1a\x96\x03\n\x1dPerformative_Pmt_Performative\x12~\n\x17\x63ontent_dict_bool_bytes\x18\x01 \x03(\x0b\x32].fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\x12|\n\x16\x63ontent_dict_str_float\x18\x02 \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\x1a;\n\x19\x43ontentDictBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a:\n\x18\x43ontentDictStrFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\xf9\x0b\n\x1cPerformative_Mt_Performative\x12W\n\x1e\x63ontent_union_1_type_DataModel\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x12"\n\x1a\x63ontent_union_1_type_bytes\x18\x02 \x01(\x0c\x12 \n\x18\x63ontent_union_1_type_int\x18\x03 \x01(\x05\x12"\n\x1a\x63ontent_union_1_type_float\x18\x04 \x01(\x02\x12!\n\x19\x63ontent_union_1_type_bool\x18\x05 \x01(\x08\x12 \n\x18\x63ontent_union_1_type_str\x18\x06 \x01(\t\x12\'\n\x1f\x63ontent_union_1_type_set_of_int\x18\x07 \x03(\x05\x12)\n!content_union_1_type_list_of_bool\x18\x08 \x03(\x08\x12\x93\x01\n$content_union_1_type_dict_of_str_int\x18\t \x03(\x0b\x32\x65.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\x12)\n!content_union_2_type_set_of_bytes\x18\n \x03(\x0c\x12\'\n\x1f\x63ontent_union_2_type_set_of_int\x18\x0b \x03(\x05\x12\'\n\x1f\x63ontent_union_2_type_set_of_str\x18\x0c \x03(\t\x12*\n"content_union_2_type_list_of_float\x18\r \x03(\x02\x12)\n!content_union_2_type_list_of_bool\x18\x0e \x03(\x08\x12*\n"content_union_2_type_list_of_bytes\x18\x0f \x03(\x0c\x12\x93\x01\n$content_union_2_type_dict_of_str_int\x18\x10 \x03(\x0b\x32\x65.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\x12\x97\x01\n&content_union_2_type_dict_of_int_float\x18\x11 \x03(\x0b\x32g.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\x12\x99\x01\n\'content_union_2_type_dict_of_bool_bytes\x18\x12 \x03(\x0b\x32h.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\x1a\x44\n"ContentUnion1TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x44\n"ContentUnion2TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x46\n$ContentUnion2TypeDictOfIntFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1aG\n%ContentUnion2TypeDictOfBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x96\t\n\x1bPerformative_O_Performative\x12\x45\n\x0c\x63ontent_o_ct\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x12\x1b\n\x13\x63ontent_o_ct_is_set\x18\x02 \x01(\x08\x12\x16\n\x0e\x63ontent_o_bool\x18\x03 \x01(\x08\x12\x1d\n\x15\x63ontent_o_bool_is_set\x18\x04 \x01(\x08\x12\x1b\n\x13\x63ontent_o_set_float\x18\x05 \x03(\x02\x12"\n\x1a\x63ontent_o_set_float_is_set\x18\x06 \x01(\x08\x12\x1c\n\x14\x63ontent_o_list_bytes\x18\x07 \x03(\x0c\x12#\n\x1b\x63ontent_o_list_bytes_is_set\x18\x08 \x01(\x08\x12y\n\x16\x63ontent_o_dict_str_int\x18\t \x03(\x0b\x32Y.fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry\x12%\n\x1d\x63ontent_o_dict_str_int_is_set\x18\n \x01(\x08\x12 \n\x18\x63ontent_o_union_type_str\x18\x0b \x01(\t\x12\x92\x01\n$content_o_union_type_dict_of_str_int\x18\x0c \x03(\x0b\x32\x64.fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry\x12\'\n\x1f\x63ontent_o_union_type_set_of_int\x18\r \x03(\x05\x12)\n!content_o_union_type_set_of_bytes\x18\x0e \x03(\x0c\x12)\n!content_o_union_type_list_of_bool\x18\x0f \x03(\x08\x12\x96\x01\n&content_o_union_type_dict_of_str_float\x18\x10 \x03(\x0b\x32\x66.fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry\x12\x1e\n\x16\x63ontent_o_union_is_set\x18\x11 \x01(\x08\x1a\x39\n\x17\x43ontentODictStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x44\n"ContentOUnionTypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x46\n$ContentOUnionTypeDictOfStrFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a*\n(Performative_Empty_Contents_PerformativeB\x0e\n\x0cperformativeb\x06proto3'
- ),
+ serialized_pb=b'\n\x10t_protocol.proto\x12\x13\x66\x65tch.aea.TProtocol"\xab\x33\n\x10TProtocolMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12]\n\x0fperformative_ct\x18\x05 \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Ct_PerformativeH\x00\x12u\n\x1bperformative_empty_contents\x18\x06 \x01(\x0b\x32N.fetch.aea.TProtocol.TProtocolMessage.Performative_Empty_Contents_PerformativeH\x00\x12]\n\x0fperformative_mt\x18\x07 \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_PerformativeH\x00\x12[\n\x0eperformative_o\x18\x08 \x01(\x0b\x32\x41.fetch.aea.TProtocol.TProtocolMessage.Performative_O_PerformativeH\x00\x12_\n\x10performative_pct\x18\t \x01(\x0b\x32\x43.fetch.aea.TProtocol.TProtocolMessage.Performative_Pct_PerformativeH\x00\x12_\n\x10performative_pmt\x18\n \x01(\x0b\x32\x43.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_PerformativeH\x00\x12]\n\x0fperformative_pt\x18\x0b \x01(\x0b\x32\x42.fetch.aea.TProtocol.TProtocolMessage.Performative_Pt_PerformativeH\x00\x1a\x9c\x02\n\tDataModel\x12\x13\n\x0b\x62ytes_field\x18\x01 \x01(\x0c\x12\x11\n\tint_field\x18\x02 \x01(\x05\x12\x13\n\x0b\x66loat_field\x18\x03 \x01(\x02\x12\x12\n\nbool_field\x18\x04 \x01(\x08\x12\x11\n\tstr_field\x18\x05 \x01(\t\x12\x11\n\tset_field\x18\x06 \x03(\x05\x12\x12\n\nlist_field\x18\x07 \x03(\t\x12R\n\ndict_field\x18\x08 \x03(\x0b\x32>.fetch.aea.TProtocol.TProtocolMessage.DataModel.DictFieldEntry\x1a\x30\n\x0e\x44ictFieldEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x63\n\x1cPerformative_Ct_Performative\x12\x43\n\ncontent_ct\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x1a\x8c\x01\n\x1cPerformative_Pt_Performative\x12\x15\n\rcontent_bytes\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontent_int\x18\x02 \x01(\x05\x12\x15\n\rcontent_float\x18\x03 \x01(\x02\x12\x14\n\x0c\x63ontent_bool\x18\x04 \x01(\x08\x12\x13\n\x0b\x63ontent_str\x18\x05 \x01(\t\x1a\xa8\x02\n\x1dPerformative_Pct_Performative\x12\x19\n\x11\x63ontent_set_bytes\x18\x01 \x03(\x0c\x12\x17\n\x0f\x63ontent_set_int\x18\x02 \x03(\x05\x12\x19\n\x11\x63ontent_set_float\x18\x03 \x03(\x02\x12\x18\n\x10\x63ontent_set_bool\x18\x04 \x03(\x08\x12\x17\n\x0f\x63ontent_set_str\x18\x05 \x03(\t\x12\x1a\n\x12\x63ontent_list_bytes\x18\x06 \x03(\x0c\x12\x18\n\x10\x63ontent_list_int\x18\x07 \x03(\x05\x12\x1a\n\x12\x63ontent_list_float\x18\x08 \x03(\x02\x12\x19\n\x11\x63ontent_list_bool\x18\t \x03(\x08\x12\x18\n\x10\x63ontent_list_str\x18\n \x03(\t\x1a\xe7\x15\n\x1dPerformative_Pmt_Performative\x12|\n\x16\x63ontent_dict_int_bytes\x18\x01 \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\x12x\n\x14\x63ontent_dict_int_int\x18\x02 \x03(\x0b\x32Z.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\x12|\n\x16\x63ontent_dict_int_float\x18\x03 \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\x12z\n\x15\x63ontent_dict_int_bool\x18\x04 \x03(\x0b\x32[.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\x12x\n\x14\x63ontent_dict_int_str\x18\x05 \x03(\x0b\x32Z.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\x12~\n\x17\x63ontent_dict_bool_bytes\x18\x06 \x03(\x0b\x32].fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\x12z\n\x15\x63ontent_dict_bool_int\x18\x07 \x03(\x0b\x32[.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\x12~\n\x17\x63ontent_dict_bool_float\x18\x08 \x03(\x0b\x32].fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\x12|\n\x16\x63ontent_dict_bool_bool\x18\t \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\x12z\n\x15\x63ontent_dict_bool_str\x18\n \x03(\x0b\x32[.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\x12|\n\x16\x63ontent_dict_str_bytes\x18\x0b \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\x12x\n\x14\x63ontent_dict_str_int\x18\x0c \x03(\x0b\x32Z.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\x12|\n\x16\x63ontent_dict_str_float\x18\r \x03(\x0b\x32\\.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\x12z\n\x15\x63ontent_dict_str_bool\x18\x0e \x03(\x0b\x32[.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\x12x\n\x14\x63ontent_dict_str_str\x18\x0f \x03(\x0b\x32Z.fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\x1a:\n\x18\x43ontentDictIntBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictIntIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a:\n\x18\x43ontentDictIntFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictIntBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictIntStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a;\n\x19\x43ontentDictBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictBoolIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a;\n\x19\x43ontentDictBoolFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a:\n\x18\x43ontentDictBoolBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictBoolStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18\x43ontentDictStrBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a:\n\x18\x43ontentDictStrFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictStrBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictStrStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xf9\x0b\n\x1cPerformative_Mt_Performative\x12W\n\x1e\x63ontent_union_1_type_DataModel\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x12"\n\x1a\x63ontent_union_1_type_bytes\x18\x02 \x01(\x0c\x12 \n\x18\x63ontent_union_1_type_int\x18\x03 \x01(\x05\x12"\n\x1a\x63ontent_union_1_type_float\x18\x04 \x01(\x02\x12!\n\x19\x63ontent_union_1_type_bool\x18\x05 \x01(\x08\x12 \n\x18\x63ontent_union_1_type_str\x18\x06 \x01(\t\x12\'\n\x1f\x63ontent_union_1_type_set_of_int\x18\x07 \x03(\x05\x12)\n!content_union_1_type_list_of_bool\x18\x08 \x03(\x08\x12\x93\x01\n$content_union_1_type_dict_of_str_int\x18\t \x03(\x0b\x32\x65.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\x12)\n!content_union_2_type_set_of_bytes\x18\n \x03(\x0c\x12\'\n\x1f\x63ontent_union_2_type_set_of_int\x18\x0b \x03(\x05\x12\'\n\x1f\x63ontent_union_2_type_set_of_str\x18\x0c \x03(\t\x12*\n"content_union_2_type_list_of_float\x18\r \x03(\x02\x12)\n!content_union_2_type_list_of_bool\x18\x0e \x03(\x08\x12*\n"content_union_2_type_list_of_bytes\x18\x0f \x03(\x0c\x12\x93\x01\n$content_union_2_type_dict_of_str_int\x18\x10 \x03(\x0b\x32\x65.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\x12\x97\x01\n&content_union_2_type_dict_of_int_float\x18\x11 \x03(\x0b\x32g.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\x12\x99\x01\n\'content_union_2_type_dict_of_bool_bytes\x18\x12 \x03(\x0b\x32h.fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\x1a\x44\n"ContentUnion1TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x44\n"ContentUnion2TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x46\n$ContentUnion2TypeDictOfIntFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1aG\n%ContentUnion2TypeDictOfBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x95\x04\n\x1bPerformative_O_Performative\x12\x45\n\x0c\x63ontent_o_ct\x18\x01 \x01(\x0b\x32/.fetch.aea.TProtocol.TProtocolMessage.DataModel\x12\x1b\n\x13\x63ontent_o_ct_is_set\x18\x02 \x01(\x08\x12\x16\n\x0e\x63ontent_o_bool\x18\x03 \x01(\x08\x12\x1d\n\x15\x63ontent_o_bool_is_set\x18\x04 \x01(\x08\x12\x19\n\x11\x63ontent_o_set_int\x18\x05 \x03(\x05\x12 \n\x18\x63ontent_o_set_int_is_set\x18\x06 \x01(\x08\x12\x1c\n\x14\x63ontent_o_list_bytes\x18\x07 \x03(\x0c\x12#\n\x1b\x63ontent_o_list_bytes_is_set\x18\x08 \x01(\x08\x12y\n\x16\x63ontent_o_dict_str_int\x18\t \x03(\x0b\x32Y.fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry\x12%\n\x1d\x63ontent_o_dict_str_int_is_set\x18\n \x01(\x08\x1a\x39\n\x17\x43ontentODictStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a*\n(Performative_Empty_Contents_PerformativeB\x0e\n\x0cperformativeb\x06proto3',
)
@@ -72,7 +68,7 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
@@ -97,7 +93,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b(""),
+ default_value=b"",
message_type=None,
enum_type=None,
containing_type=None,
@@ -169,7 +165,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -299,7 +295,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b(""),
+ default_value=b"",
message_type=None,
enum_type=None,
containing_type=None,
@@ -371,7 +367,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -593,23 +589,23 @@
serialized_end=1691,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY = _descriptor.Descriptor(
- name="ContentDictBoolBytesEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictIntBytesEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry.key",
index=0,
number=1,
- type=8,
- cpp_type=7,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=False,
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -620,14 +616,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry.value",
index=1,
number=2,
type=12,
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b(""),
+ default_value=b"",
message_type=None,
enum_type=None,
containing_type=None,
@@ -640,32 +636,32 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1981,
- serialized_end=2040,
+ serialized_start=3597,
+ serialized_end=3655,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY = _descriptor.Descriptor(
- name="ContentDictStrFloatEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY = _descriptor.Descriptor(
+ name="ContentDictIntIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry.key",
index=0,
number=1,
- type=9,
- cpp_type=9,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -676,14 +672,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry.value",
index=1,
number=2,
- type=2,
- cpp_type=6,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=float(0),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -696,32 +692,32 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=2042,
- serialized_end=2100,
+ serialized_start=3657,
+ serialized_end=3713,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE = _descriptor.Descriptor(
- name="Performative_Pmt_Performative",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictIntFloatEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name="content_dict_bool_bytes",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_bytes",
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry.key",
index=0,
number=1,
- type=11,
- cpp_type=10,
- label=3,
+ type=5,
+ cpp_type=1,
+ label=1,
has_default_value=False,
- default_value=[],
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -731,15 +727,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_dict_str_float",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_float",
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry.value",
index=1,
number=2,
- type=11,
- cpp_type=10,
- label=3,
+ type=2,
+ cpp_type=6,
+ label=1,
has_default_value=False,
- default_value=[],
+ default_value=float(0),
message_type=None,
enum_type=None,
containing_type=None,
@@ -750,37 +746,34 @@
),
],
extensions=[],
- nested_types=[
- _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
- _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
- ],
+ nested_types=[],
enum_types=[],
- serialized_options=None,
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=1694,
- serialized_end=2100,
+ serialized_start=3715,
+ serialized_end=3773,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
- name="ContentUnion1TypeDictOfStrIntEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictIntBoolEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry.key",
index=0,
number=1,
- type=9,
- cpp_type=9,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -791,14 +784,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry.value",
index=1,
number=2,
- type=5,
- cpp_type=1,
+ type=8,
+ cpp_type=7,
label=1,
has_default_value=False,
- default_value=0,
+ default_value=False,
message_type=None,
enum_type=None,
containing_type=None,
@@ -811,32 +804,32 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3349,
- serialized_end=3417,
+ serialized_start=3775,
+ serialized_end=3832,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
- name="ContentUnion2TypeDictOfStrIntEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictIntStrEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry.key",
index=0,
number=1,
- type=9,
- cpp_type=9,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -847,14 +840,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry.value",
index=1,
number=2,
- type=5,
- cpp_type=1,
+ type=9,
+ cpp_type=9,
label=1,
has_default_value=False,
- default_value=0,
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -867,32 +860,32 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3419,
- serialized_end=3487,
+ serialized_start=3834,
+ serialized_end=3890,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY = _descriptor.Descriptor(
- name="ContentUnion2TypeDictOfIntFloatEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolBytesEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.key",
index=0,
number=1,
- type=5,
- cpp_type=1,
+ type=8,
+ cpp_type=7,
label=1,
has_default_value=False,
- default_value=0,
+ default_value=False,
message_type=None,
enum_type=None,
containing_type=None,
@@ -903,14 +896,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.value",
index=1,
number=2,
- type=2,
- cpp_type=6,
+ type=12,
+ cpp_type=9,
label=1,
has_default_value=False,
- default_value=float(0),
+ default_value=b"",
message_type=None,
enum_type=None,
containing_type=None,
@@ -923,25 +916,25 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3489,
- serialized_end=3559,
+ serialized_start=3892,
+ serialized_end=3951,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY = _descriptor.Descriptor(
- name="ContentUnion2TypeDictOfBoolBytesEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry.key",
index=0,
number=1,
type=8,
@@ -959,14 +952,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry.value",
index=1,
number=2,
- type=12,
- cpp_type=9,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=_b(""),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -979,32 +972,32 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3561,
- serialized_end=3632,
+ serialized_start=3953,
+ serialized_end=4010,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE = _descriptor.Descriptor(
- name="Performative_Mt_Performative",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative",
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolFloatEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name="content_union_1_type_DataModel",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_DataModel",
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry.key",
index=0,
number=1,
- type=11,
- cpp_type=10,
+ type=8,
+ cpp_type=7,
label=1,
has_default_value=False,
- default_value=None,
+ default_value=False,
message_type=None,
enum_type=None,
containing_type=None,
@@ -1014,15 +1007,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_union_1_type_bytes",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_bytes",
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry.value",
index=1,
number=2,
- type=12,
- cpp_type=9,
+ type=2,
+ cpp_type=6,
label=1,
has_default_value=False,
- default_value=_b(""),
+ default_value=float(0),
message_type=None,
enum_type=None,
containing_type=None,
@@ -1031,16 +1024,36 @@
serialized_options=None,
file=DESCRIPTOR,
),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4012,
+ serialized_end=4071,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolBoolEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
_descriptor.FieldDescriptor(
- name="content_union_1_type_int",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_int",
- index=2,
- number=3,
- type=5,
- cpp_type=1,
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
label=1,
has_default_value=False,
- default_value=0,
+ default_value=False,
message_type=None,
enum_type=None,
containing_type=None,
@@ -1050,15 +1063,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_union_1_type_float",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_float",
- index=3,
- number=4,
- type=2,
- cpp_type=6,
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry.value",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
label=1,
has_default_value=False,
- default_value=float(0),
+ default_value=False,
message_type=None,
enum_type=None,
containing_type=None,
@@ -1067,11 +1080,31 @@
serialized_options=None,
file=DESCRIPTOR,
),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4073,
+ serialized_end=4131,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolStrEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
_descriptor.FieldDescriptor(
- name="content_union_1_type_bool",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_bool",
- index=4,
- number=5,
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry.key",
+ index=0,
+ number=1,
type=8,
cpp_type=7,
label=1,
@@ -1086,15 +1119,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_union_1_type_str",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_str",
- index=5,
- number=6,
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry.value",
+ index=1,
+ number=2,
type=9,
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -1103,16 +1136,36 @@
serialized_options=None,
file=DESCRIPTOR,
),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4133,
+ serialized_end=4190,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictStrBytesEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
_descriptor.FieldDescriptor(
- name="content_union_1_type_set_of_int",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_set_of_int",
- index=6,
- number=7,
- type=5,
- cpp_type=1,
- label=3,
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
has_default_value=False,
- default_value=[],
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -1122,15 +1175,15 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_union_1_type_list_of_bool",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_list_of_bool",
- index=7,
- number=8,
- type=8,
- cpp_type=7,
- label=3,
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
has_default_value=False,
- default_value=[],
+ default_value=b"",
message_type=None,
enum_type=None,
containing_type=None,
@@ -1139,10 +1192,928 @@
serialized_options=None,
file=DESCRIPTOR,
),
- _descriptor.FieldDescriptor(
- name="content_union_1_type_dict_of_str_int",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_dict_of_str_int",
- index=8,
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4192,
+ serialized_end=4250,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentDictStrIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4252,
+ serialized_end=4308,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictStrFloatEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4310,
+ serialized_end=4368,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictStrBoolEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry.value",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4370,
+ serialized_end=4427,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictStrStrEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry.value",
+ index=1,
+ number=2,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4429,
+ serialized_end=4485,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Pmt_Performative",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_bytes",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_int_bytes",
+ index=0,
+ number=1,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_int_int",
+ index=1,
+ number=2,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_float",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_int_float",
+ index=2,
+ number=3,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_bool",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_int_bool",
+ index=3,
+ number=4,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_str",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_int_str",
+ index=4,
+ number=5,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_bytes",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_bytes",
+ index=5,
+ number=6,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_int",
+ index=6,
+ number=7,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_float",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_float",
+ index=7,
+ number=8,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_bool",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_bool",
+ index=8,
+ number=9,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_str",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_bool_str",
+ index=9,
+ number=10,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_bytes",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_bytes",
+ index=10,
+ number=11,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_int",
+ index=11,
+ number=12,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_float",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_float",
+ index=12,
+ number=13,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_bool",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_bool",
+ index=13,
+ number=14,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_str",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.content_dict_str_str",
+ index=14,
+ number=15,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,
+ ],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=1694,
+ serialized_end=4485,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentUnion1TypeDictOfStrIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5734,
+ serialized_end=5802,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfStrIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5804,
+ serialized_end=5872,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfIntFloatEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5874,
+ serialized_end=5944,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfBoolBytesEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5946,
+ serialized_end=6017,
+)
+
+_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Mt_Performative",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_DataModel",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_DataModel",
+ index=0,
+ number=1,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_bytes",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_bytes",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_int",
+ index=2,
+ number=3,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_float",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_float",
+ index=3,
+ number=4,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_bool",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_bool",
+ index=4,
+ number=5,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_str",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_str",
+ index=5,
+ number=6,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_set_of_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_set_of_int",
+ index=6,
+ number=7,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_list_of_bool",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_list_of_bool",
+ index=7,
+ number=8,
+ type=8,
+ cpp_type=7,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_dict_of_str_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.content_union_1_type_dict_of_str_int",
+ index=8,
number=9,
type=11,
cpp_type=10,
@@ -1324,148 +2295,36 @@
nested_types=[
_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,
_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,
- _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
- _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
- ],
- enum_types=[],
- serialized_options=None,
- is_extendable=False,
- syntax="proto3",
- extension_ranges=[],
- oneofs=[],
- serialized_start=2103,
- serialized_end=3632,
-)
-
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY = _descriptor.Descriptor(
- name="ContentODictStrIntEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry",
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry.key",
- index=0,
- number=1,
- type=9,
- cpp_type=9,
- label=1,
- has_default_value=False,
- default_value=_b("").decode("utf-8"),
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry.value",
- index=1,
- number=2,
- type=5,
- cpp_type=1,
- label=1,
- has_default_value=False,
- default_value=0,
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- ],
- extensions=[],
- nested_types=[],
- enum_types=[],
- serialized_options=_b("8\001"),
- is_extendable=False,
- syntax="proto3",
- extension_ranges=[],
- oneofs=[],
- serialized_start=4610,
- serialized_end=4667,
-)
-
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
- name="ContentOUnionTypeDictOfStrIntEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry",
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry.key",
- index=0,
- number=1,
- type=9,
- cpp_type=9,
- label=1,
- has_default_value=False,
- default_value=_b("").decode("utf-8"),
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry.value",
- index=1,
- number=2,
- type=5,
- cpp_type=1,
- label=1,
- has_default_value=False,
- default_value=0,
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
+ _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
+ _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
],
- extensions=[],
- nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=None,
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=4669,
- serialized_end=4737,
+ serialized_start=4488,
+ serialized_end=6017,
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY = _descriptor.Descriptor(
- name="ContentOUnionTypeDictOfStrFloatEntry",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry",
+_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentODictStrIntEntry",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry",
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name="key",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry.key",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry.key",
index=0,
number=1,
type=9,
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -1476,14 +2335,14 @@
),
_descriptor.FieldDescriptor(
name="value",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry.value",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry.value",
index=1,
number=2,
- type=2,
- cpp_type=6,
+ type=5,
+ cpp_type=1,
label=1,
has_default_value=False,
- default_value=float(0),
+ default_value=0,
message_type=None,
enum_type=None,
containing_type=None,
@@ -1496,13 +2355,13 @@
extensions=[],
nested_types=[],
enum_types=[],
- serialized_options=_b("8\001"),
+ serialized_options=b"8\001",
is_extendable=False,
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=4739,
- serialized_end=4809,
+ serialized_start=6496,
+ serialized_end=6553,
)
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE = _descriptor.Descriptor(
@@ -1585,12 +2444,12 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_o_set_float",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_set_float",
+ name="content_o_set_int",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_set_int",
index=4,
number=5,
- type=2,
- cpp_type=6,
+ type=5,
+ cpp_type=1,
label=3,
has_default_value=False,
default_value=[],
@@ -1603,8 +2462,8 @@
file=DESCRIPTOR,
),
_descriptor.FieldDescriptor(
- name="content_o_set_float_is_set",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_set_float_is_set",
+ name="content_o_set_int_is_set",
+ full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_set_int_is_set",
index=5,
number=6,
type=8,
@@ -1692,138 +2551,10 @@
serialized_options=None,
file=DESCRIPTOR,
),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_str",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_str",
- index=10,
- number=11,
- type=9,
- cpp_type=9,
- label=1,
- has_default_value=False,
- default_value=_b("").decode("utf-8"),
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_dict_of_str_int",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_dict_of_str_int",
- index=11,
- number=12,
- type=11,
- cpp_type=10,
- label=3,
- has_default_value=False,
- default_value=[],
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_set_of_int",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_set_of_int",
- index=12,
- number=13,
- type=5,
- cpp_type=1,
- label=3,
- has_default_value=False,
- default_value=[],
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_set_of_bytes",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_set_of_bytes",
- index=13,
- number=14,
- type=12,
- cpp_type=9,
- label=3,
- has_default_value=False,
- default_value=[],
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_list_of_bool",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_list_of_bool",
- index=14,
- number=15,
- type=8,
- cpp_type=7,
- label=3,
- has_default_value=False,
- default_value=[],
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_type_dict_of_str_float",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_type_dict_of_str_float",
- index=15,
- number=16,
- type=11,
- cpp_type=10,
- label=3,
- has_default_value=False,
- default_value=[],
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
- _descriptor.FieldDescriptor(
- name="content_o_union_is_set",
- full_name="fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.content_o_union_is_set",
- index=16,
- number=17,
- type=8,
- cpp_type=7,
- label=1,
- has_default_value=False,
- default_value=False,
- message_type=None,
- enum_type=None,
- containing_type=None,
- is_extension=False,
- extension_scope=None,
- serialized_options=None,
- file=DESCRIPTOR,
- ),
],
extensions=[],
nested_types=[
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY,
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY,
],
enum_types=[],
serialized_options=None,
@@ -1831,8 +2562,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=3635,
- serialized_end=4809,
+ serialized_start=6020,
+ serialized_end=6553,
)
_TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE = _descriptor.Descriptor(
@@ -1850,8 +2581,8 @@
syntax="proto3",
extension_ranges=[],
oneofs=[],
- serialized_start=4811,
- serialized_end=4853,
+ serialized_start=6555,
+ serialized_end=6597,
)
_TPROTOCOLMESSAGE = _descriptor.Descriptor(
@@ -1888,7 +2619,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -1906,7 +2637,7 @@
cpp_type=9,
label=1,
has_default_value=False,
- default_value=_b("").decode("utf-8"),
+ default_value=b"".decode("utf-8"),
message_type=None,
enum_type=None,
containing_type=None,
@@ -2086,7 +2817,7 @@
),
],
serialized_start=42,
- serialized_end=4869,
+ serialized_end=6613,
)
_TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY.containing_type = _TPROTOCOLMESSAGE_DATAMODEL
@@ -2100,22 +2831,110 @@
_TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE.containing_type = _TPROTOCOLMESSAGE
_TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE.containing_type = _TPROTOCOLMESSAGE
_TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE.containing_type = _TPROTOCOLMESSAGE
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY.containing_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY.containing_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY.containing_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_bytes"
+].message_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_int"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_float"
+].message_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_bool"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_str"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
"content_dict_bool_bytes"
].message_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY
)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_int"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_float"
+].message_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_bool"
+].message_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_str"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_bytes"
+].message_type = (
+ _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_int"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
"content_dict_str_float"
].message_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY
)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_bool"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_str"
+].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.containing_type = _TPROTOCOLMESSAGE
_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY.containing_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
@@ -2156,28 +2975,12 @@
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY.containing_type = (
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE
)
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY.containing_type = (
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE
-)
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY.containing_type = (
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE
-)
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.fields_by_name[
"content_o_ct"
].message_type = _TPROTOCOLMESSAGE_DATAMODEL
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.fields_by_name[
"content_o_dict_str_int"
].message_type = _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.fields_by_name[
- "content_o_union_type_dict_of_str_int"
-].message_type = (
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY
-)
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.fields_by_name[
- "content_o_union_type_dict_of_str_float"
-].message_type = (
- _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY
-)
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE.containing_type = _TPROTOCOLMESSAGE
_TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE.containing_type = (
_TPROTOCOLMESSAGE
@@ -2251,173 +3054,272 @@
TProtocolMessage = _reflection.GeneratedProtocolMessageType(
"TProtocolMessage",
(_message.Message,),
- dict(
- DataModel=_reflection.GeneratedProtocolMessageType(
+ {
+ "DataModel": _reflection.GeneratedProtocolMessageType(
"DataModel",
(_message.Message,),
- dict(
- DictFieldEntry=_reflection.GeneratedProtocolMessageType(
+ {
+ "DictFieldEntry": _reflection.GeneratedProtocolMessageType(
"DictFieldEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.DataModel.DictFieldEntry)
- ),
+ },
),
- DESCRIPTOR=_TPROTOCOLMESSAGE_DATAMODEL,
- __module__="t_protocol_pb2"
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_DATAMODEL,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.DataModel)
- ),
+ },
),
- Performative_Ct_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Ct_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Ct_Performative",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_CT_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Ct_Performative)
- ),
+ },
),
- Performative_Pt_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Pt_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Pt_Performative",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pt_Performative)
- ),
+ },
),
- Performative_Pct_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Pct_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Pct_Performative",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pct_Performative)
- ),
+ },
),
- Performative_Pmt_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Pmt_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Pmt_Performative",
(_message.Message,),
- dict(
- ContentDictBoolBytesEntry=_reflection.GeneratedProtocolMessageType(
+ {
+ "ContentDictIntBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry)
+ },
+ ),
+ "ContentDictIntIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry)
+ },
+ ),
+ "ContentDictIntFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry)
+ },
+ ),
+ "ContentDictIntBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry)
+ },
+ ),
+ "ContentDictIntStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry)
+ },
+ ),
+ "ContentDictBoolBytesEntry": _reflection.GeneratedProtocolMessageType(
"ContentDictBoolBytesEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry)
- ),
+ },
+ ),
+ "ContentDictBoolIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry)
+ },
+ ),
+ "ContentDictBoolFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry)
+ },
+ ),
+ "ContentDictBoolBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry)
+ },
+ ),
+ "ContentDictBoolStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry)
+ },
),
- ContentDictStrFloatEntry=_reflection.GeneratedProtocolMessageType(
+ "ContentDictStrBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry)
+ },
+ ),
+ "ContentDictStrIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry)
+ },
+ ),
+ "ContentDictStrFloatEntry": _reflection.GeneratedProtocolMessageType(
"ContentDictStrFloatEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry)
- ),
+ },
+ ),
+ "ContentDictStrBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry)
+ },
+ ),
+ "ContentDictStrStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,
+ "__module__": "t_protocol_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry)
+ },
),
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Pmt_Performative)
- ),
+ },
),
- Performative_Mt_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Mt_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Mt_Performative",
(_message.Message,),
- dict(
- ContentUnion1TypeDictOfStrIntEntry=_reflection.GeneratedProtocolMessageType(
+ {
+ "ContentUnion1TypeDictOfStrIntEntry": _reflection.GeneratedProtocolMessageType(
"ContentUnion1TypeDictOfStrIntEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry)
- ),
+ },
),
- ContentUnion2TypeDictOfStrIntEntry=_reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfStrIntEntry": _reflection.GeneratedProtocolMessageType(
"ContentUnion2TypeDictOfStrIntEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry)
- ),
+ },
),
- ContentUnion2TypeDictOfIntFloatEntry=_reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfIntFloatEntry": _reflection.GeneratedProtocolMessageType(
"ContentUnion2TypeDictOfIntFloatEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry)
- ),
+ },
),
- ContentUnion2TypeDictOfBoolBytesEntry=_reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfBoolBytesEntry": _reflection.GeneratedProtocolMessageType(
"ContentUnion2TypeDictOfBoolBytesEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry)
- ),
+ },
),
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Mt_Performative)
- ),
+ },
),
- Performative_O_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_O_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_O_Performative",
(_message.Message,),
- dict(
- ContentODictStrIntEntry=_reflection.GeneratedProtocolMessageType(
+ {
+ "ContentODictStrIntEntry": _reflection.GeneratedProtocolMessageType(
"ContentODictStrIntEntry",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry)
- ),
+ },
),
- ContentOUnionTypeDictOfStrIntEntry=_reflection.GeneratedProtocolMessageType(
- "ContentOUnionTypeDictOfStrIntEntry",
- (_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY,
- __module__="t_protocol_pb2"
- # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry)
- ),
- ),
- ContentOUnionTypeDictOfStrFloatEntry=_reflection.GeneratedProtocolMessageType(
- "ContentOUnionTypeDictOfStrFloatEntry",
- (_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY,
- __module__="t_protocol_pb2"
- # @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry)
- ),
- ),
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_O_Performative)
- ),
+ },
),
- Performative_Empty_Contents_Performative=_reflection.GeneratedProtocolMessageType(
+ "Performative_Empty_Contents_Performative": _reflection.GeneratedProtocolMessageType(
"Performative_Empty_Contents_Performative",
(_message.Message,),
- dict(
- DESCRIPTOR=_TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,
- __module__="t_protocol_pb2"
+ {
+ "DESCRIPTOR": _TPROTOCOLMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage.Performative_Empty_Contents_Performative)
- ),
+ },
),
- DESCRIPTOR=_TPROTOCOLMESSAGE,
- __module__="t_protocol_pb2"
+ "DESCRIPTOR": _TPROTOCOLMESSAGE,
+ "__module__": "t_protocol_pb2"
# @@protoc_insertion_point(class_scope:fetch.aea.TProtocol.TProtocolMessage)
- ),
+ },
)
_sym_db.RegisterMessage(TProtocolMessage)
_sym_db.RegisterMessage(TProtocolMessage.DataModel)
@@ -2426,12 +3328,51 @@
_sym_db.RegisterMessage(TProtocolMessage.Performative_Pt_Performative)
_sym_db.RegisterMessage(TProtocolMessage.Performative_Pct_Performative)
_sym_db.RegisterMessage(TProtocolMessage.Performative_Pmt_Performative)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictIntIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictIntStrEntry
+)
_sym_db.RegisterMessage(
TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry
)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictStrIntEntry
+)
_sym_db.RegisterMessage(
TProtocolMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry
)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolMessage.Performative_Pmt_Performative.ContentDictStrStrEntry
+)
_sym_db.RegisterMessage(TProtocolMessage.Performative_Mt_Performative)
_sym_db.RegisterMessage(
TProtocolMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry
@@ -2449,20 +3390,29 @@
_sym_db.RegisterMessage(
TProtocolMessage.Performative_O_Performative.ContentODictStrIntEntry
)
-_sym_db.RegisterMessage(
- TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrIntEntry
-)
-_sym_db.RegisterMessage(
- TProtocolMessage.Performative_O_Performative.ContentOUnionTypeDictOfStrFloatEntry
-)
_sym_db.RegisterMessage(TProtocolMessage.Performative_Empty_Contents_Performative)
_TPROTOCOLMESSAGE_DATAMODEL_DICTFIELDENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._options = None
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._options = (
None
)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._options = (
+ None
+)
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._options = None
_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._options = None
+_TPROTOCOLMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._options = None
_TPROTOCOLMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._options = (
None
)
@@ -2476,10 +3426,4 @@
None
)
_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._options = None
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRINTENTRY._options = (
- None
-)
-_TPROTOCOLMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTOUNIONTYPEDICTOFSTRFLOATENTRY._options = (
- None
-)
# @@protoc_insertion_point(module_scope)
diff --git a/tests/data/generator/t_protocol_no_ct/__init__.py b/tests/data/generator/t_protocol_no_ct/__init__.py
new file mode 100644
index 0000000000..4ce3b6e598
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2020 fetchai
+#
+# 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 t_protocol_no_ct protocol."""
+
+from tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage
+from tests.data.generator.t_protocol_no_ct.serialization import TProtocolNoCtSerializer
+
+TProtocolNoCtMessage.serializer = TProtocolNoCtSerializer
diff --git a/tests/data/generator/t_protocol_no_ct/dialogues.py b/tests/data/generator/t_protocol_no_ct/dialogues.py
new file mode 100644
index 0000000000..bf5e985f1a
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/dialogues.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2020 fetchai
+#
+# 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 classes required for t_protocol_no_ct dialogue management.
+
+- TProtocolNoCtDialogue: The dialogue class maintains state of a dialogue and manages it.
+- TProtocolNoCtDialogues: The dialogues class keeps track of all dialogues.
+"""
+
+from abc import ABC
+from typing import Dict, FrozenSet, Optional, cast
+
+from aea.helpers.dialogue.base import Dialogue, DialogueLabel, Dialogues
+from aea.mail.base import Address
+from aea.protocols.base import Message
+
+from tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage
+
+
+class TProtocolNoCtDialogue(Dialogue):
+ """The t_protocol_no_ct dialogue class maintains state of a dialogue and manages it."""
+
+ INITIAL_PERFORMATIVES = frozenset(
+ {TProtocolNoCtMessage.Performative.PERFORMATIVE_PT}
+ )
+ TERMINAL_PERFORMATIVES = frozenset(
+ {
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_O,
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS,
+ }
+ )
+ VALID_REPLIES = {
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS: frozenset(
+ {TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS}
+ ),
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_MT: frozenset(),
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_O: frozenset(),
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT: frozenset(
+ {
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_O,
+ }
+ ),
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT: frozenset(
+ {
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_MT,
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_O,
+ }
+ ),
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_PT: frozenset(
+ {
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT,
+ TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT,
+ }
+ ),
+ }
+
+ class Role(Dialogue.Role):
+ """This class defines the agent's role in a t_protocol_no_ct dialogue."""
+
+ ROLE_1 = "role_1"
+ ROLE_2 = "role_2"
+
+ class EndState(Dialogue.EndState):
+ """This class defines the end states of a t_protocol_no_ct dialogue."""
+
+ END_STATE_1 = 0
+ END_STATE_2 = 1
+ END_STATE_3 = 2
+
+ def __init__(
+ self,
+ dialogue_label: DialogueLabel,
+ agent_address: Optional[Address] = None,
+ role: Optional[Dialogue.Role] = None,
+ ) -> None:
+ """
+ Initialize a dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param agent_address: the address of the agent for whom this dialogue is maintained
+ :param role: the role of the agent this dialogue is maintained for
+ :return: None
+ """
+ Dialogue.__init__(
+ self,
+ dialogue_label=dialogue_label,
+ agent_address=agent_address,
+ role=role,
+ rules=Dialogue.Rules(
+ cast(FrozenSet[Message.Performative], self.INITIAL_PERFORMATIVES),
+ cast(FrozenSet[Message.Performative], self.TERMINAL_PERFORMATIVES),
+ cast(
+ Dict[Message.Performative, FrozenSet[Message.Performative]],
+ self.VALID_REPLIES,
+ ),
+ ),
+ )
+
+ def is_valid(self, message: Message) -> bool:
+ """
+ Check whether 'message' is a valid next message in the dialogue.
+
+ These rules capture specific constraints designed for dialogues which are instances of a concrete sub-class of this class.
+ Override this method with your additional dialogue rules.
+
+ :param message: the message to be validated
+ :return: True if valid, False otherwise
+ """
+ return True
+
+
+class TProtocolNoCtDialogues(Dialogues, ABC):
+ """This class keeps track of all t_protocol_no_ct dialogues."""
+
+ END_STATES = frozenset(
+ {
+ TProtocolNoCtDialogue.EndState.END_STATE_1,
+ TProtocolNoCtDialogue.EndState.END_STATE_2,
+ TProtocolNoCtDialogue.EndState.END_STATE_3,
+ }
+ )
+
+ def __init__(self, agent_address: Address) -> None:
+ """
+ Initialize dialogues.
+
+ :param agent_address: the address of the agent for whom dialogues are maintained
+ :return: None
+ """
+ Dialogues.__init__(
+ self,
+ agent_address=agent_address,
+ end_states=cast(FrozenSet[Dialogue.EndState], self.END_STATES),
+ )
+
+ def create_dialogue(
+ self, dialogue_label: DialogueLabel, role: Dialogue.Role,
+ ) -> TProtocolNoCtDialogue:
+ """
+ Create an instance of t_protocol_no_ct dialogue.
+
+ :param dialogue_label: the identifier of the dialogue
+ :param role: the role of the agent this dialogue is maintained for
+
+ :return: the created dialogue
+ """
+ dialogue = TProtocolNoCtDialogue(
+ dialogue_label=dialogue_label, agent_address=self.agent_address, role=role
+ )
+ return dialogue
diff --git a/tests/data/generator/t_protocol_no_ct/message.py b/tests/data/generator/t_protocol_no_ct/message.py
new file mode 100644
index 0000000000..468ba1e1f5
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/message.py
@@ -0,0 +1,1008 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2020 fetchai
+#
+# 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 t_protocol_no_ct's message definition."""
+
+import logging
+from enum import Enum
+from typing import Dict, FrozenSet, Optional, Set, Tuple, Union, cast
+
+from aea.configurations.base import ProtocolId
+from aea.protocols.base import Message
+
+logger = logging.getLogger("aea.packages.fetchai.protocols.t_protocol_no_ct.message")
+
+DEFAULT_BODY_SIZE = 4
+
+
+class TProtocolNoCtMessage(Message):
+ """A protocol for testing purposes."""
+
+ protocol_id = ProtocolId.from_str("fetchai/t_protocol_no_ct:0.1.0")
+
+ class Performative(Enum):
+ """Performatives for the t_protocol_no_ct protocol."""
+
+ PERFORMATIVE_EMPTY_CONTENTS = "performative_empty_contents"
+ PERFORMATIVE_MT = "performative_mt"
+ PERFORMATIVE_O = "performative_o"
+ PERFORMATIVE_PCT = "performative_pct"
+ PERFORMATIVE_PMT = "performative_pmt"
+ PERFORMATIVE_PT = "performative_pt"
+
+ def __str__(self):
+ """Get the string representation."""
+ return str(self.value)
+
+ def __init__(
+ self,
+ performative: Performative,
+ dialogue_reference: Tuple[str, str] = ("", ""),
+ message_id: int = 1,
+ target: int = 0,
+ **kwargs,
+ ):
+ """
+ Initialise an instance of TProtocolNoCtMessage.
+
+ :param message_id: the message id.
+ :param dialogue_reference: the dialogue reference.
+ :param target: the message target.
+ :param performative: the message performative.
+ """
+ super().__init__(
+ dialogue_reference=dialogue_reference,
+ message_id=message_id,
+ target=target,
+ performative=TProtocolNoCtMessage.Performative(performative),
+ **kwargs,
+ )
+ self._performatives = {
+ "performative_empty_contents",
+ "performative_mt",
+ "performative_o",
+ "performative_pct",
+ "performative_pmt",
+ "performative_pt",
+ }
+
+ @property
+ def valid_performatives(self) -> Set[str]:
+ """Get valid performatives."""
+ return self._performatives
+
+ @property
+ def dialogue_reference(self) -> Tuple[str, str]:
+ """Get the dialogue_reference of the message."""
+ assert self.is_set("dialogue_reference"), "dialogue_reference is not set."
+ return cast(Tuple[str, str], self.get("dialogue_reference"))
+
+ @property
+ def message_id(self) -> int:
+ """Get the message_id of the message."""
+ assert self.is_set("message_id"), "message_id is not set."
+ return cast(int, self.get("message_id"))
+
+ @property
+ def performative(self) -> Performative: # type: ignore # noqa: F821
+ """Get the performative of the message."""
+ assert self.is_set("performative"), "performative is not set."
+ return cast(TProtocolNoCtMessage.Performative, self.get("performative"))
+
+ @property
+ def target(self) -> int:
+ """Get the target of the message."""
+ assert self.is_set("target"), "target is not set."
+ return cast(int, self.get("target"))
+
+ @property
+ def content_bool(self) -> bool:
+ """Get the 'content_bool' content from the message."""
+ assert self.is_set("content_bool"), "'content_bool' content is not set."
+ return cast(bool, self.get("content_bool"))
+
+ @property
+ def content_bytes(self) -> bytes:
+ """Get the 'content_bytes' content from the message."""
+ assert self.is_set("content_bytes"), "'content_bytes' content is not set."
+ return cast(bytes, self.get("content_bytes"))
+
+ @property
+ def content_dict_bool_bool(self) -> Dict[bool, bool]:
+ """Get the 'content_dict_bool_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_bool"
+ ), "'content_dict_bool_bool' content is not set."
+ return cast(Dict[bool, bool], self.get("content_dict_bool_bool"))
+
+ @property
+ def content_dict_bool_bytes(self) -> Dict[bool, bytes]:
+ """Get the 'content_dict_bool_bytes' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_bytes"
+ ), "'content_dict_bool_bytes' content is not set."
+ return cast(Dict[bool, bytes], self.get("content_dict_bool_bytes"))
+
+ @property
+ def content_dict_bool_float(self) -> Dict[bool, float]:
+ """Get the 'content_dict_bool_float' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_float"
+ ), "'content_dict_bool_float' content is not set."
+ return cast(Dict[bool, float], self.get("content_dict_bool_float"))
+
+ @property
+ def content_dict_bool_int(self) -> Dict[bool, int]:
+ """Get the 'content_dict_bool_int' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_int"
+ ), "'content_dict_bool_int' content is not set."
+ return cast(Dict[bool, int], self.get("content_dict_bool_int"))
+
+ @property
+ def content_dict_bool_str(self) -> Dict[bool, str]:
+ """Get the 'content_dict_bool_str' content from the message."""
+ assert self.is_set(
+ "content_dict_bool_str"
+ ), "'content_dict_bool_str' content is not set."
+ return cast(Dict[bool, str], self.get("content_dict_bool_str"))
+
+ @property
+ def content_dict_int_bool(self) -> Dict[int, bool]:
+ """Get the 'content_dict_int_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_int_bool"
+ ), "'content_dict_int_bool' content is not set."
+ return cast(Dict[int, bool], self.get("content_dict_int_bool"))
+
+ @property
+ def content_dict_int_bytes(self) -> Dict[int, bytes]:
+ """Get the 'content_dict_int_bytes' content from the message."""
+ assert self.is_set(
+ "content_dict_int_bytes"
+ ), "'content_dict_int_bytes' content is not set."
+ return cast(Dict[int, bytes], self.get("content_dict_int_bytes"))
+
+ @property
+ def content_dict_int_float(self) -> Dict[int, float]:
+ """Get the 'content_dict_int_float' content from the message."""
+ assert self.is_set(
+ "content_dict_int_float"
+ ), "'content_dict_int_float' content is not set."
+ return cast(Dict[int, float], self.get("content_dict_int_float"))
+
+ @property
+ def content_dict_int_int(self) -> Dict[int, int]:
+ """Get the 'content_dict_int_int' content from the message."""
+ assert self.is_set(
+ "content_dict_int_int"
+ ), "'content_dict_int_int' content is not set."
+ return cast(Dict[int, int], self.get("content_dict_int_int"))
+
+ @property
+ def content_dict_int_str(self) -> Dict[int, str]:
+ """Get the 'content_dict_int_str' content from the message."""
+ assert self.is_set(
+ "content_dict_int_str"
+ ), "'content_dict_int_str' content is not set."
+ return cast(Dict[int, str], self.get("content_dict_int_str"))
+
+ @property
+ def content_dict_str_bool(self) -> Dict[str, bool]:
+ """Get the 'content_dict_str_bool' content from the message."""
+ assert self.is_set(
+ "content_dict_str_bool"
+ ), "'content_dict_str_bool' content is not set."
+ return cast(Dict[str, bool], self.get("content_dict_str_bool"))
+
+ @property
+ def content_dict_str_bytes(self) -> Dict[str, bytes]:
+ """Get the 'content_dict_str_bytes' content from the message."""
+ assert self.is_set(
+ "content_dict_str_bytes"
+ ), "'content_dict_str_bytes' content is not set."
+ return cast(Dict[str, bytes], self.get("content_dict_str_bytes"))
+
+ @property
+ def content_dict_str_float(self) -> Dict[str, float]:
+ """Get the 'content_dict_str_float' content from the message."""
+ assert self.is_set(
+ "content_dict_str_float"
+ ), "'content_dict_str_float' content is not set."
+ return cast(Dict[str, float], self.get("content_dict_str_float"))
+
+ @property
+ def content_dict_str_int(self) -> Dict[str, int]:
+ """Get the 'content_dict_str_int' content from the message."""
+ assert self.is_set(
+ "content_dict_str_int"
+ ), "'content_dict_str_int' content is not set."
+ return cast(Dict[str, int], self.get("content_dict_str_int"))
+
+ @property
+ def content_dict_str_str(self) -> Dict[str, str]:
+ """Get the 'content_dict_str_str' content from the message."""
+ assert self.is_set(
+ "content_dict_str_str"
+ ), "'content_dict_str_str' content is not set."
+ return cast(Dict[str, str], self.get("content_dict_str_str"))
+
+ @property
+ def content_float(self) -> float:
+ """Get the 'content_float' content from the message."""
+ assert self.is_set("content_float"), "'content_float' content is not set."
+ return cast(float, self.get("content_float"))
+
+ @property
+ def content_int(self) -> int:
+ """Get the 'content_int' content from the message."""
+ assert self.is_set("content_int"), "'content_int' content is not set."
+ return cast(int, self.get("content_int"))
+
+ @property
+ def content_list_bool(self) -> Tuple[bool, ...]:
+ """Get the 'content_list_bool' content from the message."""
+ assert self.is_set(
+ "content_list_bool"
+ ), "'content_list_bool' content is not set."
+ return cast(Tuple[bool, ...], self.get("content_list_bool"))
+
+ @property
+ def content_list_bytes(self) -> Tuple[bytes, ...]:
+ """Get the 'content_list_bytes' content from the message."""
+ assert self.is_set(
+ "content_list_bytes"
+ ), "'content_list_bytes' content is not set."
+ return cast(Tuple[bytes, ...], self.get("content_list_bytes"))
+
+ @property
+ def content_list_float(self) -> Tuple[float, ...]:
+ """Get the 'content_list_float' content from the message."""
+ assert self.is_set(
+ "content_list_float"
+ ), "'content_list_float' content is not set."
+ return cast(Tuple[float, ...], self.get("content_list_float"))
+
+ @property
+ def content_list_int(self) -> Tuple[int, ...]:
+ """Get the 'content_list_int' content from the message."""
+ assert self.is_set("content_list_int"), "'content_list_int' content is not set."
+ return cast(Tuple[int, ...], self.get("content_list_int"))
+
+ @property
+ def content_list_str(self) -> Tuple[str, ...]:
+ """Get the 'content_list_str' content from the message."""
+ assert self.is_set("content_list_str"), "'content_list_str' content is not set."
+ return cast(Tuple[str, ...], self.get("content_list_str"))
+
+ @property
+ def content_o_bool(self) -> Optional[bool]:
+ """Get the 'content_o_bool' content from the message."""
+ return cast(Optional[bool], self.get("content_o_bool"))
+
+ @property
+ def content_o_dict_str_int(self) -> Optional[Dict[str, int]]:
+ """Get the 'content_o_dict_str_int' content from the message."""
+ return cast(Optional[Dict[str, int]], self.get("content_o_dict_str_int"))
+
+ @property
+ def content_o_list_bytes(self) -> Optional[Tuple[bytes, ...]]:
+ """Get the 'content_o_list_bytes' content from the message."""
+ return cast(Optional[Tuple[bytes, ...]], self.get("content_o_list_bytes"))
+
+ @property
+ def content_o_set_int(self) -> Optional[FrozenSet[int]]:
+ """Get the 'content_o_set_int' content from the message."""
+ return cast(Optional[FrozenSet[int]], self.get("content_o_set_int"))
+
+ @property
+ def content_set_bool(self) -> FrozenSet[bool]:
+ """Get the 'content_set_bool' content from the message."""
+ assert self.is_set("content_set_bool"), "'content_set_bool' content is not set."
+ return cast(FrozenSet[bool], self.get("content_set_bool"))
+
+ @property
+ def content_set_bytes(self) -> FrozenSet[bytes]:
+ """Get the 'content_set_bytes' content from the message."""
+ assert self.is_set(
+ "content_set_bytes"
+ ), "'content_set_bytes' content is not set."
+ return cast(FrozenSet[bytes], self.get("content_set_bytes"))
+
+ @property
+ def content_set_float(self) -> FrozenSet[float]:
+ """Get the 'content_set_float' content from the message."""
+ assert self.is_set(
+ "content_set_float"
+ ), "'content_set_float' content is not set."
+ return cast(FrozenSet[float], self.get("content_set_float"))
+
+ @property
+ def content_set_int(self) -> FrozenSet[int]:
+ """Get the 'content_set_int' content from the message."""
+ assert self.is_set("content_set_int"), "'content_set_int' content is not set."
+ return cast(FrozenSet[int], self.get("content_set_int"))
+
+ @property
+ def content_set_str(self) -> FrozenSet[str]:
+ """Get the 'content_set_str' content from the message."""
+ assert self.is_set("content_set_str"), "'content_set_str' content is not set."
+ return cast(FrozenSet[str], self.get("content_set_str"))
+
+ @property
+ def content_str(self) -> str:
+ """Get the 'content_str' content from the message."""
+ assert self.is_set("content_str"), "'content_str' content is not set."
+ return cast(str, self.get("content_str"))
+
+ @property
+ def content_union_1(
+ self,
+ ) -> Union[
+ bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]
+ ]:
+ """Get the 'content_union_1' content from the message."""
+ assert self.is_set("content_union_1"), "'content_union_1' content is not set."
+ return cast(
+ Union[
+ bytes,
+ int,
+ float,
+ bool,
+ str,
+ FrozenSet[int],
+ Tuple[bool, ...],
+ Dict[str, int],
+ ],
+ self.get("content_union_1"),
+ )
+
+ @property
+ def content_union_2(
+ self,
+ ) -> Union[
+ FrozenSet[bytes],
+ FrozenSet[int],
+ FrozenSet[str],
+ Tuple[float, ...],
+ Tuple[bool, ...],
+ Tuple[bytes, ...],
+ Dict[str, int],
+ Dict[int, float],
+ Dict[bool, bytes],
+ ]:
+ """Get the 'content_union_2' content from the message."""
+ assert self.is_set("content_union_2"), "'content_union_2' content is not set."
+ return cast(
+ Union[
+ FrozenSet[bytes],
+ FrozenSet[int],
+ FrozenSet[str],
+ Tuple[float, ...],
+ Tuple[bool, ...],
+ Tuple[bytes, ...],
+ Dict[str, int],
+ Dict[int, float],
+ Dict[bool, bytes],
+ ],
+ self.get("content_union_2"),
+ )
+
+ def _is_consistent(self) -> bool:
+ """Check that the message follows the t_protocol_no_ct protocol."""
+ try:
+ assert (
+ type(self.dialogue_reference) == tuple
+ ), "Invalid type for 'dialogue_reference'. Expected 'tuple'. Found '{}'.".format(
+ type(self.dialogue_reference)
+ )
+ assert (
+ type(self.dialogue_reference[0]) == str
+ ), "Invalid type for 'dialogue_reference[0]'. Expected 'str'. Found '{}'.".format(
+ type(self.dialogue_reference[0])
+ )
+ assert (
+ type(self.dialogue_reference[1]) == str
+ ), "Invalid type for 'dialogue_reference[1]'. Expected 'str'. Found '{}'.".format(
+ type(self.dialogue_reference[1])
+ )
+ assert (
+ type(self.message_id) == int
+ ), "Invalid type for 'message_id'. Expected 'int'. Found '{}'.".format(
+ type(self.message_id)
+ )
+ assert (
+ type(self.target) == int
+ ), "Invalid type for 'target'. Expected 'int'. Found '{}'.".format(
+ type(self.target)
+ )
+
+ # Light Protocol Rule 2
+ # Check correct performative
+ assert (
+ type(self.performative) == TProtocolNoCtMessage.Performative
+ ), "Invalid 'performative'. Expected either of '{}'. Found '{}'.".format(
+ self.valid_performatives, self.performative
+ )
+
+ # Check correct contents
+ actual_nb_of_contents = len(self.body) - DEFAULT_BODY_SIZE
+ expected_nb_of_contents = 0
+ if self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:
+ expected_nb_of_contents = 5
+ assert (
+ type(self.content_bytes) == bytes
+ ), "Invalid type for content 'content_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(self.content_bytes)
+ )
+ assert (
+ type(self.content_int) == int
+ ), "Invalid type for content 'content_int'. Expected 'int'. Found '{}'.".format(
+ type(self.content_int)
+ )
+ assert (
+ type(self.content_float) == float
+ ), "Invalid type for content 'content_float'. Expected 'float'. Found '{}'.".format(
+ type(self.content_float)
+ )
+ assert (
+ type(self.content_bool) == bool
+ ), "Invalid type for content 'content_bool'. Expected 'bool'. Found '{}'.".format(
+ type(self.content_bool)
+ )
+ assert (
+ type(self.content_str) == str
+ ), "Invalid type for content 'content_str'. Expected 'str'. Found '{}'.".format(
+ type(self.content_str)
+ )
+ elif (
+ self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT
+ ):
+ expected_nb_of_contents = 10
+ assert (
+ type(self.content_set_bytes) == frozenset
+ ), "Invalid type for content 'content_set_bytes'. Expected 'frozenset'. Found '{}'.".format(
+ type(self.content_set_bytes)
+ )
+ assert all(
+ type(element) == bytes for element in self.content_set_bytes
+ ), "Invalid type for frozenset elements in content 'content_set_bytes'. Expected 'bytes'."
+ assert (
+ type(self.content_set_int) == frozenset
+ ), "Invalid type for content 'content_set_int'. Expected 'frozenset'. Found '{}'.".format(
+ type(self.content_set_int)
+ )
+ assert all(
+ type(element) == int for element in self.content_set_int
+ ), "Invalid type for frozenset elements in content 'content_set_int'. Expected 'int'."
+ assert (
+ type(self.content_set_float) == frozenset
+ ), "Invalid type for content 'content_set_float'. Expected 'frozenset'. Found '{}'.".format(
+ type(self.content_set_float)
+ )
+ assert all(
+ type(element) == float for element in self.content_set_float
+ ), "Invalid type for frozenset elements in content 'content_set_float'. Expected 'float'."
+ assert (
+ type(self.content_set_bool) == frozenset
+ ), "Invalid type for content 'content_set_bool'. Expected 'frozenset'. Found '{}'.".format(
+ type(self.content_set_bool)
+ )
+ assert all(
+ type(element) == bool for element in self.content_set_bool
+ ), "Invalid type for frozenset elements in content 'content_set_bool'. Expected 'bool'."
+ assert (
+ type(self.content_set_str) == frozenset
+ ), "Invalid type for content 'content_set_str'. Expected 'frozenset'. Found '{}'.".format(
+ type(self.content_set_str)
+ )
+ assert all(
+ type(element) == str for element in self.content_set_str
+ ), "Invalid type for frozenset elements in content 'content_set_str'. Expected 'str'."
+ assert (
+ type(self.content_list_bytes) == tuple
+ ), "Invalid type for content 'content_list_bytes'. Expected 'tuple'. Found '{}'.".format(
+ type(self.content_list_bytes)
+ )
+ assert all(
+ type(element) == bytes for element in self.content_list_bytes
+ ), "Invalid type for tuple elements in content 'content_list_bytes'. Expected 'bytes'."
+ assert (
+ type(self.content_list_int) == tuple
+ ), "Invalid type for content 'content_list_int'. Expected 'tuple'. Found '{}'.".format(
+ type(self.content_list_int)
+ )
+ assert all(
+ type(element) == int for element in self.content_list_int
+ ), "Invalid type for tuple elements in content 'content_list_int'. Expected 'int'."
+ assert (
+ type(self.content_list_float) == tuple
+ ), "Invalid type for content 'content_list_float'. Expected 'tuple'. Found '{}'.".format(
+ type(self.content_list_float)
+ )
+ assert all(
+ type(element) == float for element in self.content_list_float
+ ), "Invalid type for tuple elements in content 'content_list_float'. Expected 'float'."
+ assert (
+ type(self.content_list_bool) == tuple
+ ), "Invalid type for content 'content_list_bool'. Expected 'tuple'. Found '{}'.".format(
+ type(self.content_list_bool)
+ )
+ assert all(
+ type(element) == bool for element in self.content_list_bool
+ ), "Invalid type for tuple elements in content 'content_list_bool'. Expected 'bool'."
+ assert (
+ type(self.content_list_str) == tuple
+ ), "Invalid type for content 'content_list_str'. Expected 'tuple'. Found '{}'.".format(
+ type(self.content_list_str)
+ )
+ assert all(
+ type(element) == str for element in self.content_list_str
+ ), "Invalid type for tuple elements in content 'content_list_str'. Expected 'str'."
+ elif (
+ self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT
+ ):
+ expected_nb_of_contents = 15
+ assert (
+ type(self.content_dict_int_bytes) == dict
+ ), "Invalid type for content 'content_dict_int_bytes'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_bytes)
+ )
+ for (
+ key_of_content_dict_int_bytes,
+ value_of_content_dict_int_bytes,
+ ) in self.content_dict_int_bytes.items():
+ assert (
+ type(key_of_content_dict_int_bytes) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_bytes'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_bytes)
+ )
+ assert (
+ type(value_of_content_dict_int_bytes) == bytes
+ ), "Invalid type for dictionary values in content 'content_dict_int_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(value_of_content_dict_int_bytes)
+ )
+ assert (
+ type(self.content_dict_int_int) == dict
+ ), "Invalid type for content 'content_dict_int_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_int)
+ )
+ for (
+ key_of_content_dict_int_int,
+ value_of_content_dict_int_int,
+ ) in self.content_dict_int_int.items():
+ assert (
+ type(key_of_content_dict_int_int) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_int'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_int)
+ )
+ assert (
+ type(value_of_content_dict_int_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_int_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_int_int)
+ )
+ assert (
+ type(self.content_dict_int_float) == dict
+ ), "Invalid type for content 'content_dict_int_float'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_float)
+ )
+ for (
+ key_of_content_dict_int_float,
+ value_of_content_dict_int_float,
+ ) in self.content_dict_int_float.items():
+ assert (
+ type(key_of_content_dict_int_float) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_float'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_float)
+ )
+ assert (
+ type(value_of_content_dict_int_float) == float
+ ), "Invalid type for dictionary values in content 'content_dict_int_float'. Expected 'float'. Found '{}'.".format(
+ type(value_of_content_dict_int_float)
+ )
+ assert (
+ type(self.content_dict_int_bool) == dict
+ ), "Invalid type for content 'content_dict_int_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_bool)
+ )
+ for (
+ key_of_content_dict_int_bool,
+ value_of_content_dict_int_bool,
+ ) in self.content_dict_int_bool.items():
+ assert (
+ type(key_of_content_dict_int_bool) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_bool'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_bool)
+ )
+ assert (
+ type(value_of_content_dict_int_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_int_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_int_bool)
+ )
+ assert (
+ type(self.content_dict_int_str) == dict
+ ), "Invalid type for content 'content_dict_int_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_int_str)
+ )
+ for (
+ key_of_content_dict_int_str,
+ value_of_content_dict_int_str,
+ ) in self.content_dict_int_str.items():
+ assert (
+ type(key_of_content_dict_int_str) == int
+ ), "Invalid type for dictionary keys in content 'content_dict_int_str'. Expected 'int'. Found '{}'.".format(
+ type(key_of_content_dict_int_str)
+ )
+ assert (
+ type(value_of_content_dict_int_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_int_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_int_str)
+ )
+ assert (
+ type(self.content_dict_bool_bytes) == dict
+ ), "Invalid type for content 'content_dict_bool_bytes'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_bytes)
+ )
+ for (
+ key_of_content_dict_bool_bytes,
+ value_of_content_dict_bool_bytes,
+ ) in self.content_dict_bool_bytes.items():
+ assert (
+ type(key_of_content_dict_bool_bytes) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_bytes'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_bytes)
+ )
+ assert (
+ type(value_of_content_dict_bool_bytes) == bytes
+ ), "Invalid type for dictionary values in content 'content_dict_bool_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(value_of_content_dict_bool_bytes)
+ )
+ assert (
+ type(self.content_dict_bool_int) == dict
+ ), "Invalid type for content 'content_dict_bool_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_int)
+ )
+ for (
+ key_of_content_dict_bool_int,
+ value_of_content_dict_bool_int,
+ ) in self.content_dict_bool_int.items():
+ assert (
+ type(key_of_content_dict_bool_int) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_int'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_int)
+ )
+ assert (
+ type(value_of_content_dict_bool_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_bool_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_bool_int)
+ )
+ assert (
+ type(self.content_dict_bool_float) == dict
+ ), "Invalid type for content 'content_dict_bool_float'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_float)
+ )
+ for (
+ key_of_content_dict_bool_float,
+ value_of_content_dict_bool_float,
+ ) in self.content_dict_bool_float.items():
+ assert (
+ type(key_of_content_dict_bool_float) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_float'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_float)
+ )
+ assert (
+ type(value_of_content_dict_bool_float) == float
+ ), "Invalid type for dictionary values in content 'content_dict_bool_float'. Expected 'float'. Found '{}'.".format(
+ type(value_of_content_dict_bool_float)
+ )
+ assert (
+ type(self.content_dict_bool_bool) == dict
+ ), "Invalid type for content 'content_dict_bool_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_bool)
+ )
+ for (
+ key_of_content_dict_bool_bool,
+ value_of_content_dict_bool_bool,
+ ) in self.content_dict_bool_bool.items():
+ assert (
+ type(key_of_content_dict_bool_bool) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_bool)
+ )
+ assert (
+ type(value_of_content_dict_bool_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_bool_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_bool_bool)
+ )
+ assert (
+ type(self.content_dict_bool_str) == dict
+ ), "Invalid type for content 'content_dict_bool_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_bool_str)
+ )
+ for (
+ key_of_content_dict_bool_str,
+ value_of_content_dict_bool_str,
+ ) in self.content_dict_bool_str.items():
+ assert (
+ type(key_of_content_dict_bool_str) == bool
+ ), "Invalid type for dictionary keys in content 'content_dict_bool_str'. Expected 'bool'. Found '{}'.".format(
+ type(key_of_content_dict_bool_str)
+ )
+ assert (
+ type(value_of_content_dict_bool_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_bool_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_bool_str)
+ )
+ assert (
+ type(self.content_dict_str_bytes) == dict
+ ), "Invalid type for content 'content_dict_str_bytes'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_bytes)
+ )
+ for (
+ key_of_content_dict_str_bytes,
+ value_of_content_dict_str_bytes,
+ ) in self.content_dict_str_bytes.items():
+ assert (
+ type(key_of_content_dict_str_bytes) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_bytes'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_bytes)
+ )
+ assert (
+ type(value_of_content_dict_str_bytes) == bytes
+ ), "Invalid type for dictionary values in content 'content_dict_str_bytes'. Expected 'bytes'. Found '{}'.".format(
+ type(value_of_content_dict_str_bytes)
+ )
+ assert (
+ type(self.content_dict_str_int) == dict
+ ), "Invalid type for content 'content_dict_str_int'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_int)
+ )
+ for (
+ key_of_content_dict_str_int,
+ value_of_content_dict_str_int,
+ ) in self.content_dict_str_int.items():
+ assert (
+ type(key_of_content_dict_str_int) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_int'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_int)
+ )
+ assert (
+ type(value_of_content_dict_str_int) == int
+ ), "Invalid type for dictionary values in content 'content_dict_str_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_dict_str_int)
+ )
+ assert (
+ type(self.content_dict_str_float) == dict
+ ), "Invalid type for content 'content_dict_str_float'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_float)
+ )
+ for (
+ key_of_content_dict_str_float,
+ value_of_content_dict_str_float,
+ ) in self.content_dict_str_float.items():
+ assert (
+ type(key_of_content_dict_str_float) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_float'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_float)
+ )
+ assert (
+ type(value_of_content_dict_str_float) == float
+ ), "Invalid type for dictionary values in content 'content_dict_str_float'. Expected 'float'. Found '{}'.".format(
+ type(value_of_content_dict_str_float)
+ )
+ assert (
+ type(self.content_dict_str_bool) == dict
+ ), "Invalid type for content 'content_dict_str_bool'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_bool)
+ )
+ for (
+ key_of_content_dict_str_bool,
+ value_of_content_dict_str_bool,
+ ) in self.content_dict_str_bool.items():
+ assert (
+ type(key_of_content_dict_str_bool) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_bool'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_bool)
+ )
+ assert (
+ type(value_of_content_dict_str_bool) == bool
+ ), "Invalid type for dictionary values in content 'content_dict_str_bool'. Expected 'bool'. Found '{}'.".format(
+ type(value_of_content_dict_str_bool)
+ )
+ assert (
+ type(self.content_dict_str_str) == dict
+ ), "Invalid type for content 'content_dict_str_str'. Expected 'dict'. Found '{}'.".format(
+ type(self.content_dict_str_str)
+ )
+ for (
+ key_of_content_dict_str_str,
+ value_of_content_dict_str_str,
+ ) in self.content_dict_str_str.items():
+ assert (
+ type(key_of_content_dict_str_str) == str
+ ), "Invalid type for dictionary keys in content 'content_dict_str_str'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_dict_str_str)
+ )
+ assert (
+ type(value_of_content_dict_str_str) == str
+ ), "Invalid type for dictionary values in content 'content_dict_str_str'. Expected 'str'. Found '{}'.".format(
+ type(value_of_content_dict_str_str)
+ )
+ elif self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:
+ expected_nb_of_contents = 2
+ assert (
+ type(self.content_union_1) == bool
+ or type(self.content_union_1) == bytes
+ or type(self.content_union_1) == dict
+ or type(self.content_union_1) == float
+ or type(self.content_union_1) == frozenset
+ or type(self.content_union_1) == int
+ or type(self.content_union_1) == str
+ or type(self.content_union_1) == tuple
+ ), "Invalid type for content 'content_union_1'. Expected either of '['bool', 'bytes', 'dict', 'float', 'frozenset', 'int', 'str', 'tuple']'. Found '{}'.".format(
+ type(self.content_union_1)
+ )
+ if type(self.content_union_1) == frozenset:
+ assert all(
+ type(element) == int for element in self.content_union_1
+ ), "Invalid type for elements of content 'content_union_1'. Expected 'int'."
+ if type(self.content_union_1) == tuple:
+ assert all(
+ type(element) == bool for element in self.content_union_1
+ ), "Invalid type for tuple elements in content 'content_union_1'. Expected 'bool'."
+ if type(self.content_union_1) == dict:
+ for (
+ key_of_content_union_1,
+ value_of_content_union_1,
+ ) in self.content_union_1.items():
+ assert (
+ type(key_of_content_union_1) == str
+ and type(value_of_content_union_1) == int
+ ), "Invalid type for dictionary key, value in content 'content_union_1'. Expected 'str', 'int'."
+ assert (
+ type(self.content_union_2) == dict
+ or type(self.content_union_2) == frozenset
+ or type(self.content_union_2) == tuple
+ ), "Invalid type for content 'content_union_2'. Expected either of '['dict', 'frozenset', 'tuple']'. Found '{}'.".format(
+ type(self.content_union_2)
+ )
+ if type(self.content_union_2) == frozenset:
+ assert (
+ all(type(element) == bytes for element in self.content_union_2)
+ or all(type(element) == int for element in self.content_union_2)
+ or all(type(element) == str for element in self.content_union_2)
+ ), "Invalid type for frozenset elements in content 'content_union_2'. Expected either 'bytes' or 'int' or 'str'."
+ if type(self.content_union_2) == tuple:
+ assert (
+ all(type(element) == bool for element in self.content_union_2)
+ or all(
+ type(element) == bytes for element in self.content_union_2
+ )
+ or all(
+ type(element) == float for element in self.content_union_2
+ )
+ ), "Invalid type for tuple elements in content 'content_union_2'. Expected either 'bool' or 'bytes' or 'float'."
+ if type(self.content_union_2) == dict:
+ for (
+ key_of_content_union_2,
+ value_of_content_union_2,
+ ) in self.content_union_2.items():
+ assert (
+ (
+ type(key_of_content_union_2) == bool
+ and type(value_of_content_union_2) == bytes
+ )
+ or (
+ type(key_of_content_union_2) == int
+ and type(value_of_content_union_2) == float
+ )
+ or (
+ type(key_of_content_union_2) == str
+ and type(value_of_content_union_2) == int
+ )
+ ), "Invalid type for dictionary key, value in content 'content_union_2'. Expected 'bool','bytes' or 'int','float' or 'str','int'."
+ elif self.performative == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:
+ expected_nb_of_contents = 0
+ if self.is_set("content_o_bool"):
+ expected_nb_of_contents += 1
+ content_o_bool = cast(bool, self.content_o_bool)
+ assert (
+ type(content_o_bool) == bool
+ ), "Invalid type for content 'content_o_bool'. Expected 'bool'. Found '{}'.".format(
+ type(content_o_bool)
+ )
+ if self.is_set("content_o_set_int"):
+ expected_nb_of_contents += 1
+ content_o_set_int = cast(FrozenSet[int], self.content_o_set_int)
+ assert (
+ type(content_o_set_int) == frozenset
+ ), "Invalid type for content 'content_o_set_int'. Expected 'frozenset'. Found '{}'.".format(
+ type(content_o_set_int)
+ )
+ assert all(
+ type(element) == int for element in content_o_set_int
+ ), "Invalid type for frozenset elements in content 'content_o_set_int'. Expected 'int'."
+ if self.is_set("content_o_list_bytes"):
+ expected_nb_of_contents += 1
+ content_o_list_bytes = cast(
+ Tuple[bytes, ...], self.content_o_list_bytes
+ )
+ assert (
+ type(content_o_list_bytes) == tuple
+ ), "Invalid type for content 'content_o_list_bytes'. Expected 'tuple'. Found '{}'.".format(
+ type(content_o_list_bytes)
+ )
+ assert all(
+ type(element) == bytes for element in content_o_list_bytes
+ ), "Invalid type for tuple elements in content 'content_o_list_bytes'. Expected 'bytes'."
+ if self.is_set("content_o_dict_str_int"):
+ expected_nb_of_contents += 1
+ content_o_dict_str_int = cast(
+ Dict[str, int], self.content_o_dict_str_int
+ )
+ assert (
+ type(content_o_dict_str_int) == dict
+ ), "Invalid type for content 'content_o_dict_str_int'. Expected 'dict'. Found '{}'.".format(
+ type(content_o_dict_str_int)
+ )
+ for (
+ key_of_content_o_dict_str_int,
+ value_of_content_o_dict_str_int,
+ ) in content_o_dict_str_int.items():
+ assert (
+ type(key_of_content_o_dict_str_int) == str
+ ), "Invalid type for dictionary keys in content 'content_o_dict_str_int'. Expected 'str'. Found '{}'.".format(
+ type(key_of_content_o_dict_str_int)
+ )
+ assert (
+ type(value_of_content_o_dict_str_int) == int
+ ), "Invalid type for dictionary values in content 'content_o_dict_str_int'. Expected 'int'. Found '{}'.".format(
+ type(value_of_content_o_dict_str_int)
+ )
+ elif (
+ self.performative
+ == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
+ ):
+ expected_nb_of_contents = 0
+
+ # Check correct content count
+ assert (
+ expected_nb_of_contents == actual_nb_of_contents
+ ), "Incorrect number of contents. Expected {}. Found {}".format(
+ expected_nb_of_contents, actual_nb_of_contents
+ )
+
+ # Light Protocol Rule 3
+ if self.message_id == 1:
+ assert (
+ self.target == 0
+ ), "Invalid 'target'. Expected 0 (because 'message_id' is 1). Found {}.".format(
+ self.target
+ )
+ else:
+ assert (
+ 0 < self.target < self.message_id
+ ), "Invalid 'target'. Expected an integer between 1 and {} inclusive. Found {}.".format(
+ self.message_id - 1, self.target,
+ )
+ except (AssertionError, ValueError, KeyError) as e:
+ logger.error(str(e))
+ return False
+
+ return True
diff --git a/tests/data/generator/t_protocol_no_ct/protocol.yaml b/tests/data/generator/t_protocol_no_ct/protocol.yaml
new file mode 100644
index 0000000000..a6d9693f14
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/protocol.yaml
@@ -0,0 +1,16 @@
+name: t_protocol_no_ct
+author: fetchai
+version: 0.1.0
+description: A protocol for testing purposes.
+license: Apache-2.0
+aea_version: '>=0.5.0, <0.6.0'
+fingerprint:
+ __init__.py: QmRGHGRoZHGCXQ29v3q93Nt6J5TuhggYvUvZoQfrM6c3yp
+ dialogues.py: QmR8zDLTaKpxeuJU2wRXo4vnVQVHGcY2FX9xjy62c5n9jX
+ message.py: QmcMYvB4MwQgZ8Z33aGAUUBMqx3Eq7uXBZwhdeKWMyvZWg
+ serialization.py: Qmc3tJ5vk1AbtkF5BrPUeuyrnvVUTrfuUMF9MgDfkiiMkB
+ t_protocol_no_ct.proto: QmeZWVLhb6EUGr5AgVwgf2YTEZTSuCskpmxCwAE3sDU9sY
+ t_protocol_no_ct_pb2.py: QmYtjyYTv1fQrwTS2x5ZkrNB8bpgH2vpPUJsUV29B7E4d9
+fingerprint_ignore_patterns: []
+dependencies:
+ protobuf: {}
diff --git a/tests/data/generator/t_protocol_no_ct/serialization.py b/tests/data/generator/t_protocol_no_ct/serialization.py
new file mode 100644
index 0000000000..bf7b3face3
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/serialization.py
@@ -0,0 +1,542 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2020 fetchai
+#
+# 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.
+#
+# ------------------------------------------------------------------------------
+
+"""Serialization module for t_protocol_no_ct protocol."""
+
+from typing import Any, Dict, cast
+
+from aea.protocols.base import Message
+from aea.protocols.base import Serializer
+
+from tests.data.generator.t_protocol_no_ct import t_protocol_no_ct_pb2
+from tests.data.generator.t_protocol_no_ct.message import TProtocolNoCtMessage
+
+
+class TProtocolNoCtSerializer(Serializer):
+ """Serialization for the 't_protocol_no_ct' protocol."""
+
+ @staticmethod
+ def encode(msg: Message) -> bytes:
+ """
+ Encode a 'TProtocolNoCt' message into bytes.
+
+ :param msg: the message object.
+ :return: the bytes.
+ """
+ msg = cast(TProtocolNoCtMessage, msg)
+ t_protocol_no_ct_msg = t_protocol_no_ct_pb2.TProtocolNoCtMessage()
+ t_protocol_no_ct_msg.message_id = msg.message_id
+ dialogue_reference = msg.dialogue_reference
+ t_protocol_no_ct_msg.dialogue_starter_reference = dialogue_reference[0]
+ t_protocol_no_ct_msg.dialogue_responder_reference = dialogue_reference[1]
+ t_protocol_no_ct_msg.target = msg.target
+
+ performative_id = msg.performative
+ if performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pt_Performative() # type: ignore
+ content_bytes = msg.content_bytes
+ performative.content_bytes = content_bytes
+ content_int = msg.content_int
+ performative.content_int = content_int
+ content_float = msg.content_float
+ performative.content_float = content_float
+ content_bool = msg.content_bool
+ performative.content_bool = content_bool
+ content_str = msg.content_str
+ performative.content_str = content_str
+ t_protocol_no_ct_msg.performative_pt.CopyFrom(performative)
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT:
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pct_Performative() # type: ignore
+ content_set_bytes = msg.content_set_bytes
+ performative.content_set_bytes.extend(content_set_bytes)
+ content_set_int = msg.content_set_int
+ performative.content_set_int.extend(content_set_int)
+ content_set_float = msg.content_set_float
+ performative.content_set_float.extend(content_set_float)
+ content_set_bool = msg.content_set_bool
+ performative.content_set_bool.extend(content_set_bool)
+ content_set_str = msg.content_set_str
+ performative.content_set_str.extend(content_set_str)
+ content_list_bytes = msg.content_list_bytes
+ performative.content_list_bytes.extend(content_list_bytes)
+ content_list_int = msg.content_list_int
+ performative.content_list_int.extend(content_list_int)
+ content_list_float = msg.content_list_float
+ performative.content_list_float.extend(content_list_float)
+ content_list_bool = msg.content_list_bool
+ performative.content_list_bool.extend(content_list_bool)
+ content_list_str = msg.content_list_str
+ performative.content_list_str.extend(content_list_str)
+ t_protocol_no_ct_msg.performative_pct.CopyFrom(performative)
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT:
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Pmt_Performative() # type: ignore
+ content_dict_int_bytes = msg.content_dict_int_bytes
+ performative.content_dict_int_bytes.update(content_dict_int_bytes)
+ content_dict_int_int = msg.content_dict_int_int
+ performative.content_dict_int_int.update(content_dict_int_int)
+ content_dict_int_float = msg.content_dict_int_float
+ performative.content_dict_int_float.update(content_dict_int_float)
+ content_dict_int_bool = msg.content_dict_int_bool
+ performative.content_dict_int_bool.update(content_dict_int_bool)
+ content_dict_int_str = msg.content_dict_int_str
+ performative.content_dict_int_str.update(content_dict_int_str)
+ content_dict_bool_bytes = msg.content_dict_bool_bytes
+ performative.content_dict_bool_bytes.update(content_dict_bool_bytes)
+ content_dict_bool_int = msg.content_dict_bool_int
+ performative.content_dict_bool_int.update(content_dict_bool_int)
+ content_dict_bool_float = msg.content_dict_bool_float
+ performative.content_dict_bool_float.update(content_dict_bool_float)
+ content_dict_bool_bool = msg.content_dict_bool_bool
+ performative.content_dict_bool_bool.update(content_dict_bool_bool)
+ content_dict_bool_str = msg.content_dict_bool_str
+ performative.content_dict_bool_str.update(content_dict_bool_str)
+ content_dict_str_bytes = msg.content_dict_str_bytes
+ performative.content_dict_str_bytes.update(content_dict_str_bytes)
+ content_dict_str_int = msg.content_dict_str_int
+ performative.content_dict_str_int.update(content_dict_str_int)
+ content_dict_str_float = msg.content_dict_str_float
+ performative.content_dict_str_float.update(content_dict_str_float)
+ content_dict_str_bool = msg.content_dict_str_bool
+ performative.content_dict_str_bool.update(content_dict_str_bool)
+ content_dict_str_str = msg.content_dict_str_str
+ performative.content_dict_str_str.update(content_dict_str_str)
+ t_protocol_no_ct_msg.performative_pmt.CopyFrom(performative)
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Mt_Performative() # type: ignore
+ if msg.is_set("content_union_1_type_bytes"):
+ performative.content_union_1_type_bytes_is_set = True
+ content_union_1_type_bytes = msg.content_union_1_type_bytes
+ performative.content_union_1_type_bytes = content_union_1_type_bytes
+ if msg.is_set("content_union_1_type_int"):
+ performative.content_union_1_type_int_is_set = True
+ content_union_1_type_int = msg.content_union_1_type_int
+ performative.content_union_1_type_int = content_union_1_type_int
+ if msg.is_set("content_union_1_type_float"):
+ performative.content_union_1_type_float_is_set = True
+ content_union_1_type_float = msg.content_union_1_type_float
+ performative.content_union_1_type_float = content_union_1_type_float
+ if msg.is_set("content_union_1_type_bool"):
+ performative.content_union_1_type_bool_is_set = True
+ content_union_1_type_bool = msg.content_union_1_type_bool
+ performative.content_union_1_type_bool = content_union_1_type_bool
+ if msg.is_set("content_union_1_type_str"):
+ performative.content_union_1_type_str_is_set = True
+ content_union_1_type_str = msg.content_union_1_type_str
+ performative.content_union_1_type_str = content_union_1_type_str
+ if msg.is_set("content_union_1_type_set_of_int"):
+ performative.content_union_1_type_set_of_int_is_set = True
+ content_union_1_type_set_of_int = msg.content_union_1_type_set_of_int
+ performative.content_union_1_type_set_of_int.extend(
+ content_union_1_type_set_of_int
+ )
+ if msg.is_set("content_union_1_type_list_of_bool"):
+ performative.content_union_1_type_list_of_bool_is_set = True
+ content_union_1_type_list_of_bool = (
+ msg.content_union_1_type_list_of_bool
+ )
+ performative.content_union_1_type_list_of_bool.extend(
+ content_union_1_type_list_of_bool
+ )
+ if msg.is_set("content_union_1_type_dict_of_str_int"):
+ performative.content_union_1_type_dict_of_str_int_is_set = True
+ content_union_1_type_dict_of_str_int = (
+ msg.content_union_1_type_dict_of_str_int
+ )
+ performative.content_union_1_type_dict_of_str_int.update(
+ content_union_1_type_dict_of_str_int
+ )
+ if msg.is_set("content_union_2_type_set_of_bytes"):
+ performative.content_union_2_type_set_of_bytes_is_set = True
+ content_union_2_type_set_of_bytes = (
+ msg.content_union_2_type_set_of_bytes
+ )
+ performative.content_union_2_type_set_of_bytes.extend(
+ content_union_2_type_set_of_bytes
+ )
+ if msg.is_set("content_union_2_type_set_of_int"):
+ performative.content_union_2_type_set_of_int_is_set = True
+ content_union_2_type_set_of_int = msg.content_union_2_type_set_of_int
+ performative.content_union_2_type_set_of_int.extend(
+ content_union_2_type_set_of_int
+ )
+ if msg.is_set("content_union_2_type_set_of_str"):
+ performative.content_union_2_type_set_of_str_is_set = True
+ content_union_2_type_set_of_str = msg.content_union_2_type_set_of_str
+ performative.content_union_2_type_set_of_str.extend(
+ content_union_2_type_set_of_str
+ )
+ if msg.is_set("content_union_2_type_list_of_float"):
+ performative.content_union_2_type_list_of_float_is_set = True
+ content_union_2_type_list_of_float = (
+ msg.content_union_2_type_list_of_float
+ )
+ performative.content_union_2_type_list_of_float.extend(
+ content_union_2_type_list_of_float
+ )
+ if msg.is_set("content_union_2_type_list_of_bool"):
+ performative.content_union_2_type_list_of_bool_is_set = True
+ content_union_2_type_list_of_bool = (
+ msg.content_union_2_type_list_of_bool
+ )
+ performative.content_union_2_type_list_of_bool.extend(
+ content_union_2_type_list_of_bool
+ )
+ if msg.is_set("content_union_2_type_list_of_bytes"):
+ performative.content_union_2_type_list_of_bytes_is_set = True
+ content_union_2_type_list_of_bytes = (
+ msg.content_union_2_type_list_of_bytes
+ )
+ performative.content_union_2_type_list_of_bytes.extend(
+ content_union_2_type_list_of_bytes
+ )
+ if msg.is_set("content_union_2_type_dict_of_str_int"):
+ performative.content_union_2_type_dict_of_str_int_is_set = True
+ content_union_2_type_dict_of_str_int = (
+ msg.content_union_2_type_dict_of_str_int
+ )
+ performative.content_union_2_type_dict_of_str_int.update(
+ content_union_2_type_dict_of_str_int
+ )
+ if msg.is_set("content_union_2_type_dict_of_int_float"):
+ performative.content_union_2_type_dict_of_int_float_is_set = True
+ content_union_2_type_dict_of_int_float = (
+ msg.content_union_2_type_dict_of_int_float
+ )
+ performative.content_union_2_type_dict_of_int_float.update(
+ content_union_2_type_dict_of_int_float
+ )
+ if msg.is_set("content_union_2_type_dict_of_bool_bytes"):
+ performative.content_union_2_type_dict_of_bool_bytes_is_set = True
+ content_union_2_type_dict_of_bool_bytes = (
+ msg.content_union_2_type_dict_of_bool_bytes
+ )
+ performative.content_union_2_type_dict_of_bool_bytes.update(
+ content_union_2_type_dict_of_bool_bytes
+ )
+ t_protocol_no_ct_msg.performative_mt.CopyFrom(performative)
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_O_Performative() # type: ignore
+ if msg.is_set("content_o_bool"):
+ performative.content_o_bool_is_set = True
+ content_o_bool = msg.content_o_bool
+ performative.content_o_bool = content_o_bool
+ if msg.is_set("content_o_set_int"):
+ performative.content_o_set_int_is_set = True
+ content_o_set_int = msg.content_o_set_int
+ performative.content_o_set_int.extend(content_o_set_int)
+ if msg.is_set("content_o_list_bytes"):
+ performative.content_o_list_bytes_is_set = True
+ content_o_list_bytes = msg.content_o_list_bytes
+ performative.content_o_list_bytes.extend(content_o_list_bytes)
+ if msg.is_set("content_o_dict_str_int"):
+ performative.content_o_dict_str_int_is_set = True
+ content_o_dict_str_int = msg.content_o_dict_str_int
+ performative.content_o_dict_str_int.update(content_o_dict_str_int)
+ t_protocol_no_ct_msg.performative_o.CopyFrom(performative)
+ elif (
+ performative_id
+ == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
+ ):
+ performative = t_protocol_no_ct_pb2.TProtocolNoCtMessage.Performative_Empty_Contents_Performative() # type: ignore
+ t_protocol_no_ct_msg.performative_empty_contents.CopyFrom(performative)
+ else:
+ raise ValueError("Performative not valid: {}".format(performative_id))
+
+ t_protocol_no_ct_bytes = t_protocol_no_ct_msg.SerializeToString()
+ return t_protocol_no_ct_bytes
+
+ @staticmethod
+ def decode(obj: bytes) -> Message:
+ """
+ Decode bytes into a 'TProtocolNoCt' message.
+
+ :param obj: the bytes object.
+ :return: the 'TProtocolNoCt' message.
+ """
+ t_protocol_no_ct_pb = t_protocol_no_ct_pb2.TProtocolNoCtMessage()
+ t_protocol_no_ct_pb.ParseFromString(obj)
+ message_id = t_protocol_no_ct_pb.message_id
+ dialogue_reference = (
+ t_protocol_no_ct_pb.dialogue_starter_reference,
+ t_protocol_no_ct_pb.dialogue_responder_reference,
+ )
+ target = t_protocol_no_ct_pb.target
+
+ performative = t_protocol_no_ct_pb.WhichOneof("performative")
+ performative_id = TProtocolNoCtMessage.Performative(str(performative))
+ performative_content = dict() # type: Dict[str, Any]
+ if performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PT:
+ content_bytes = t_protocol_no_ct_pb.performative_pt.content_bytes
+ performative_content["content_bytes"] = content_bytes
+ content_int = t_protocol_no_ct_pb.performative_pt.content_int
+ performative_content["content_int"] = content_int
+ content_float = t_protocol_no_ct_pb.performative_pt.content_float
+ performative_content["content_float"] = content_float
+ content_bool = t_protocol_no_ct_pb.performative_pt.content_bool
+ performative_content["content_bool"] = content_bool
+ content_str = t_protocol_no_ct_pb.performative_pt.content_str
+ performative_content["content_str"] = content_str
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PCT:
+ content_set_bytes = t_protocol_no_ct_pb.performative_pct.content_set_bytes
+ content_set_bytes_frozenset = frozenset(content_set_bytes)
+ performative_content["content_set_bytes"] = content_set_bytes_frozenset
+ content_set_int = t_protocol_no_ct_pb.performative_pct.content_set_int
+ content_set_int_frozenset = frozenset(content_set_int)
+ performative_content["content_set_int"] = content_set_int_frozenset
+ content_set_float = t_protocol_no_ct_pb.performative_pct.content_set_float
+ content_set_float_frozenset = frozenset(content_set_float)
+ performative_content["content_set_float"] = content_set_float_frozenset
+ content_set_bool = t_protocol_no_ct_pb.performative_pct.content_set_bool
+ content_set_bool_frozenset = frozenset(content_set_bool)
+ performative_content["content_set_bool"] = content_set_bool_frozenset
+ content_set_str = t_protocol_no_ct_pb.performative_pct.content_set_str
+ content_set_str_frozenset = frozenset(content_set_str)
+ performative_content["content_set_str"] = content_set_str_frozenset
+ content_list_bytes = t_protocol_no_ct_pb.performative_pct.content_list_bytes
+ content_list_bytes_tuple = tuple(content_list_bytes)
+ performative_content["content_list_bytes"] = content_list_bytes_tuple
+ content_list_int = t_protocol_no_ct_pb.performative_pct.content_list_int
+ content_list_int_tuple = tuple(content_list_int)
+ performative_content["content_list_int"] = content_list_int_tuple
+ content_list_float = t_protocol_no_ct_pb.performative_pct.content_list_float
+ content_list_float_tuple = tuple(content_list_float)
+ performative_content["content_list_float"] = content_list_float_tuple
+ content_list_bool = t_protocol_no_ct_pb.performative_pct.content_list_bool
+ content_list_bool_tuple = tuple(content_list_bool)
+ performative_content["content_list_bool"] = content_list_bool_tuple
+ content_list_str = t_protocol_no_ct_pb.performative_pct.content_list_str
+ content_list_str_tuple = tuple(content_list_str)
+ performative_content["content_list_str"] = content_list_str_tuple
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_PMT:
+ content_dict_int_bytes = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_int_bytes
+ )
+ content_dict_int_bytes_dict = dict(content_dict_int_bytes)
+ performative_content["content_dict_int_bytes"] = content_dict_int_bytes_dict
+ content_dict_int_int = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_int_int
+ )
+ content_dict_int_int_dict = dict(content_dict_int_int)
+ performative_content["content_dict_int_int"] = content_dict_int_int_dict
+ content_dict_int_float = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_int_float
+ )
+ content_dict_int_float_dict = dict(content_dict_int_float)
+ performative_content["content_dict_int_float"] = content_dict_int_float_dict
+ content_dict_int_bool = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_int_bool
+ )
+ content_dict_int_bool_dict = dict(content_dict_int_bool)
+ performative_content["content_dict_int_bool"] = content_dict_int_bool_dict
+ content_dict_int_str = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_int_str
+ )
+ content_dict_int_str_dict = dict(content_dict_int_str)
+ performative_content["content_dict_int_str"] = content_dict_int_str_dict
+ content_dict_bool_bytes = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_bool_bytes
+ )
+ content_dict_bool_bytes_dict = dict(content_dict_bool_bytes)
+ performative_content[
+ "content_dict_bool_bytes"
+ ] = content_dict_bool_bytes_dict
+ content_dict_bool_int = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_bool_int
+ )
+ content_dict_bool_int_dict = dict(content_dict_bool_int)
+ performative_content["content_dict_bool_int"] = content_dict_bool_int_dict
+ content_dict_bool_float = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_bool_float
+ )
+ content_dict_bool_float_dict = dict(content_dict_bool_float)
+ performative_content[
+ "content_dict_bool_float"
+ ] = content_dict_bool_float_dict
+ content_dict_bool_bool = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_bool_bool
+ )
+ content_dict_bool_bool_dict = dict(content_dict_bool_bool)
+ performative_content["content_dict_bool_bool"] = content_dict_bool_bool_dict
+ content_dict_bool_str = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_bool_str
+ )
+ content_dict_bool_str_dict = dict(content_dict_bool_str)
+ performative_content["content_dict_bool_str"] = content_dict_bool_str_dict
+ content_dict_str_bytes = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_str_bytes
+ )
+ content_dict_str_bytes_dict = dict(content_dict_str_bytes)
+ performative_content["content_dict_str_bytes"] = content_dict_str_bytes_dict
+ content_dict_str_int = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_str_int
+ )
+ content_dict_str_int_dict = dict(content_dict_str_int)
+ performative_content["content_dict_str_int"] = content_dict_str_int_dict
+ content_dict_str_float = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_str_float
+ )
+ content_dict_str_float_dict = dict(content_dict_str_float)
+ performative_content["content_dict_str_float"] = content_dict_str_float_dict
+ content_dict_str_bool = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_str_bool
+ )
+ content_dict_str_bool_dict = dict(content_dict_str_bool)
+ performative_content["content_dict_str_bool"] = content_dict_str_bool_dict
+ content_dict_str_str = (
+ t_protocol_no_ct_pb.performative_pmt.content_dict_str_str
+ )
+ content_dict_str_str_dict = dict(content_dict_str_str)
+ performative_content["content_dict_str_str"] = content_dict_str_str_dict
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_MT:
+ if t_protocol_no_ct_pb.performative_mt.content_union_1_type_bytes_is_set:
+ content_union_1 = (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_bytes
+ )
+ performative_content["content_union_1"] = content_union_1
+ if t_protocol_no_ct_pb.performative_mt.content_union_1_type_int_is_set:
+ content_union_1 = (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_int
+ )
+ performative_content["content_union_1"] = content_union_1
+ if t_protocol_no_ct_pb.performative_mt.content_union_1_type_float_is_set:
+ content_union_1 = (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_float
+ )
+ performative_content["content_union_1"] = content_union_1
+ if t_protocol_no_ct_pb.performative_mt.content_union_1_type_bool_is_set:
+ content_union_1 = (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_bool
+ )
+ performative_content["content_union_1"] = content_union_1
+ if t_protocol_no_ct_pb.performative_mt.content_union_1_type_str_is_set:
+ content_union_1 = (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_str
+ )
+ performative_content["content_union_1"] = content_union_1
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_set_of_int_is_set
+ ):
+ content_union_1 = t_protocol_no_ct_pb.performative_mt.content_union_1
+ content_union_1_frozenset = frozenset(content_union_1)
+ performative_content["content_union_1"] = content_union_1_frozenset
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_list_of_bool_is_set
+ ):
+ content_union_1 = t_protocol_no_ct_pb.performative_mt.content_union_1
+ content_union_1_tuple = tuple(content_union_1)
+ performative_content["content_union_1"] = content_union_1_tuple
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_1_type_dict_of_str_int_is_set
+ ):
+ content_union_1 = t_protocol_no_ct_pb.performative_mt.content_union_1
+ content_union_1_dict = dict(content_union_1)
+ performative_content["content_union_1"] = content_union_1_dict
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_bytes_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_frozenset = frozenset(content_union_2)
+ performative_content["content_union_2"] = content_union_2_frozenset
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_int_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_frozenset = frozenset(content_union_2)
+ performative_content["content_union_2"] = content_union_2_frozenset
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_set_of_str_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_frozenset = frozenset(content_union_2)
+ performative_content["content_union_2"] = content_union_2_frozenset
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_float_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_tuple = tuple(content_union_2)
+ performative_content["content_union_2"] = content_union_2_tuple
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bool_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_tuple = tuple(content_union_2)
+ performative_content["content_union_2"] = content_union_2_tuple
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_list_of_bytes_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_tuple = tuple(content_union_2)
+ performative_content["content_union_2"] = content_union_2_tuple
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_str_int_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_dict = dict(content_union_2)
+ performative_content["content_union_2"] = content_union_2_dict
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_int_float_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_dict = dict(content_union_2)
+ performative_content["content_union_2"] = content_union_2_dict
+ if (
+ t_protocol_no_ct_pb.performative_mt.content_union_2_type_dict_of_bool_bytes_is_set
+ ):
+ content_union_2 = t_protocol_no_ct_pb.performative_mt.content_union_2
+ content_union_2_dict = dict(content_union_2)
+ performative_content["content_union_2"] = content_union_2_dict
+ elif performative_id == TProtocolNoCtMessage.Performative.PERFORMATIVE_O:
+ if t_protocol_no_ct_pb.performative_o.content_o_bool_is_set:
+ content_o_bool = t_protocol_no_ct_pb.performative_o.content_o_bool
+ performative_content["content_o_bool"] = content_o_bool
+ if t_protocol_no_ct_pb.performative_o.content_o_set_int_is_set:
+ content_o_set_int = t_protocol_no_ct_pb.performative_o.content_o_set_int
+ content_o_set_int_frozenset = frozenset(content_o_set_int)
+ performative_content["content_o_set_int"] = content_o_set_int_frozenset
+ if t_protocol_no_ct_pb.performative_o.content_o_list_bytes_is_set:
+ content_o_list_bytes = (
+ t_protocol_no_ct_pb.performative_o.content_o_list_bytes
+ )
+ content_o_list_bytes_tuple = tuple(content_o_list_bytes)
+ performative_content[
+ "content_o_list_bytes"
+ ] = content_o_list_bytes_tuple
+ if t_protocol_no_ct_pb.performative_o.content_o_dict_str_int_is_set:
+ content_o_dict_str_int = (
+ t_protocol_no_ct_pb.performative_o.content_o_dict_str_int
+ )
+ content_o_dict_str_int_dict = dict(content_o_dict_str_int)
+ performative_content[
+ "content_o_dict_str_int"
+ ] = content_o_dict_str_int_dict
+ elif (
+ performative_id
+ == TProtocolNoCtMessage.Performative.PERFORMATIVE_EMPTY_CONTENTS
+ ):
+ pass
+ else:
+ raise ValueError("Performative not valid: {}.".format(performative_id))
+
+ return TProtocolNoCtMessage(
+ message_id=message_id,
+ dialogue_reference=dialogue_reference,
+ target=target,
+ performative=performative,
+ **performative_content
+ )
diff --git a/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct.proto b/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct.proto
new file mode 100644
index 0000000000..c9a4b9a145
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct.proto
@@ -0,0 +1,94 @@
+syntax = "proto3";
+
+package fetch.aea.TProtocolNoCt;
+
+message TProtocolNoCtMessage{
+
+ // Performatives and contents
+ message Performative_Pt_Performative{
+ bytes content_bytes = 1;
+ int32 content_int = 2;
+ float content_float = 3;
+ bool content_bool = 4;
+ string content_str = 5;
+ }
+
+ message Performative_Pct_Performative{
+ repeated bytes content_set_bytes = 1;
+ repeated int32 content_set_int = 2;
+ repeated float content_set_float = 3;
+ repeated bool content_set_bool = 4;
+ repeated string content_set_str = 5;
+ repeated bytes content_list_bytes = 6;
+ repeated int32 content_list_int = 7;
+ repeated float content_list_float = 8;
+ repeated bool content_list_bool = 9;
+ repeated string content_list_str = 10;
+ }
+
+ message Performative_Pmt_Performative{
+ map content_dict_int_bytes = 1;
+ map content_dict_int_int = 2;
+ map content_dict_int_float = 3;
+ map content_dict_int_bool = 4;
+ map content_dict_int_str = 5;
+ map content_dict_bool_bytes = 6;
+ map content_dict_bool_int = 7;
+ map content_dict_bool_float = 8;
+ map content_dict_bool_bool = 9;
+ map content_dict_bool_str = 10;
+ map content_dict_str_bytes = 11;
+ map content_dict_str_int = 12;
+ map content_dict_str_float = 13;
+ map content_dict_str_bool = 14;
+ map content_dict_str_str = 15;
+ }
+
+ message Performative_Mt_Performative{
+ bytes content_union_1_type_bytes = 1;
+ int32 content_union_1_type_int = 2;
+ float content_union_1_type_float = 3;
+ bool content_union_1_type_bool = 4;
+ string content_union_1_type_str = 5;
+ repeated int32 content_union_1_type_set_of_int = 6;
+ repeated bool content_union_1_type_list_of_bool = 7;
+ map content_union_1_type_dict_of_str_int = 8;
+ repeated bytes content_union_2_type_set_of_bytes = 9;
+ repeated int32 content_union_2_type_set_of_int = 10;
+ repeated string content_union_2_type_set_of_str = 11;
+ repeated float content_union_2_type_list_of_float = 12;
+ repeated bool content_union_2_type_list_of_bool = 13;
+ repeated bytes content_union_2_type_list_of_bytes = 14;
+ map content_union_2_type_dict_of_str_int = 15;
+ map content_union_2_type_dict_of_int_float = 16;
+ map content_union_2_type_dict_of_bool_bytes = 17;
+ }
+
+ message Performative_O_Performative{
+ bool content_o_bool = 1;
+ bool content_o_bool_is_set = 2;
+ repeated int32 content_o_set_int = 3;
+ bool content_o_set_int_is_set = 4;
+ repeated bytes content_o_list_bytes = 5;
+ bool content_o_list_bytes_is_set = 6;
+ map content_o_dict_str_int = 7;
+ bool content_o_dict_str_int_is_set = 8;
+ }
+
+ message Performative_Empty_Contents_Performative{}
+
+
+ // Standard TProtocolNoCtMessage fields
+ int32 message_id = 1;
+ string dialogue_starter_reference = 2;
+ string dialogue_responder_reference = 3;
+ int32 target = 4;
+ oneof performative{
+ Performative_Empty_Contents_Performative performative_empty_contents = 5;
+ Performative_Mt_Performative performative_mt = 6;
+ Performative_O_Performative performative_o = 7;
+ Performative_Pct_Performative performative_pct = 8;
+ Performative_Pmt_Performative performative_pmt = 9;
+ Performative_Pt_Performative performative_pt = 10;
+ }
+}
diff --git a/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct_pb2.py b/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct_pb2.py
new file mode 100644
index 0000000000..c018654cf4
--- /dev/null
+++ b/tests/data/generator/t_protocol_no_ct/t_protocol_no_ct_pb2.py
@@ -0,0 +1,3090 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: t_protocol_no_ct.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name="t_protocol_no_ct.proto",
+ package="fetch.aea.TProtocolNoCt",
+ syntax="proto3",
+ serialized_options=None,
+ serialized_pb=b'\n\x16t_protocol_no_ct.proto\x12\x17\x66\x65tch.aea.TProtocolNoCt"\xef/\n\x14TProtocolNoCtMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12}\n\x1bperformative_empty_contents\x18\x05 \x01(\x0b\x32V.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Empty_Contents_PerformativeH\x00\x12\x65\n\x0fperformative_mt\x18\x06 \x01(\x0b\x32J.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_PerformativeH\x00\x12\x63\n\x0eperformative_o\x18\x07 \x01(\x0b\x32I.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_PerformativeH\x00\x12g\n\x10performative_pct\x18\x08 \x01(\x0b\x32K.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_PerformativeH\x00\x12g\n\x10performative_pmt\x18\t \x01(\x0b\x32K.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_PerformativeH\x00\x12\x65\n\x0fperformative_pt\x18\n \x01(\x0b\x32J.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_PerformativeH\x00\x1a\x8c\x01\n\x1cPerformative_Pt_Performative\x12\x15\n\rcontent_bytes\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontent_int\x18\x02 \x01(\x05\x12\x15\n\rcontent_float\x18\x03 \x01(\x02\x12\x14\n\x0c\x63ontent_bool\x18\x04 \x01(\x08\x12\x13\n\x0b\x63ontent_str\x18\x05 \x01(\t\x1a\xa8\x02\n\x1dPerformative_Pct_Performative\x12\x19\n\x11\x63ontent_set_bytes\x18\x01 \x03(\x0c\x12\x17\n\x0f\x63ontent_set_int\x18\x02 \x03(\x05\x12\x19\n\x11\x63ontent_set_float\x18\x03 \x03(\x02\x12\x18\n\x10\x63ontent_set_bool\x18\x04 \x03(\x08\x12\x17\n\x0f\x63ontent_set_str\x18\x05 \x03(\t\x12\x1a\n\x12\x63ontent_list_bytes\x18\x06 \x03(\x0c\x12\x18\n\x10\x63ontent_list_int\x18\x07 \x03(\x05\x12\x1a\n\x12\x63ontent_list_float\x18\x08 \x03(\x02\x12\x19\n\x11\x63ontent_list_bool\x18\t \x03(\x08\x12\x18\n\x10\x63ontent_list_str\x18\n \x03(\t\x1a\xee\x16\n\x1dPerformative_Pmt_Performative\x12\x84\x01\n\x16\x63ontent_dict_int_bytes\x18\x01 \x03(\x0b\x32\x64.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry\x12\x80\x01\n\x14\x63ontent_dict_int_int\x18\x02 \x03(\x0b\x32\x62.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry\x12\x84\x01\n\x16\x63ontent_dict_int_float\x18\x03 \x03(\x0b\x32\x64.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry\x12\x82\x01\n\x15\x63ontent_dict_int_bool\x18\x04 \x03(\x0b\x32\x63.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry\x12\x80\x01\n\x14\x63ontent_dict_int_str\x18\x05 \x03(\x0b\x32\x62.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry\x12\x86\x01\n\x17\x63ontent_dict_bool_bytes\x18\x06 \x03(\x0b\x32\x65.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry\x12\x82\x01\n\x15\x63ontent_dict_bool_int\x18\x07 \x03(\x0b\x32\x63.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry\x12\x86\x01\n\x17\x63ontent_dict_bool_float\x18\x08 \x03(\x0b\x32\x65.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry\x12\x84\x01\n\x16\x63ontent_dict_bool_bool\x18\t \x03(\x0b\x32\x64.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry\x12\x82\x01\n\x15\x63ontent_dict_bool_str\x18\n \x03(\x0b\x32\x63.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry\x12\x84\x01\n\x16\x63ontent_dict_str_bytes\x18\x0b \x03(\x0b\x32\x64.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry\x12\x80\x01\n\x14\x63ontent_dict_str_int\x18\x0c \x03(\x0b\x32\x62.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry\x12\x84\x01\n\x16\x63ontent_dict_str_float\x18\r \x03(\x0b\x32\x64.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry\x12\x82\x01\n\x15\x63ontent_dict_str_bool\x18\x0e \x03(\x0b\x32\x63.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry\x12\x80\x01\n\x14\x63ontent_dict_str_str\x18\x0f \x03(\x0b\x32\x62.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry\x1a:\n\x18\x43ontentDictIntBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictIntIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a:\n\x18\x43ontentDictIntFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictIntBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictIntStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a;\n\x19\x43ontentDictBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictBoolIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a;\n\x19\x43ontentDictBoolFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a:\n\x18\x43ontentDictBoolBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictBoolStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a:\n\x18\x43ontentDictStrBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a:\n\x18\x43ontentDictStrFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1a\x39\n\x17\x43ontentDictStrBoolEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01\x1a\x38\n\x16\x43ontentDictStrStrEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\xc0\x0b\n\x1cPerformative_Mt_Performative\x12"\n\x1a\x63ontent_union_1_type_bytes\x18\x01 \x01(\x0c\x12 \n\x18\x63ontent_union_1_type_int\x18\x02 \x01(\x05\x12"\n\x1a\x63ontent_union_1_type_float\x18\x03 \x01(\x02\x12!\n\x19\x63ontent_union_1_type_bool\x18\x04 \x01(\x08\x12 \n\x18\x63ontent_union_1_type_str\x18\x05 \x01(\t\x12\'\n\x1f\x63ontent_union_1_type_set_of_int\x18\x06 \x03(\x05\x12)\n!content_union_1_type_list_of_bool\x18\x07 \x03(\x08\x12\x9b\x01\n$content_union_1_type_dict_of_str_int\x18\x08 \x03(\x0b\x32m.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry\x12)\n!content_union_2_type_set_of_bytes\x18\t \x03(\x0c\x12\'\n\x1f\x63ontent_union_2_type_set_of_int\x18\n \x03(\x05\x12\'\n\x1f\x63ontent_union_2_type_set_of_str\x18\x0b \x03(\t\x12*\n"content_union_2_type_list_of_float\x18\x0c \x03(\x02\x12)\n!content_union_2_type_list_of_bool\x18\r \x03(\x08\x12*\n"content_union_2_type_list_of_bytes\x18\x0e \x03(\x0c\x12\x9b\x01\n$content_union_2_type_dict_of_str_int\x18\x0f \x03(\x0b\x32m.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry\x12\x9f\x01\n&content_union_2_type_dict_of_int_float\x18\x10 \x03(\x0b\x32o.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry\x12\xa1\x01\n\'content_union_2_type_dict_of_bool_bytes\x18\x11 \x03(\x0b\x32p.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry\x1a\x44\n"ContentUnion1TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x44\n"ContentUnion2TypeDictOfStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a\x46\n$ContentUnion2TypeDictOfIntFloatEntry\x12\x0b\n\x03key\x18\x01 \x01(\x05\x12\r\n\x05value\x18\x02 \x01(\x02:\x02\x38\x01\x1aG\n%ContentUnion2TypeDictOfBoolBytesEntry\x12\x0b\n\x03key\x18\x01 \x01(\x08\x12\r\n\x05value\x18\x02 \x01(\x0c:\x02\x38\x01\x1a\xba\x03\n\x1bPerformative_O_Performative\x12\x16\n\x0e\x63ontent_o_bool\x18\x01 \x01(\x08\x12\x1d\n\x15\x63ontent_o_bool_is_set\x18\x02 \x01(\x08\x12\x19\n\x11\x63ontent_o_set_int\x18\x03 \x03(\x05\x12 \n\x18\x63ontent_o_set_int_is_set\x18\x04 \x01(\x08\x12\x1c\n\x14\x63ontent_o_list_bytes\x18\x05 \x03(\x0c\x12#\n\x1b\x63ontent_o_list_bytes_is_set\x18\x06 \x01(\x08\x12\x81\x01\n\x16\x63ontent_o_dict_str_int\x18\x07 \x03(\x0b\x32\x61.fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry\x12%\n\x1d\x63ontent_o_dict_str_int_is_set\x18\x08 \x01(\x08\x1a\x39\n\x17\x43ontentODictStrIntEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a*\n(Performative_Empty_Contents_PerformativeB\x0e\n\x0cperformativeb\x06proto3',
+)
+
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Pt_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative.content_bytes",
+ index=0,
+ number=1,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative.content_int",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative.content_float",
+ index=2,
+ number=3,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative.content_bool",
+ index=3,
+ number=4,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative.content_str",
+ index=4,
+ number=5,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=831,
+ serialized_end=971,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Pct_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_set_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_set_bytes",
+ index=0,
+ number=1,
+ type=12,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_set_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_set_int",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_set_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_set_float",
+ index=2,
+ number=3,
+ type=2,
+ cpp_type=6,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_set_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_set_bool",
+ index=3,
+ number=4,
+ type=8,
+ cpp_type=7,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_set_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_set_str",
+ index=4,
+ number=5,
+ type=9,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_list_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_list_bytes",
+ index=5,
+ number=6,
+ type=12,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_list_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_list_int",
+ index=6,
+ number=7,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_list_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_list_float",
+ index=7,
+ number=8,
+ type=2,
+ cpp_type=6,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_list_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_list_bool",
+ index=8,
+ number=9,
+ type=8,
+ cpp_type=7,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_list_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative.content_list_str",
+ index=9,
+ number=10,
+ type=9,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=974,
+ serialized_end=1270,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictIntBytesEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3311,
+ serialized_end=3369,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY = _descriptor.Descriptor(
+ name="ContentDictIntIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3371,
+ serialized_end=3427,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictIntFloatEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3429,
+ serialized_end=3487,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictIntBoolEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry.value",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3489,
+ serialized_end=3546,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictIntStrEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry.value",
+ index=1,
+ number=2,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3548,
+ serialized_end=3604,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolBytesEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3606,
+ serialized_end=3665,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3667,
+ serialized_end=3724,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolFloatEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3726,
+ serialized_end=3785,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolBoolEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry.value",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3787,
+ serialized_end=3845,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictBoolStrEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry.value",
+ index=1,
+ number=2,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3847,
+ serialized_end=3904,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY = _descriptor.Descriptor(
+ name="ContentDictStrBytesEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3906,
+ serialized_end=3964,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentDictStrIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=3966,
+ serialized_end=4022,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY = _descriptor.Descriptor(
+ name="ContentDictStrFloatEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4024,
+ serialized_end=4082,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY = _descriptor.Descriptor(
+ name="ContentDictStrBoolEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry.value",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4084,
+ serialized_end=4141,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY = _descriptor.Descriptor(
+ name="ContentDictStrStrEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry.value",
+ index=1,
+ number=2,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4143,
+ serialized_end=4199,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Pmt_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_int_bytes",
+ index=0,
+ number=1,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_int_int",
+ index=1,
+ number=2,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_int_float",
+ index=2,
+ number=3,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_int_bool",
+ index=3,
+ number=4,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_int_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_int_str",
+ index=4,
+ number=5,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_bool_bytes",
+ index=5,
+ number=6,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_bool_int",
+ index=6,
+ number=7,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_bool_float",
+ index=7,
+ number=8,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_bool_bool",
+ index=8,
+ number=9,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_bool_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_bool_str",
+ index=9,
+ number=10,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_str_bytes",
+ index=10,
+ number=11,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_str_int",
+ index=11,
+ number=12,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_str_float",
+ index=12,
+ number=13,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_str_bool",
+ index=13,
+ number=14,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_dict_str_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.content_dict_str_str",
+ index=14,
+ number=15,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,
+ ],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=1273,
+ serialized_end=4199,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentUnion1TypeDictOfStrIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5391,
+ serialized_end=5459,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfStrIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5461,
+ serialized_end=5529,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfIntFloatEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.key",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry.value",
+ index=1,
+ number=2,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5531,
+ serialized_end=5601,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY = _descriptor.Descriptor(
+ name="ContentUnion2TypeDictOfBoolBytesEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.key",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry.value",
+ index=1,
+ number=2,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5603,
+ serialized_end=5674,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Mt_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_bytes",
+ index=0,
+ number=1,
+ type=12,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"",
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_int",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_float",
+ index=2,
+ number=3,
+ type=2,
+ cpp_type=6,
+ label=1,
+ has_default_value=False,
+ default_value=float(0),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_bool",
+ index=3,
+ number=4,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_str",
+ index=4,
+ number=5,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_set_of_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_set_of_int",
+ index=5,
+ number=6,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_list_of_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_list_of_bool",
+ index=6,
+ number=7,
+ type=8,
+ cpp_type=7,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_1_type_dict_of_str_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_1_type_dict_of_str_int",
+ index=7,
+ number=8,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_set_of_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_set_of_bytes",
+ index=8,
+ number=9,
+ type=12,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_set_of_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_set_of_int",
+ index=9,
+ number=10,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_set_of_str",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_set_of_str",
+ index=10,
+ number=11,
+ type=9,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_list_of_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_list_of_float",
+ index=11,
+ number=12,
+ type=2,
+ cpp_type=6,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_list_of_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_list_of_bool",
+ index=12,
+ number=13,
+ type=8,
+ cpp_type=7,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_list_of_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_list_of_bytes",
+ index=13,
+ number=14,
+ type=12,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_dict_of_str_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_dict_of_str_int",
+ index=14,
+ number=15,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_dict_of_int_float",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_dict_of_int_float",
+ index=15,
+ number=16,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_union_2_type_dict_of_bool_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.content_union_2_type_dict_of_bool_bytes",
+ index=16,
+ number=17,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
+ ],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=4202,
+ serialized_end=5674,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY = _descriptor.Descriptor(
+ name="ContentODictStrIntEntry",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="key",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry.key",
+ index=0,
+ number=1,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="value",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry.value",
+ index=1,
+ number=2,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=b"8\001",
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=6062,
+ serialized_end=6119,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_O_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="content_o_bool",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_bool",
+ index=0,
+ number=1,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_bool_is_set",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_bool_is_set",
+ index=1,
+ number=2,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_set_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_set_int",
+ index=2,
+ number=3,
+ type=5,
+ cpp_type=1,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_set_int_is_set",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_set_int_is_set",
+ index=3,
+ number=4,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_list_bytes",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_list_bytes",
+ index=4,
+ number=5,
+ type=12,
+ cpp_type=9,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_list_bytes_is_set",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_list_bytes_is_set",
+ index=5,
+ number=6,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_dict_str_int",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_dict_str_int",
+ index=6,
+ number=7,
+ type=11,
+ cpp_type=10,
+ label=3,
+ has_default_value=False,
+ default_value=[],
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="content_o_dict_str_int_is_set",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.content_o_dict_str_int_is_set",
+ index=7,
+ number=8,
+ type=8,
+ cpp_type=7,
+ label=1,
+ has_default_value=False,
+ default_value=False,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,
+ ],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=5677,
+ serialized_end=6119,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE = _descriptor.Descriptor(
+ name="Performative_Empty_Contents_Performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Empty_Contents_Performative",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[],
+ extensions=[],
+ nested_types=[],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[],
+ serialized_start=6121,
+ serialized_end=6163,
+)
+
+_TPROTOCOLNOCTMESSAGE = _descriptor.Descriptor(
+ name="TProtocolNoCtMessage",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage",
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name="message_id",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.message_id",
+ index=0,
+ number=1,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="dialogue_starter_reference",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.dialogue_starter_reference",
+ index=1,
+ number=2,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="dialogue_responder_reference",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.dialogue_responder_reference",
+ index=2,
+ number=3,
+ type=9,
+ cpp_type=9,
+ label=1,
+ has_default_value=False,
+ default_value=b"".decode("utf-8"),
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="target",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.target",
+ index=3,
+ number=4,
+ type=5,
+ cpp_type=1,
+ label=1,
+ has_default_value=False,
+ default_value=0,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_empty_contents",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_empty_contents",
+ index=4,
+ number=5,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_mt",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_mt",
+ index=5,
+ number=6,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_o",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_o",
+ index=6,
+ number=7,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_pct",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_pct",
+ index=7,
+ number=8,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_pmt",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_pmt",
+ index=8,
+ number=9,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ _descriptor.FieldDescriptor(
+ name="performative_pt",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative_pt",
+ index=9,
+ number=10,
+ type=11,
+ cpp_type=10,
+ label=1,
+ has_default_value=False,
+ default_value=None,
+ message_type=None,
+ enum_type=None,
+ containing_type=None,
+ is_extension=False,
+ extension_scope=None,
+ serialized_options=None,
+ file=DESCRIPTOR,
+ ),
+ ],
+ extensions=[],
+ nested_types=[
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE,
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,
+ ],
+ enum_types=[],
+ serialized_options=None,
+ is_extendable=False,
+ syntax="proto3",
+ extension_ranges=[],
+ oneofs=[
+ _descriptor.OneofDescriptor(
+ name="performative",
+ full_name="fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.performative",
+ index=0,
+ containing_type=None,
+ fields=[],
+ ),
+ ],
+ serialized_start=52,
+ serialized_end=6179,
+)
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_bytes"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_int"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_float"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_bool"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_int_str"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_bytes"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_int"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_float"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_bool"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_bool_str"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_bytes"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_int"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_float"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_bool"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.fields_by_name[
+ "content_dict_str_str"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.fields_by_name[
+ "content_union_1_type_dict_of_str_int"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.fields_by_name[
+ "content_union_2_type_dict_of_str_int"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.fields_by_name[
+ "content_union_2_type_dict_of_int_float"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.fields_by_name[
+ "content_union_2_type_dict_of_bool_bytes"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY.containing_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE.fields_by_name[
+ "content_o_dict_str_int"
+].message_type = (
+ _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE.containing_type = (
+ _TPROTOCOLNOCTMESSAGE
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_empty_contents"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_mt"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_o"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pct"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pmt"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pt"
+].message_type = _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_empty_contents"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_empty_contents"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_mt"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_mt"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_o"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_o"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_pct"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pct"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_pmt"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pmt"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+_TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"].fields.append(
+ _TPROTOCOLNOCTMESSAGE.fields_by_name["performative_pt"]
+)
+_TPROTOCOLNOCTMESSAGE.fields_by_name[
+ "performative_pt"
+].containing_oneof = _TPROTOCOLNOCTMESSAGE.oneofs_by_name["performative"]
+DESCRIPTOR.message_types_by_name["TProtocolNoCtMessage"] = _TPROTOCOLNOCTMESSAGE
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TProtocolNoCtMessage = _reflection.GeneratedProtocolMessageType(
+ "TProtocolNoCtMessage",
+ (_message.Message,),
+ {
+ "Performative_Pt_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_Pt_Performative",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PT_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pt_Performative)
+ },
+ ),
+ "Performative_Pct_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_Pct_Performative",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PCT_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pct_Performative)
+ },
+ ),
+ "Performative_Pmt_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_Pmt_Performative",
+ (_message.Message,),
+ {
+ "ContentDictIntBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry)
+ },
+ ),
+ "ContentDictIntIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry)
+ },
+ ),
+ "ContentDictIntFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry)
+ },
+ ),
+ "ContentDictIntBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry)
+ },
+ ),
+ "ContentDictIntStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictIntStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry)
+ },
+ ),
+ "ContentDictBoolBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry)
+ },
+ ),
+ "ContentDictBoolIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry)
+ },
+ ),
+ "ContentDictBoolFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry)
+ },
+ ),
+ "ContentDictBoolBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry)
+ },
+ ),
+ "ContentDictBoolStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictBoolStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry)
+ },
+ ),
+ "ContentDictStrBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry)
+ },
+ ),
+ "ContentDictStrIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry)
+ },
+ ),
+ "ContentDictStrFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry)
+ },
+ ),
+ "ContentDictStrBoolEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrBoolEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry)
+ },
+ ),
+ "ContentDictStrStrEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentDictStrStrEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry)
+ },
+ ),
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Pmt_Performative)
+ },
+ ),
+ "Performative_Mt_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_Mt_Performative",
+ (_message.Message,),
+ {
+ "ContentUnion1TypeDictOfStrIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentUnion1TypeDictOfStrIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry)
+ },
+ ),
+ "ContentUnion2TypeDictOfStrIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfStrIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry)
+ },
+ ),
+ "ContentUnion2TypeDictOfIntFloatEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfIntFloatEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry)
+ },
+ ),
+ "ContentUnion2TypeDictOfBoolBytesEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentUnion2TypeDictOfBoolBytesEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry)
+ },
+ ),
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Mt_Performative)
+ },
+ ),
+ "Performative_O_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_O_Performative",
+ (_message.Message,),
+ {
+ "ContentODictStrIntEntry": _reflection.GeneratedProtocolMessageType(
+ "ContentODictStrIntEntry",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry)
+ },
+ ),
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_O_Performative)
+ },
+ ),
+ "Performative_Empty_Contents_Performative": _reflection.GeneratedProtocolMessageType(
+ "Performative_Empty_Contents_Performative",
+ (_message.Message,),
+ {
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE_PERFORMATIVE_EMPTY_CONTENTS_PERFORMATIVE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage.Performative_Empty_Contents_Performative)
+ },
+ ),
+ "DESCRIPTOR": _TPROTOCOLNOCTMESSAGE,
+ "__module__": "t_protocol_no_ct_pb2"
+ # @@protoc_insertion_point(class_scope:fetch.aea.TProtocolNoCt.TProtocolNoCtMessage)
+ },
+)
+_sym_db.RegisterMessage(TProtocolNoCtMessage)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pt_Performative)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pct_Performative)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Pmt_Performative)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBytesEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictIntStrEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBytesEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictBoolStrEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBytesEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrBoolEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Pmt_Performative.ContentDictStrStrEntry
+)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Mt_Performative)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion1TypeDictOfStrIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfStrIntEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfIntFloatEntry
+)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_Mt_Performative.ContentUnion2TypeDictOfBoolBytesEntry
+)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_O_Performative)
+_sym_db.RegisterMessage(
+ TProtocolNoCtMessage.Performative_O_Performative.ContentODictStrIntEntry
+)
+_sym_db.RegisterMessage(TProtocolNoCtMessage.Performative_Empty_Contents_Performative)
+
+
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBYTESENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTINTENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTFLOATENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTBOOLENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTINTSTRENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBYTESENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLINTENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLFLOATENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLBOOLENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTBOOLSTRENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBYTESENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRINTENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRFLOATENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRBOOLENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_PMT_PERFORMATIVE_CONTENTDICTSTRSTRENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION1TYPEDICTOFSTRINTENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFSTRINTENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFINTFLOATENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_MT_PERFORMATIVE_CONTENTUNION2TYPEDICTOFBOOLBYTESENTRY._options = (
+ None
+)
+_TPROTOCOLNOCTMESSAGE_PERFORMATIVE_O_PERFORMATIVE_CONTENTODICTSTRINTENTRY._options = (
+ None
+)
+# @@protoc_insertion_point(module_scope)
diff --git a/tests/data/gym-connection.yaml b/tests/data/gym-connection.yaml
index 4a35e327b0..847f473ba5 100644
--- a/tests/data/gym-connection.yaml
+++ b/tests/data/gym-connection.yaml
@@ -8,8 +8,8 @@ fingerprint:
aea_version: '>=0.5.0, <0.6.0'
description: "The gym connection wraps an OpenAI gym."
class_name: GymConnection
-protocols: ["fetchai/gym:0.3.0"]
-restricted_to_protocols: ["fetchai/gym:0.3.0"]
+protocols: ["fetchai/gym:0.4.0"]
+restricted_to_protocols: ["fetchai/gym:0.4.0"]
excluded_protocols: []
config:
env: 'gyms.env.BanditNArmedRandom'
diff --git a/tests/data/hashes.csv b/tests/data/hashes.csv
index 194769981f..60bacd1190 100644
--- a/tests/data/hashes.csv
+++ b/tests/data/hashes.csv
@@ -1,6 +1,6 @@
-dummy_author/agents/dummy_aea,QmTfa3sBgLbnpD7DJuzVmqcSebnAsxqL1cndSYsskJANvt
-dummy_author/skills/dummy_skill,Qme2ehYviSzGVKNZfS5N7A7Jayd7QJ4nn9EEnXdVrL231X
-fetchai/connections/dummy_connection,QmVAEYzswDE7CxEKQpz51f8GV7UVm7WE6AHZGqWj9QMMUK
+dummy_author/agents/dummy_aea,QmR4SuPKbe4qjgF5DVwVwHPm5eFqCx83sdavs4QEXgF1mR
+dummy_author/skills/dummy_skill,QmZFoPjg3byuvLSbpdGDzu9n7U31LMwg8idtPuk26izFPX
+fetchai/connections/dummy_connection,QmRLdNwog7rx8hrYG5DGu35BNZt2782ZMxGJXjfjJy3D4d
fetchai/contracts/dummy_contract,QmTBc9MJrKa66iRmvfHKpR1xmT6P5cGML5S5RUsW6yVwbm
-fetchai/skills/dependencies_skill,Qmasrc9nMApq7qZYU8n78n5K2DKzY2TUZWp9pYfzcRRmoP
+fetchai/skills/dependencies_skill,QmZzuuX3HbpuY4niyqFp3b5jq4tmUokXknf3iyKtRo8Y7N
fetchai/skills/exception_skill,QmWXXnoHarx7WLhuFuzdas2Pe1WCprS4sDkdaPH1w4kTo2
diff --git a/tests/data/sample_specification.yaml b/tests/data/sample_specification.yaml
index 18963861b1..8ee1b65289 100644
--- a/tests/data/sample_specification.yaml
+++ b/tests/data/sample_specification.yaml
@@ -1,3 +1,4 @@
+---
name: t_protocol
author: fetchai
version: 0.1.0
@@ -27,23 +28,49 @@ speech_acts:
content_list_bool: pt:list[pt:bool]
content_list_str: pt:list[pt:str]
performative_pmt:
-# content_dict_int_ct: pt:dict[pt:int, ct:DataModel] # custom type inside of set, list, and dict isn't allowed.
+# custom type inside of set, list, and dict isn't allowed.
+# content_dict_int_ct: pt:dict[pt:int, ct:DataModel]
+# content_dict_ct_ct: pt:dict[ct:DataModel, ct:DataModel]
+# invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
+# content_dict_bytes_bytes: pt:dict[pt:bytes, pt:bytes]
+# content_dict_bytes_int: pt:dict[pt:bytes, pt:int]
+# content_dict_bytes_float: pt:dict[pt:bytes, pt:float]
+# content_dict_bytes_bool: pt:dict[pt:bytes, pt:bool]
+# content_dict_bytes_str: pt:dict[pt:bytes, pt:str]
+ content_dict_int_bytes: pt:dict[pt:int, pt:bytes]
+ content_dict_int_int: pt:dict[pt:int, pt:int]
+ content_dict_int_float: pt:dict[pt:int, pt:float]
+ content_dict_int_bool: pt:dict[pt:int, pt:bool]
+ content_dict_int_str: pt:dict[pt:int, pt:str]
+# invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
+# content_dict_float_bytes: pt:dict[pt:int, pt:bytes]
+# content_dict_float_int: pt:dict[pt:int, pt:int]
+# content_dict_float_float: pt:dict[pt:int, pt:float]
+# content_dict_float_bool: pt:dict[pt:int, pt:bool]
+# content_dict_float_str: pt:dict[pt:int, pt:str]
content_dict_bool_bytes: pt:dict[pt:bool, pt:bytes]
+ content_dict_bool_int: pt:dict[pt:bool, pt:int]
+ content_dict_bool_float: pt:dict[pt:bool, pt:float]
+ content_dict_bool_bool: pt:dict[pt:bool, pt:bool]
+ content_dict_bool_str: pt:dict[pt:bool, pt:str]
+ content_dict_str_bytes: pt:dict[pt:str, pt:bytes]
+ content_dict_str_int: pt:dict[pt:str, pt:int]
content_dict_str_float: pt:dict[pt:str, pt:float]
-# content_dict_ct_ct: pt:dict[ct:DataModel, ct:DataModel] # invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
-# content_dict_bytes_int: pt:dict[pt:bytes, pt:int] # invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
-# content_dict_float_int: pt:dict[pt:float, pt:int] # invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
+ content_dict_str_bool: pt:dict[pt:str, pt:bool]
+ content_dict_str_str: pt:dict[pt:str, pt:str]
performative_mt:
content_union_1: pt:union[ct:DataModel, pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str, pt:int]]
content_union_2: pt:union[pt:set[pt:bytes], pt:set[pt:int], pt:set[pt:str], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:bool, pt:bytes]]
performative_o:
content_o_ct: pt:optional[ct:DataModel]
content_o_bool: pt:optional[pt:bool]
- content_o_set_float: pt:optional[pt:set[pt:float]]
+ content_o_set_int: pt:optional[pt:set[pt:int]]
content_o_list_bytes: pt:optional[pt:list[pt:bytes]]
content_o_dict_str_int: pt:optional[pt:dict[pt:str, pt:int]]
- content_o_union: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:int], pt:set[pt:int], pt:set[pt:bytes], pt:list[pt:bool], pt:dict[pt:str, pt:float]]]
+# union does not work properly in the generator
+# content_o_union: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:int], pt:set[pt:int], pt:set[pt:bytes], pt:list[pt:bool], pt:dict[pt:str, pt:float]]]
performative_empty_contents: {}
+...
---
ct:DataModel: |
bytes bytes_field = 1;
@@ -54,3 +81,18 @@ ct:DataModel: |
repeated int32 set_field = 6;
repeated string list_field = 7;
map dict_field = 8;
+...
+---
+initiation: [performative_ct, performative_pt]
+reply:
+ performative_ct: [performative_pct]
+ performative_pt: [performative_pmt]
+ performative_pct: [performative_mt, performative_o]
+ performative_pmt: [performative_mt, performative_o]
+ performative_mt: []
+ performative_o: []
+ performative_empty_contents: [performative_empty_contents]
+termination: [performative_mt, performative_o, performative_empty_contents]
+roles: {role_1, role_2}
+end_states: [end_state_1, end_state_2, end_state_3]
+...
diff --git a/tests/data/sample_specification_no_custom_types.yaml b/tests/data/sample_specification_no_custom_types.yaml
new file mode 100644
index 0000000000..a5ef48863d
--- /dev/null
+++ b/tests/data/sample_specification_no_custom_types.yaml
@@ -0,0 +1,85 @@
+---
+name: t_protocol_no_ct
+author: fetchai
+version: 0.1.0
+license: Apache-2.0
+aea_version: '>=0.5.0, <0.6.0'
+description: 'A protocol for testing purposes.'
+speech_acts:
+ performative_pt:
+ content_bytes: pt:bytes
+ content_int: pt:int
+ content_float: pt:float
+ content_bool: pt:bool
+ content_str: pt:str
+ performative_pct:
+# content_set_ct: pt:set[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.
+ content_set_bytes: pt:set[pt:bytes]
+ content_set_int: pt:set[pt:int]
+ content_set_float: pt:set[pt:float]
+ content_set_bool: pt:set[pt:bool]
+ content_set_str: pt:set[pt:str]
+# content_list_ct: pt:list[ct:DataModel] # custom type inside of set, list, and dict isn't allowed.
+ content_list_bytes: pt:list[pt:bytes]
+ content_list_int: pt:list[pt:int]
+ content_list_float: pt:list[pt:float]
+ content_list_bool: pt:list[pt:bool]
+ content_list_str: pt:list[pt:str]
+ performative_pmt:
+# custom type inside of set, list, and dict isn't allowed.
+# content_dict_int_ct: pt:dict[pt:int, ct:DataModel]
+# content_dict_ct_ct: pt:dict[ct:DataModel, ct:DataModel]
+# invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
+# content_dict_bytes_bytes: pt:dict[pt:bytes, pt:bytes]
+# content_dict_bytes_int: pt:dict[pt:bytes, pt:int]
+# content_dict_bytes_float: pt:dict[pt:bytes, pt:float]
+# content_dict_bytes_bool: pt:dict[pt:bytes, pt:bool]
+# content_dict_bytes_str: pt:dict[pt:bytes, pt:str]
+ content_dict_int_bytes: pt:dict[pt:int, pt:bytes]
+ content_dict_int_int: pt:dict[pt:int, pt:int]
+ content_dict_int_float: pt:dict[pt:int, pt:float]
+ content_dict_int_bool: pt:dict[pt:int, pt:bool]
+ content_dict_int_str: pt:dict[pt:int, pt:str]
+# invalid in protobuf (key in map cannot be 'bytes', 'float', 'double', 'message')
+# content_dict_float_bytes: pt:dict[pt:int, pt:bytes]
+# content_dict_float_int: pt:dict[pt:int, pt:int]
+# content_dict_float_float: pt:dict[pt:int, pt:float]
+# content_dict_float_bool: pt:dict[pt:int, pt:bool]
+# content_dict_float_str: pt:dict[pt:int, pt:str]
+ content_dict_bool_bytes: pt:dict[pt:bool, pt:bytes]
+ content_dict_bool_int: pt:dict[pt:bool, pt:int]
+ content_dict_bool_float: pt:dict[pt:bool, pt:float]
+ content_dict_bool_bool: pt:dict[pt:bool, pt:bool]
+ content_dict_bool_str: pt:dict[pt:bool, pt:str]
+ content_dict_str_bytes: pt:dict[pt:str, pt:bytes]
+ content_dict_str_int: pt:dict[pt:str, pt:int]
+ content_dict_str_float: pt:dict[pt:str, pt:float]
+ content_dict_str_bool: pt:dict[pt:str, pt:bool]
+ content_dict_str_str: pt:dict[pt:str, pt:str]
+ performative_mt:
+ content_union_1: pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str, pt:int]]
+ content_union_2: pt:union[pt:set[pt:bytes], pt:set[pt:int], pt:set[pt:str], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:bool, pt:bytes]]
+ performative_o:
+ content_o_bool: pt:optional[pt:bool]
+ content_o_set_int: pt:optional[pt:set[pt:int]]
+ content_o_list_bytes: pt:optional[pt:list[pt:bytes]]
+ content_o_dict_str_int: pt:optional[pt:dict[pt:str, pt:int]]
+# union does not work properly in the generator
+# content_o_union: pt:optional[pt:union[pt:str, pt:dict[pt:str,pt:int], pt:set[pt:int], pt:set[pt:bytes], pt:list[pt:bool], pt:dict[pt:str, pt:float]]]
+ performative_empty_contents: {}
+...
+---
+...
+---
+initiation: [performative_pt]
+reply:
+ performative_pt: [performative_pct, performative_pmt]
+ performative_pct: [performative_mt, performative_o]
+ performative_pmt: [performative_mt, performative_o]
+ performative_mt: []
+ performative_o: []
+ performative_empty_contents: [performative_empty_contents]
+termination: [performative_mt, performative_o, performative_empty_contents]
+roles: {role_1, role_2}
+end_states: [end_state_1, end_state_2, end_state_3]
+...
diff --git a/tests/test_aea.py b/tests/test_aea.py
index 47313dd400..abedcf596e 100644
--- a/tests/test_aea.py
+++ b/tests/test_aea.py
@@ -16,11 +16,13 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
"""This module contains the tests for aea/aea.py."""
-import logging
import os
import tempfile
+import time
from pathlib import Path
+from threading import Thread
from unittest.mock import patch
from aea import AEA_DIR
@@ -52,7 +54,7 @@
from .data.dummy_skill.behaviours import DummyBehaviour # type: ignore
-def test_initialise_aea():
+def test_setup_aea():
"""Tests the initialisation of the AEA."""
private_key_path = os.path.join(CUR_PATH, "data", DEFAULT_PRIVATE_KEY_FILE)
builder = AEABuilder()
@@ -71,7 +73,7 @@ def test_initialise_aea():
), "Shared state must not be None after set"
assert my_AEA.context.task_manager is not None
assert my_AEA.context.identity is not None, "Identity must not be None after set."
- my_AEA.stop()
+ my_AEA.teardown()
def test_act():
@@ -85,11 +87,8 @@ def test_act():
agent = builder.build()
with run_in_thread(agent.start, timeout=20):
- wait_for_condition(
- lambda: agent._main_loop and agent._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: agent.is_running, timeout=10)
behaviour = agent.resources.get_behaviour(DUMMY_SKILL_PUBLIC_ID, "dummy")
- import time
time.sleep(1)
wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=10)
@@ -107,12 +106,32 @@ def test_start_stop():
agent = builder.build()
with run_in_thread(agent.start, timeout=20):
- wait_for_condition(
- lambda: agent._main_loop and agent._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: agent.is_running, timeout=10)
agent.stop()
+def test_double_start():
+ """Tests the act function of the AEA."""
+ agent_name = "MyAgent"
+ private_key_path = os.path.join(CUR_PATH, "data", DEFAULT_PRIVATE_KEY_FILE)
+ builder = AEABuilder()
+ builder.set_name(agent_name)
+ builder.add_private_key(DEFAULT_LEDGER, private_key_path)
+ builder.add_skill(Path(CUR_PATH, "data", "dummy_skill"))
+ agent = builder.build()
+
+ with run_in_thread(agent.start, timeout=20):
+ try:
+ wait_for_condition(lambda: agent.is_running, timeout=10)
+
+ t = Thread(target=agent.start)
+ t.start()
+ time.sleep(1)
+ assert not t.is_alive()
+ finally:
+ agent.stop()
+
+
def test_react():
"""Tests income messages."""
with LocalNode() as node:
@@ -127,10 +146,10 @@ def test_react():
builder.add_connection(
Path(ROOT_DIR, "packages", "fetchai", "connections", "local")
)
- local_connection_id = PublicId.from_str("fetchai/local:0.4.0")
+ local_connection_id = PublicId.from_str("fetchai/local:0.5.0")
builder.set_default_connection(local_connection_id)
builder.add_skill(Path(CUR_PATH, "data", "dummy_skill"))
- agent = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.4.0")])
+ agent = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.5.0")])
# This is a temporary workaround to feed the local node to the OEF Local connection
# TODO remove it.
local_connection = agent.resources.get_connection(local_connection_id)
@@ -144,17 +163,16 @@ def test_react():
content=b"hello",
)
msg.counterparty = agent.identity.address
+ msg.sender = agent.identity.address
envelope = Envelope(
- to=agent.identity.address,
- sender=agent.identity.address,
- protocol_id=DefaultMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
with run_in_thread(agent.start, timeout=20, on_exit=agent.stop):
- wait_for_condition(
- lambda: agent._main_loop and agent._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: agent.is_running, timeout=10)
agent.outbox.put(envelope)
default_protocol_public_id = DefaultMessage.protocol_id
dummy_skill_public_id = DUMMY_SKILL_PUBLIC_ID
@@ -167,7 +185,6 @@ def test_react():
timeout=10,
error_msg="The message is not inside the handled_messages.",
)
- agent.stop()
def test_handle():
@@ -184,10 +201,10 @@ def test_handle():
builder.add_connection(
Path(ROOT_DIR, "packages", "fetchai", "connections", "local")
)
- local_connection_id = PublicId.from_str("fetchai/local:0.4.0")
+ local_connection_id = PublicId.from_str("fetchai/local:0.5.0")
builder.set_default_connection(local_connection_id)
builder.add_skill(Path(CUR_PATH, "data", "dummy_skill"))
- aea = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.4.0")])
+ aea = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.5.0")])
# This is a temporary workaround to feed the local node to the OEF Local connection
# TODO remove it.
local_connection = aea.resources.get_connection(local_connection_id)
@@ -201,17 +218,16 @@ def test_handle():
content=b"hello",
)
msg.counterparty = aea.identity.address
+ msg.sender = aea.identity.address
envelope = Envelope(
- to=aea.identity.address,
- sender=aea.identity.address,
+ to=msg.counterparty,
+ sender=msg.sender,
protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
message=msg,
)
with run_in_thread(aea.start, timeout=5):
- wait_for_condition(
- lambda: aea._main_loop and aea._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: aea.is_running, timeout=10)
dummy_skill = aea.resources.get_skill(DUMMY_SKILL_PUBLIC_ID)
dummy_handler = dummy_skill.handlers["dummy"]
@@ -242,10 +258,11 @@ def test_handle():
target=0,
)
msg.counterparty = aea.identity.address
+ msg.sender = aea.identity.address
envelope = Envelope(
- to=aea.identity.address,
- sender=aea.identity.address,
- protocol_id=FipaMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
# send envelope via localnode back to agent
@@ -270,10 +287,10 @@ def test_initialize_aea_programmatically():
builder.add_connection(
Path(ROOT_DIR, "packages", "fetchai", "connections", "local")
)
- local_connection_id = PublicId.from_str("fetchai/local:0.4.0")
+ local_connection_id = PublicId.from_str("fetchai/local:0.5.0")
builder.set_default_connection(local_connection_id)
builder.add_skill(Path(CUR_PATH, "data", "dummy_skill"))
- aea = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.4.0")])
+ aea = builder.build(connection_ids=[PublicId.from_str("fetchai/local:0.5.0")])
local_connection = aea.resources.get_connection(local_connection_id)
local_connection._local_node = node
@@ -285,17 +302,16 @@ def test_initialize_aea_programmatically():
content=b"hello",
)
expected_message.counterparty = aea.identity.address
+ expected_message.sender = aea.identity.address
envelope = Envelope(
- to=aea.identity.address,
- sender=aea.identity.address,
- protocol_id=DefaultMessage.protocol_id,
+ to=expected_message.counterparty,
+ sender=expected_message.sender,
+ protocol_id=expected_message.protocol_id,
message=expected_message,
)
with run_in_thread(aea.start, timeout=5, on_exit=aea.stop):
- wait_for_condition(
- lambda: aea._main_loop and aea._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: aea.is_running, timeout=10)
aea.outbox.put(envelope)
dummy_skill_id = DUMMY_SKILL_PUBLIC_ID
@@ -377,11 +393,10 @@ def test_initialize_aea_programmatically_build_resources():
content=b"hello",
)
expected_message.counterparty = agent_name
+ expected_message.sender = agent_name
with run_in_thread(aea.start, timeout=5, on_exit=aea.stop):
- wait_for_condition(
- lambda: aea._main_loop and aea._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: aea.is_running, timeout=10)
aea.outbox.put(
Envelope(
to=agent_name,
@@ -449,9 +464,7 @@ def test_add_behaviour_dynamically():
skill.skill_context.set_agent_context(agent.context)
with run_in_thread(agent.start, timeout=5, on_exit=agent.stop):
- wait_for_condition(
- lambda: agent._main_loop and agent._main_loop.is_running, timeout=10
- )
+ wait_for_condition(lambda: agent.is_running, timeout=10)
dummy_skill_id = PublicId("dummy_author", "dummy", "0.1.0")
dummy_skill = agent.resources.get_skill(dummy_skill_id)
@@ -500,7 +513,7 @@ def test_error_handler_is_not_set():
mocked_stop.assert_called()
-def test_no_handlers_registered(caplog):
+def test_no_handlers_registered():
"""Test no handlers are registered for message processing."""
agent_name = "MyAgent"
builder = AEABuilder()
@@ -511,9 +524,9 @@ def test_no_handlers_registered(caplog):
# builder.set_default_connection(local_connection_id)
aea = builder.build()
- with caplog.at_level(
- logging.WARNING, logger=aea._get_error_handler().context.logger.name
- ):
+ with patch.object(
+ aea._get_error_handler().context._logger, "warning"
+ ) as mock_logger:
msg = DefaultMessage(
dialogue_reference=("", ""),
message_id=1,
@@ -530,8 +543,9 @@ def test_no_handlers_registered(caplog):
)
with patch.object(aea.filter, "get_active_handlers", return_value=[]):
aea._handle(envelope)
-
- assert "Cannot handle envelope: no active handler registered" in caplog.text
+ mock_logger.assert_any_call(
+ f"Cannot handle envelope: no active handler registered for the protocol_id='{DefaultMessage.protocol_id}'."
+ )
class TestContextNamespace:
@@ -566,3 +580,36 @@ def test_access_context_namespace(self):
for skill in self.agent.resources.get_all_skills():
assert skill.skill_context.namespace.key1 == 1
assert skill.skill_context.namespace.key2 == 2
+
+
+def test_start_stop_and_start_stop_again():
+ """Tests AEA can be started/stopped twice."""
+ agent_name = "MyAgent"
+ private_key_path = os.path.join(CUR_PATH, "data", DEFAULT_PRIVATE_KEY_FILE)
+ builder = AEABuilder()
+ builder.set_name(agent_name)
+ builder.add_private_key(DEFAULT_LEDGER, private_key_path)
+ builder.add_skill(Path(CUR_PATH, "data", "dummy_skill"))
+ agent = builder.build()
+
+ with run_in_thread(agent.start, timeout=20):
+ wait_for_condition(lambda: agent.is_running, timeout=10)
+ behaviour = agent.resources.get_behaviour(DUMMY_SKILL_PUBLIC_ID, "dummy")
+
+ time.sleep(1)
+ wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=5)
+ agent.stop()
+ wait_for_condition(lambda: agent.is_stopped, timeout=10)
+
+ behaviour.nb_act_called = 0
+
+ time.sleep(2)
+ assert behaviour.nb_act_called == 0
+
+ with run_in_thread(agent.start, timeout=20):
+ wait_for_condition(lambda: agent.is_running, timeout=10)
+
+ time.sleep(1)
+ wait_for_condition(lambda: behaviour.nb_act_called > 0, timeout=5)
+ agent.stop()
+ wait_for_condition(lambda: agent.is_stopped, timeout=10)
diff --git a/tests/test_aea_builder.py b/tests/test_aea_builder.py
index 007021f3e4..dd84ae7e70 100644
--- a/tests/test_aea_builder.py
+++ b/tests/test_aea_builder.py
@@ -90,7 +90,7 @@ def test_add_package_already_existing():
builder.add_component(ComponentType.PROTOCOL, fipa_package_path)
expected_message = re.escape(
- "Component 'fetchai/fipa:0.4.0' of type 'protocol' already added."
+ "Component 'fetchai/fipa:0.5.0' of type 'protocol' already added."
)
with pytest.raises(AEAException, match=expected_message):
builder.add_component(ComponentType.PROTOCOL, fipa_package_path)
@@ -100,12 +100,12 @@ def test_when_package_has_missing_dependency():
"""Test the case when the builder tries to load the packages, but fails because of a missing dependency."""
builder = AEABuilder()
expected_message = re.escape(
- "Package 'fetchai/oef:0.6.0' of type 'connection' cannot be added. "
- "Missing dependencies: ['(protocol, fetchai/oef_search:0.3.0)']"
+ "Package 'fetchai/oef:0.7.0' of type 'connection' cannot be added. "
+ "Missing dependencies: ['(protocol, fetchai/oef_search:0.4.0)']"
)
with pytest.raises(AEAException, match=expected_message):
# connection "fetchai/oef:0.1.0" requires
- # "fetchai/oef_search:0.3.0" and "fetchai/fipa:0.4.0" protocols.
+ # "fetchai/oef_search:0.4.0" and "fetchai/fipa:0.5.0" protocols.
builder.add_component(
ComponentType.CONNECTION,
Path(ROOT_DIR) / "packages" / "fetchai" / "connections" / "oef",
diff --git a/tests/test_aea_exception_policy.py b/tests/test_aea_exception_policy.py
index da12d39f6e..dc67b0a647 100644
--- a/tests/test_aea_exception_policy.py
+++ b/tests/test_aea_exception_policy.py
@@ -23,7 +23,6 @@
import pytest
-from aea.aea import logger
from aea.aea_builder import AEABuilder
from aea.configurations.constants import DEFAULT_LEDGER
from aea.exceptions import AEAException
@@ -120,7 +119,7 @@ def test_handle_just_log(self) -> None:
self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log
self.handler.handle = self.raise_exception # type: ignore # cause error: Cannot assign to a method
- with patch.object(logger, "exception") as patched:
+ with patch.object(self.aea._logger, "exception") as patched:
t = Thread(target=self.aea.start)
t.start()
@@ -157,7 +156,7 @@ def test_act_just_log(self) -> None:
self.aea._skills_exception_policy = ExceptionPolicyEnum.just_log
self.behaviour.act = self.raise_exception # type: ignore # cause error: Cannot assign to a method
- with patch.object(logger, "exception") as patched:
+ with patch.object(self.aea._logger, "exception") as patched:
t = Thread(target=self.aea.start)
t.start()
@@ -177,4 +176,5 @@ def test_act_bad_policy(self) -> None:
def teardown(self) -> None:
"""Stop AEA if not stopped."""
+ self.aea.teardown()
self.aea.stop()
diff --git a/tests/test_aea_exectimeout.py b/tests/test_aea_exectimeout.py
index 0eaf9cabc5..1cffd06578 100644
--- a/tests/test_aea_exectimeout.py
+++ b/tests/test_aea_exectimeout.py
@@ -69,7 +69,7 @@ def setUpClass(cls) -> None:
def tearDown(self) -> None:
"""Tear down."""
- self.aea_tool.stop()
+ self.aea_tool.teardown()
def prepare(self, function: Callable) -> None:
"""Prepare aea_tool for testing.
@@ -110,7 +110,6 @@ def handler_func(*args, **kwargs):
builder.add_component_instance(test_skill)
aea = builder.build()
-
self.aea_tool = AeaTool(aea)
self.aea_tool.put_inbox(AeaTool.dummy_envelope())
@@ -131,7 +130,6 @@ def test_long_handler_cancelled_by_timeout(self):
assert execution_timeout <= timeit.time_passed <= function_sleep_time
assert not self.function_finished
- self.aea_tool.stop()
def test_short_handler_not_cancelled_by_timeout(self):
"""Test short function NOTterminated by timeout."""
@@ -151,7 +149,6 @@ def test_short_handler_not_cancelled_by_timeout(self):
assert function_sleep_time <= timeit.time_passed <= execution_timeout
assert self.function_finished
- self.aea_tool.stop()
def test_no_timeout(self):
"""Test function NOT terminated by timeout cause timeout == 0."""
@@ -169,7 +166,6 @@ def test_no_timeout(self):
assert function_sleep_time <= timeit.time_passed
assert self.function_finished
- self.aea_tool.stop()
class HandleTimeoutExecutionCase(BaseTimeExecutionCase):
diff --git a/tests/test_agent.py b/tests/test_agent.py
index a2b2980954..d01b86c781 100644
--- a/tests/test_agent.py
+++ b/tests/test_agent.py
@@ -17,14 +17,15 @@
#
# ------------------------------------------------------------------------------
-"""This module contains the tests of the agent module."""
+"""This module contains the tests of the agent module."""
+import asyncio
from threading import Thread
import pytest
-from aea.agent import Agent, AgentState, Identity, Liveness
-from aea.multiplexer import InBox, OutBox
+from aea.agent import Agent, Identity
+from aea.runtime import RuntimeStates
from packages.fetchai.connections.local.connection import LocalNode
@@ -69,56 +70,30 @@ def test_run_agent():
identity = Identity(agent_name, address=agent_address)
oef_local_connection = _make_local_connection(agent_address, node)
oef_local_connection._local_node = node
- agent = DummyAgent(identity, [oef_local_connection],)
- assert agent.name == identity.name
- assert agent.tick == 0
- assert (
- agent.agent_state == AgentState.INITIATED
- ), "Agent state must be 'initiated'"
-
- agent.multiplexer.connect()
- assert (
- agent.agent_state == AgentState.CONNECTED
- ), "Agent state must be 'connected'"
-
- assert isinstance(agent.inbox, InBox)
- assert isinstance(agent.outbox, OutBox)
-
- agent.multiplexer.disconnect()
-
- import asyncio
agent = DummyAgent(
identity, [oef_local_connection], loop=asyncio.new_event_loop()
)
agent_thread = Thread(target=agent.start)
+ assert agent.state == RuntimeStates.stopped
agent_thread.start()
try:
wait_for_condition(
- lambda: agent._main_loop and agent._main_loop.is_running,
+ lambda: agent.state == RuntimeStates.starting,
timeout=5,
- error_msg="Agent loop not started!'",
+ error_msg="Agent state must be 'starting'",
)
wait_for_condition(
- lambda: agent.agent_state == AgentState.RUNNING,
+ lambda: agent.state == RuntimeStates.running,
timeout=5,
error_msg="Agent state must be 'running'",
)
finally:
agent.stop()
+ assert agent.state == RuntimeStates.stopped
agent_thread.join()
-def test_liveness():
- """Test liveness object states."""
- liveness = Liveness()
- assert liveness.is_stopped
- liveness.start()
- assert not liveness.is_stopped
- liveness.stop()
- assert liveness.is_stopped
-
-
def test_runtime_modes():
"""Test runtime modes are set."""
agent_name = "dummyagent"
diff --git a/tests/test_cli/test_add/test_connection.py b/tests/test_cli/test_add/test_connection.py
index 0e8c632535..e57b523d62 100644
--- a/tests/test_cli/test_add/test_connection.py
+++ b/tests/test_cli/test_add/test_connection.py
@@ -59,7 +59,7 @@ def setup_class(cls):
cls.connection_name = "http_client"
cls.connection_author = "fetchai"
cls.connection_version = "0.3.0"
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
@@ -150,7 +150,7 @@ def setup_class(cls):
cls.connection_name = "http_client"
cls.connection_author = "fetchai"
cls.connection_version = "0.3.0"
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
@@ -347,7 +347,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
cls.connection_name = "http_client"
# copy the 'packages' directory in the parent of the agent folder.
@@ -415,7 +415,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
cls.connection_name = "http_client"
# copy the 'packages' directory in the parent of the agent folder.
@@ -482,7 +482,7 @@ class TestAddConnectionFromRemoteRegistry(AEATestCaseEmpty):
@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
def test_add_connection_from_remote_registry_positive(self):
"""Test add connection from Registry positive result."""
- self.add_item("connection", "fetchai/local:0.1.0", local=False)
+ self.add_item("connection", "fetchai/local:0.4.0", local=False)
items_path = os.path.join(self.agent_name, "vendor", "fetchai", "connections")
items_folders = os.listdir(items_path)
diff --git a/tests/test_cli/test_add/test_contract.py b/tests/test_cli/test_add/test_contract.py
index f1ff0e59cc..030278f521 100644
--- a/tests/test_cli/test_add/test_contract.py
+++ b/tests/test_cli/test_add/test_contract.py
@@ -62,7 +62,7 @@ class TestAddContractFromRemoteRegistry(AEATestCaseEmpty):
@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
def test_add_contract_from_remote_registry_positive(self):
"""Test add contract from Registry positive result."""
- self.add_item("contract", "fetchai/erc1155:0.1.0", local=False)
+ self.add_item("contract", "fetchai/erc1155:0.6.0", local=False)
items_path = os.path.join(self.agent_name, "vendor", "fetchai", "contracts")
items_folders = os.listdir(items_path)
diff --git a/tests/test_cli/test_add/test_protocol.py b/tests/test_cli/test_add/test_protocol.py
index 99d5b80497..08d5439ed9 100644
--- a/tests/test_cli/test_add/test_protocol.py
+++ b/tests/test_cli/test_add/test_protocol.py
@@ -56,7 +56,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.protocol_id = PublicId.from_str("fetchai/gym:0.3.0")
+ cls.protocol_id = PublicId.from_str("fetchai/gym:0.4.0")
cls.protocol_name = cls.protocol_id.name
cls.protocol_author = cls.protocol_id.author
cls.protocol_version = cls.protocol_id.version
@@ -139,7 +139,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.protocol_id = PublicId.from_str("fetchai/gym:0.3.0")
+ cls.protocol_id = PublicId.from_str("fetchai/gym:0.4.0")
cls.protocol_name = cls.protocol_id.name
cls.protocol_author = cls.protocol_id.author
cls.protocol_version = cls.protocol_id.version
@@ -351,7 +351,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.protocol_id = "fetchai/gym:0.3.0"
+ cls.protocol_id = "fetchai/gym:0.4.0"
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
@@ -417,7 +417,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.protocol_id = "fetchai/gym:0.3.0"
+ cls.protocol_id = "fetchai/gym:0.4.0"
cls.protocol_name = "gym"
# copy the 'packages' directory in the parent of the agent folder.
@@ -478,7 +478,7 @@ class TestAddProtocolFromRemoteRegistry(AEATestCaseEmpty):
@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
def test_add_protocol_from_remote_registry_positive(self):
"""Test add protocol from Registry positive result."""
- self.add_item("protocol", "fetchai/fipa:0.1.0", local=False)
+ self.add_item("protocol", "fetchai/fipa:0.4.0", local=False)
items_path = os.path.join(self.agent_name, "vendor", "fetchai", "protocols")
items_folders = os.listdir(items_path)
diff --git a/tests/test_cli/test_add/test_skill.py b/tests/test_cli/test_add/test_skill.py
index 1519288a18..d008ba1214 100644
--- a/tests/test_cli/test_add/test_skill.py
+++ b/tests/test_cli/test_add/test_skill.py
@@ -62,7 +62,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = PublicId.from_str("fetchai/error:0.3.0")
+ cls.skill_id = PublicId.from_str("fetchai/error:0.4.0")
cls.skill_name = cls.skill_id.name
cls.skill_author = cls.skill_id.author
cls.skill_version = cls.skill_id.version
@@ -144,7 +144,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = PublicId.from_str("fetchai/echo:0.3.0")
+ cls.skill_id = PublicId.from_str("fetchai/echo:0.4.0")
cls.skill_name = cls.skill_id.name
cls.skill_author = cls.skill_id.author
cls.skill_version = cls.skill_id.version
@@ -354,7 +354,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = "fetchai/echo:0.3.0"
+ cls.skill_id = "fetchai/echo:0.4.0"
cls.skill_name = "echo"
# copy the 'packages' directory in the parent of the agent folder.
@@ -426,7 +426,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = "fetchai/echo:0.3.0"
+ cls.skill_id = "fetchai/echo:0.4.0"
cls.skill_name = "echo"
# copy the 'packages' directory in the parent of the agent folder.
@@ -488,7 +488,7 @@ class TestAddSkillWithContractsDeps(AEATestCaseEmpty):
def test_add_skill_with_contracts_positive(self):
"""Test add skill with contract dependencies positive result."""
- self.add_item("skill", "fetchai/erc1155_client:0.8.0")
+ self.add_item("skill", "fetchai/erc1155_client:0.9.0")
contracts_path = os.path.join(self.agent_name, "vendor", "fetchai", "contracts")
contracts_folders = os.listdir(contracts_path)
@@ -503,6 +503,9 @@ class TestAddSkillFromRemoteRegistry(AEATestCaseEmpty):
@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
def test_add_skill_from_remote_registry_positive(self):
"""Test add skill from Registry positive result."""
+ self.run_cli_command(
+ *["remove", "protocol", "fetchai/default:0.4.0"], cwd=self._get_cwd()
+ )
self.add_item("skill", "fetchai/echo:0.3.0", local=False)
items_path = os.path.join(self.agent_name, "vendor", "fetchai", "skills")
diff --git a/tests/test_cli/test_create.py b/tests/test_cli/test_create.py
index 6618a7b3d3..2253b4198b 100644
--- a/tests/test_cli/test_create.py
+++ b/tests/test_cli/test_create.py
@@ -75,6 +75,11 @@ def setup_class(cls):
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
os.chdir(cls.t)
+ cls.cli_config_file = f"{cls.t}/cli_config.yaml"
+ cls.cli_config_patch = patch(
+ "aea.cli.utils.config.CLI_CONFIG_PATH", cls.cli_config_file
+ )
+ cls.cli_config_patch.start()
result = cls.runner.invoke(
cli, [*CLI_LOG_OPTION, "init", "--local", "--author", AUTHOR]
)
@@ -262,6 +267,7 @@ def test_skills_directory_content(self):
@classmethod
def teardown_class(cls):
"""Tear the test down."""
+ cls.cli_config_patch.start()
os.chdir(cls.cwd)
try:
shutil.rmtree(cls.t)
diff --git a/tests/test_cli/test_eject.py b/tests/test_cli/test_eject.py
index 790e832c4e..8ceed84c58 100644
--- a/tests/test_cli/test_eject.py
+++ b/tests/test_cli/test_eject.py
@@ -33,29 +33,29 @@ def test_eject_commands_positive(self):
self.set_agent_context(agent_name)
cwd = os.path.join(self.t, agent_name)
- self.add_item("connection", "fetchai/gym:0.4.0")
- self.add_item("skill", "fetchai/gym:0.4.0")
- self.add_item("contract", "fetchai/erc1155:0.6.0")
+ self.add_item("connection", "fetchai/gym:0.5.0")
+ self.add_item("skill", "fetchai/gym:0.5.0")
+ self.add_item("contract", "fetchai/erc1155:0.7.0")
- self.run_cli_command("eject", "connection", "fetchai/gym:0.4.0", cwd=cwd)
+ self.run_cli_command("eject", "connection", "fetchai/gym:0.5.0", cwd=cwd)
assert "gym" not in os.listdir(
(os.path.join(cwd, "vendor", "fetchai", "connections"))
)
assert "gym" in os.listdir((os.path.join(cwd, "connections")))
- self.run_cli_command("eject", "protocol", "fetchai/gym:0.3.0", cwd=cwd)
+ self.run_cli_command("eject", "protocol", "fetchai/gym:0.4.0", cwd=cwd)
assert "gym" not in os.listdir(
(os.path.join(cwd, "vendor", "fetchai", "protocols"))
)
assert "gym" in os.listdir((os.path.join(cwd, "protocols")))
- self.run_cli_command("eject", "skill", "fetchai/gym:0.4.0", cwd=cwd)
+ self.run_cli_command("eject", "skill", "fetchai/gym:0.5.0", cwd=cwd)
assert "gym" not in os.listdir(
(os.path.join(cwd, "vendor", "fetchai", "skills"))
)
assert "gym" in os.listdir((os.path.join(cwd, "skills")))
- self.run_cli_command("eject", "contract", "fetchai/erc1155:0.6.0", cwd=cwd)
+ self.run_cli_command("eject", "contract", "fetchai/erc1155:0.7.0", cwd=cwd)
assert "erc1155" not in os.listdir(
(os.path.join(cwd, "vendor", "fetchai", "contracts"))
)
diff --git a/tests/test_cli/test_fetch.py b/tests/test_cli/test_fetch.py
index e45ad11424..2f6781d5ce 100644
--- a/tests/test_cli/test_fetch.py
+++ b/tests/test_cli/test_fetch.py
@@ -149,5 +149,5 @@ class TestFetchFromRemoteRegistry(AEATestCaseMany):
@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
def test_fetch_agent_from_remote_registry_positive(self):
"""Test fetch agent from Registry for positive result."""
- self.run_cli_command("fetch", "fetchai/my_first_aea:0.6.0")
+ self.run_cli_command("fetch", "fetchai/my_first_aea:0.7.0")
assert "my_first_aea" in os.listdir(self.t)
diff --git a/tests/test_cli/test_generate_key.py b/tests/test_cli/test_generate_key.py
index 48d6e0e191..f30dd52e19 100644
--- a/tests/test_cli/test_generate_key.py
+++ b/tests/test_cli/test_generate_key.py
@@ -129,3 +129,44 @@ def teardown_class(cls):
"""Tear the test down."""
os.chdir(cls.cwd)
shutil.rmtree(cls.t)
+
+
+class TestGenerateKeyWithFile:
+ """Test that the command 'aea generate-key' can accept a file path."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set the test up."""
+ cls.runner = CliRunner()
+ cls.agent_name = "myagent"
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ def test_fetchai(self):
+ """Test that the fetchai private key can be deposited in a custom file."""
+ test_file = "test.txt"
+ result = self.runner.invoke(
+ cli, [*CLI_LOG_OPTION, "generate-key", FETCHAI, test_file]
+ )
+ assert result.exit_code == 0
+ assert Path(test_file).exists()
+
+ # This tests if the file has been created and its content is correct.
+ crypto = make_crypto(FETCHAI, private_key_path=test_file)
+ content = Path(test_file).read_bytes()
+ assert content.decode("utf-8") == crypto.private_key
+
+ def test_all(self):
+ """Test that the all command does not allow a file to be provided."""
+ test_file = "test.txt"
+ result = self.runner.invoke(
+ cli, [*CLI_LOG_OPTION, "generate-key", "all", test_file]
+ )
+ assert result.exit_code == 1
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ shutil.rmtree(cls.t)
diff --git a/tests/test_cli/test_generate_wealth.py b/tests/test_cli/test_generate_wealth.py
index 1b88f962e2..f5b83f2549 100644
--- a/tests/test_cli/test_generate_wealth.py
+++ b/tests/test_cli/test_generate_wealth.py
@@ -27,7 +27,12 @@
from aea.test_tools.exceptions import AEATestingException
from aea.test_tools.test_cases import AEATestCaseMany
-from tests.conftest import CLI_LOG_OPTION, CliRunner, FETCHAI
+from tests.conftest import (
+ CLI_LOG_OPTION,
+ CliRunner,
+ FETCHAI,
+ MAX_FLAKY_RERUNS_INTEGRATION,
+)
from tests.test_cli.tools_for_testing import ContextMock
@@ -38,26 +43,26 @@ class WaitFundsReleaseTestCase(TestCase):
def test__wait_funds_release_positive(self, try_get_balance_mock):
"""Test for _wait_funds_release method positive result."""
- _wait_funds_release("agent_config", "wallet", "type_")
+ with pytest.raises(ValueError):
+ _wait_funds_release("agent_config", "wallet", "type_")
class GenerateWealthTestCase(TestCase):
"""Test case for _generate_wealth method."""
@mock.patch("aea.cli.generate_wealth.Wallet")
- @mock.patch("aea.cli.generate_wealth.TESTNETS", {"type": "value"})
@mock.patch("aea.cli.generate_wealth.click.echo")
@mock.patch("aea.cli.generate_wealth.try_generate_testnet_wealth")
@mock.patch("aea.cli.generate_wealth._wait_funds_release")
- @mock.patch("aea.cli.generate_wealth.verify_or_create_private_keys")
+ @mock.patch("aea.cli.generate_wealth.verify_or_create_private_keys_ctx")
def test__generate_wealth_positive(self, *mocks):
"""Test for _generate_wealth method positive result."""
ctx = ContextMock()
- _try_generate_wealth(ctx, "type", True)
+ _try_generate_wealth(ctx, "cosmos", True)
@mock.patch("aea.cli.utils.decorators.try_to_load_agent_config")
-@mock.patch("aea.cli.generate_wealth.verify_or_create_private_keys")
+@mock.patch("aea.cli.generate_wealth.verify_or_create_private_keys_ctx")
@mock.patch("aea.cli.generate_wealth._try_generate_wealth")
class GenerateWealthCommandTestCase(TestCase):
"""Test case for CLI generate_wealth command."""
@@ -82,9 +87,11 @@ def test_run_positive(self, *mocks):
self.assertEqual(result.exit_code, 0)
-class TestWealthCommands(AEATestCaseMany):
+class TestWealthCommandsPositive(AEATestCaseMany):
"""Test case for CLI wealth commands."""
+ @pytest.mark.integration
+ @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)
def test_wealth_commands(self):
"""Test wealth commands."""
agent_name = "test_aea"
@@ -97,6 +104,20 @@ def test_wealth_commands(self):
self.generate_wealth()
+
+class TestWealthCommandsNegative(AEATestCaseMany):
+ """Test case for CLI wealth commands, negative case."""
+
+ def test_wealth_commands_negative(self):
+ """Test wealth commands."""
+ agent_name = "test_aea"
+ self.create_agents(agent_name)
+
+ self.set_agent_context(agent_name)
+
+ self.generate_private_key()
+ self.add_private_key()
+
settings = {"unsupported_crypto": "path"}
self.force_set_config("agent.private_key_paths", settings)
with pytest.raises(AEATestingException) as excinfo:
diff --git a/tests/test_cli/test_get_address.py b/tests/test_cli/test_get_address.py
index 5badc75cbf..81ef1dffef 100644
--- a/tests/test_cli/test_get_address.py
+++ b/tests/test_cli/test_get_address.py
@@ -31,7 +31,7 @@ class GetAddressTestCase(TestCase):
"""Test case for _get_address method."""
@mock.patch("aea.cli.get_address.Wallet")
- @mock.patch("aea.cli.get_address.verify_or_create_private_keys")
+ @mock.patch("aea.cli.get_address.verify_or_create_private_keys_ctx")
def test__get_address_positive(self, *mocks):
"""Test for _get_address method positive result."""
ctx = ContextMock()
@@ -39,7 +39,7 @@ def test__get_address_positive(self, *mocks):
@mock.patch("aea.cli.utils.decorators.try_to_load_agent_config")
-@mock.patch("aea.cli.get_address.verify_or_create_private_keys")
+@mock.patch("aea.cli.get_address.verify_or_create_private_keys_ctx")
@mock.patch("aea.cli.get_address._try_get_address")
@mock.patch("aea.cli.get_address.click.echo")
class GetAddressCommandTestCase(TestCase):
diff --git a/tests/test_cli/test_get_wealth.py b/tests/test_cli/test_get_wealth.py
index eb1fa6f624..1d7f45d3a6 100644
--- a/tests/test_cli/test_get_wealth.py
+++ b/tests/test_cli/test_get_wealth.py
@@ -31,7 +31,7 @@ class GetWealthTestCase(TestCase):
"""Test case for _get_wealth method."""
@mock.patch("aea.cli.get_wealth.Wallet")
- @mock.patch("aea.cli.get_wealth.verify_or_create_private_keys")
+ @mock.patch("aea.cli.get_wealth.verify_or_create_private_keys_ctx")
@mock.patch("aea.cli.get_wealth.try_get_balance")
def test__get_wealth_positive(self, *mocks):
"""Test for _get_wealth method positive result."""
@@ -40,7 +40,7 @@ def test__get_wealth_positive(self, *mocks):
@mock.patch("aea.cli.utils.decorators.try_to_load_agent_config")
-@mock.patch("aea.cli.get_wealth.verify_or_create_private_keys")
+@mock.patch("aea.cli.get_wealth.verify_or_create_private_keys_ctx")
@mock.patch("aea.cli.get_wealth._try_get_wealth")
@mock.patch("aea.cli.get_wealth.click.echo")
class GetWealthCommandTestCase(TestCase):
diff --git a/tests/test_cli/test_remove/test_connection.py b/tests/test_cli/test_remove/test_connection.py
index 6b3741c51a..06923f5cd7 100644
--- a/tests/test_cli/test_remove/test_connection.py
+++ b/tests/test_cli/test_remove/test_connection.py
@@ -47,7 +47,7 @@ def setup_class(cls):
cls.t = tempfile.mkdtemp()
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
cls.connection_name = "http_client"
os.chdir(cls.t)
@@ -109,7 +109,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.connection_id = "fetchai/local:0.4.0"
+ cls.connection_id = "fetchai/local:0.5.0"
os.chdir(cls.t)
result = cls.runner.invoke(
@@ -164,7 +164,7 @@ def setup_class(cls):
cls.t = tempfile.mkdtemp()
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
cls.connection_name = "http_client"
os.chdir(cls.t)
diff --git a/tests/test_cli/test_remove/test_protocol.py b/tests/test_cli/test_remove/test_protocol.py
index f9dfd1e25f..17a0d102ee 100644
--- a/tests/test_cli/test_remove/test_protocol.py
+++ b/tests/test_cli/test_remove/test_protocol.py
@@ -47,7 +47,7 @@ def setup_class(cls):
cls.t = tempfile.mkdtemp()
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
- cls.protocol_id = "fetchai/gym:0.3.0"
+ cls.protocol_id = "fetchai/gym:0.4.0"
cls.protocol_name = "gym"
os.chdir(cls.t)
@@ -109,7 +109,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.protocol_id = "fetchai/gym:0.3.0"
+ cls.protocol_id = "fetchai/gym:0.4.0"
os.chdir(cls.t)
result = cls.runner.invoke(
@@ -164,7 +164,7 @@ def setup_class(cls):
cls.t = tempfile.mkdtemp()
# copy the 'packages' directory in the parent of the agent folder.
shutil.copytree(Path(CUR_PATH, "..", "packages"), Path(cls.t, "packages"))
- cls.protocol_id = "fetchai/gym:0.3.0"
+ cls.protocol_id = "fetchai/gym:0.4.0"
os.chdir(cls.t)
result = cls.runner.invoke(
diff --git a/tests/test_cli/test_remove/test_skill.py b/tests/test_cli/test_remove/test_skill.py
index 1e2d6af90d..3eb2e7d7a7 100644
--- a/tests/test_cli/test_remove/test_skill.py
+++ b/tests/test_cli/test_remove/test_skill.py
@@ -45,7 +45,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = "fetchai/gym:0.4.0"
+ cls.skill_id = "fetchai/gym:0.5.0"
cls.skill_name = "gym"
os.chdir(cls.t)
@@ -114,7 +114,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = "fetchai/gym:0.4.0"
+ cls.skill_id = "fetchai/gym:0.5.0"
os.chdir(cls.t)
result = cls.runner.invoke(
@@ -168,7 +168,7 @@ def setup_class(cls):
cls.agent_name = "myagent"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
- cls.skill_id = "fetchai/gym:0.4.0"
+ cls.skill_id = "fetchai/gym:0.5.0"
cls.skill_name = "gym"
os.chdir(cls.t)
diff --git a/tests/test_cli/test_run.py b/tests/test_cli/test_run.py
index 87757e0976..deb41536c2 100644
--- a/tests/test_cli/test_run.py
+++ b/tests/test_cli/test_run.py
@@ -16,6 +16,8 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
+
"""This test module contains the tests for the `aea run` sub-command."""
import os
import shutil
@@ -28,6 +30,8 @@
from click import ClickException
+from pexpect.exceptions import EOF # type: ignore
+
import pytest
import yaml
@@ -75,7 +79,7 @@ def test_run():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
@@ -86,7 +90,7 @@ def test_run():
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -167,9 +171,9 @@ def test_run_with_default_connection():
@pytest.mark.parametrize(
argnames=["connection_ids"],
argvalues=[
- ["fetchai/http_client:0.5.0,{}".format(str(DEFAULT_CONNECTION))],
- ["'fetchai/http_client:0.5.0, {}'".format(str(DEFAULT_CONNECTION))],
- ["fetchai/http_client:0.5.0,,{},".format(str(DEFAULT_CONNECTION))],
+ ["fetchai/http_client:0.6.0,{}".format(str(DEFAULT_CONNECTION))],
+ ["'fetchai/http_client:0.6.0, {}'".format(str(DEFAULT_CONNECTION))],
+ ["fetchai/http_client:0.6.0,,{},".format(str(DEFAULT_CONNECTION))],
],
)
def test_run_multiple_connections(connection_ids):
@@ -194,7 +198,7 @@ def test_run_multiple_connections(connection_ids):
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
@@ -203,26 +207,24 @@ def test_run_multiple_connections(connection_ids):
cli, [*CLI_LOG_OPTION, "add", "--local", "connection", str(DEFAULT_CONNECTION)]
)
assert result.exit_code == 1
+ process = PexpectWrapper( # nosec
+ [sys.executable, "-m", "aea.cli", "run", "--connections", connection_ids],
+ env=os.environ,
+ maxread=10000,
+ encoding="utf-8",
+ logfile=sys.stdout,
+ )
try:
- process = subprocess.Popen( # nosec
- [sys.executable, "-m", "aea.cli", "run", "--connections", connection_ids],
- stdout=subprocess.PIPE,
- env=os.environ.copy(),
+ process.expect_all(["Start processing messages"], timeout=20)
+ process.control_c()
+ process.expect(
+ EOF, timeout=20,
)
-
- time.sleep(5.0)
- sigint_crossplatform(process)
- process.wait(timeout=5)
-
+ process.wait_to_complete(10)
assert process.returncode == 0
-
finally:
- poll = process.poll()
- if poll is None:
- process.terminate()
- process.wait(2)
-
+ process.wait_to_complete(10)
os.chdir(cwd)
try:
shutil.rmtree(t)
@@ -252,7 +254,7 @@ def test_run_unknown_private_key():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
result = runner.invoke(
@@ -262,7 +264,7 @@ def test_run_unknown_private_key():
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -291,7 +293,7 @@ def test_run_unknown_private_key():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.6.0"],
standalone_mode=False,
)
@@ -327,7 +329,7 @@ def test_run_fet_private_key_config():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
@@ -351,7 +353,7 @@ def test_run_fet_private_key_config():
error_msg = ""
try:
- cli.main([*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.5.0"])
+ cli.main([*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.6.0"])
except SystemExit as e:
error_msg = str(e)
@@ -386,7 +388,7 @@ def test_run_ethereum_private_key_config():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
@@ -410,7 +412,7 @@ def test_run_ethereum_private_key_config():
error_msg = ""
try:
- cli.main([*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.5.0"])
+ cli.main([*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.6.0"])
except SystemExit as e:
error_msg = str(e)
@@ -448,7 +450,7 @@ def test_run_with_install_deps():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
result = runner.invoke(
@@ -458,7 +460,7 @@ def test_run_with_install_deps():
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -474,7 +476,7 @@ def test_run_with_install_deps():
"run",
"--install-deps",
"--connections",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
env=os.environ,
maxread=10000,
@@ -520,7 +522,7 @@ def test_run_with_install_deps_and_requirement_file():
result = runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.5.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "connection", "fetchai/http_client:0.6.0"],
)
assert result.exit_code == 0
result = runner.invoke(
@@ -530,7 +532,7 @@ def test_run_with_install_deps_and_requirement_file():
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -550,7 +552,7 @@ def test_run_with_install_deps_and_requirement_file():
"run",
"--install-deps",
"--connections",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
env=os.environ,
maxread=10000,
@@ -608,7 +610,7 @@ def setup_class(cls):
"add",
"--local",
"connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
standalone_mode=False,
)
@@ -625,7 +627,7 @@ def setup_class(cls):
try:
cli.main(
- [*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.5.0"]
+ [*CLI_LOG_OPTION, "run", "--connections", "fetchai/http_client:0.6.0"]
)
except SystemExit as e:
cls.exit_code = e.code
@@ -820,7 +822,7 @@ def setup_class(cls):
"""Set the test up."""
cls.runner = CliRunner()
cls.agent_name = "myagent"
- cls.connection_id = PublicId.from_str("fetchai/http_client:0.5.0")
+ cls.connection_id = PublicId.from_str("fetchai/http_client:0.6.0")
cls.connection_name = cls.connection_id.name
cls.connection_author = cls.connection_id.author
cls.cwd = os.getcwd()
@@ -854,7 +856,7 @@ def setup_class(cls):
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -913,7 +915,7 @@ def setup_class(cls):
"""Set the test up."""
cls.runner = CliRunner()
cls.agent_name = "myagent"
- cls.connection_id = PublicId.from_str("fetchai/http_client:0.5.0")
+ cls.connection_id = PublicId.from_str("fetchai/http_client:0.6.0")
cls.connection_author = cls.connection_id.author
cls.connection_name = cls.connection_id.name
cls.cwd = os.getcwd()
@@ -947,7 +949,7 @@ def setup_class(cls):
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -1005,7 +1007,7 @@ def setup_class(cls):
"""Set the test up."""
cls.runner = CliRunner()
cls.agent_name = "myagent"
- cls.connection_id = "fetchai/http_client:0.5.0"
+ cls.connection_id = "fetchai/http_client:0.6.0"
cls.connection_name = "http_client"
cls.cwd = os.getcwd()
cls.t = tempfile.mkdtemp()
@@ -1038,7 +1040,7 @@ def setup_class(cls):
"config",
"set",
"agent.default_connection",
- "fetchai/http_client:0.5.0",
+ "fetchai/http_client:0.6.0",
],
)
assert result.exit_code == 0
@@ -1192,7 +1194,7 @@ def setup_class(cls):
result = cls.runner.invoke(
cli,
- [*CLI_LOG_OPTION, "add", "--local", "protocol", "fetchai/fipa:0.4.0"],
+ [*CLI_LOG_OPTION, "add", "--local", "protocol", "fetchai/fipa:0.5.0"],
standalone_mode=False,
)
assert result.exit_code == 0
diff --git a/tests/test_cli/test_search.py b/tests/test_cli/test_search.py
index 34b9208800..abe4a8d29d 100644
--- a/tests/test_cli/test_search.py
+++ b/tests/test_cli/test_search.py
@@ -31,6 +31,7 @@
from aea import AEA_DIR
from aea.cli import cli
+from aea.configurations.base import PublicId
from tests.conftest import (
AGENT_CONFIGURATION_SCHEMA,
@@ -184,6 +185,11 @@ def setup_class(cls):
cls.t = tempfile.mkdtemp()
os.chdir(cls.t)
+ cls.cli_config_file = f"{cls.t}/cli_config.yaml"
+ cls.cli_config_patch = mock.patch(
+ "aea.cli.utils.config.CLI_CONFIG_PATH", cls.cli_config_file
+ )
+ cls.cli_config_patch.start()
result = cls.runner.invoke(
cli, [*CLI_LOG_OPTION, "init", "--local", "--author", AUTHOR]
)
@@ -233,6 +239,7 @@ def test_correct_output_default_registry(self):
@classmethod
def teardown_class(cls):
"""Tear the test down."""
+ cls.cli_config_patch.stop()
os.chdir(cls.cwd)
try:
shutil.rmtree(cls.t)
@@ -351,23 +358,30 @@ def test_exit_code_equal_to_zero(self):
def test_correct_output(self,):
"""Test that the command has printed the correct output.."""
+ public_id_echo = PublicId.from_str("fetchai/echo:0.4.0")
+ public_id_error = PublicId.from_str("fetchai/error:0.4.0")
expected = (
'Searching for ""...\n'
"Skills found:\n\n"
"------------------------------\n"
- "Public ID: fetchai/echo:0.3.0\n"
+ "Public ID: {}\n"
"Name: echo\n"
"Description: The echo skill implements simple echo functionality.\n"
"Author: fetchai\n"
- "Version: 0.3.0\n"
+ "Version: {}\n"
"------------------------------\n"
"------------------------------\n"
- "Public ID: fetchai/error:0.3.0\n"
+ "Public ID: {}\n"
"Name: error\n"
"Description: The error skill implements basic error handling required by all AEAs.\n"
"Author: fetchai\n"
- "Version: 0.3.0\n"
+ "Version: {}\n"
"------------------------------\n\n"
+ ).format(
+ str(public_id_echo),
+ str(public_id_echo.version),
+ str(public_id_error),
+ str(public_id_error.version),
)
assert self.result.output == expected
@@ -426,23 +440,30 @@ def test_exit_code_equal_to_zero(self):
def test_correct_output(self,):
"""Test that the command has printed the correct output.."""
+ public_id_echo = PublicId.from_str("fetchai/echo:0.4.0")
+ public_id_error = PublicId.from_str("fetchai/error:0.4.0")
expected = (
'Searching for ""...\n'
"Skills found:\n\n"
"------------------------------\n"
- "Public ID: fetchai/echo:0.3.0\n"
+ "Public ID: {}\n"
"Name: echo\n"
"Description: The echo skill implements simple echo functionality.\n"
"Author: fetchai\n"
- "Version: 0.3.0\n"
+ "Version: {}\n"
"------------------------------\n"
"------------------------------\n"
- "Public ID: fetchai/error:0.3.0\n"
+ "Public ID: {}\n"
"Name: error\n"
"Description: The error skill implements basic error handling required by all AEAs.\n"
"Author: fetchai\n"
- "Version: 0.3.0\n"
+ "Version: {}\n"
"------------------------------\n\n"
+ ).format(
+ str(public_id_echo),
+ str(public_id_echo.version),
+ str(public_id_error),
+ str(public_id_error.version),
)
assert self.result.output == expected
diff --git a/tests/test_cli/test_utils/test_utils.py b/tests/test_cli/test_utils/test_utils.py
index 2ebfa11971..da370da07a 100644
--- a/tests/test_cli/test_utils/test_utils.py
+++ b/tests/test_cli/test_utils/test_utils.py
@@ -275,7 +275,7 @@ class FindItemLocallyTestCase(TestCase):
)
def test_find_item_locally_bad_config(self, *mocks):
"""Test find_item_locally for bad config result."""
- public_id = PublicIdMock.from_str("fetchai/echo:0.3.0")
+ public_id = PublicIdMock.from_str("fetchai/echo:0.4.0")
with self.assertRaises(ClickException) as cm:
find_item_locally(ContextMock(), "skill", public_id)
@@ -289,7 +289,7 @@ def test_find_item_locally_bad_config(self, *mocks):
)
def test_find_item_locally_cant_find(self, from_conftype_mock, *mocks):
"""Test find_item_locally for can't find result."""
- public_id = PublicIdMock.from_str("fetchai/echo:0.3.0")
+ public_id = PublicIdMock.from_str("fetchai/echo:0.4.0")
with self.assertRaises(ClickException) as cm:
find_item_locally(ContextMock(), "skill", public_id)
@@ -308,7 +308,7 @@ class FindItemInDistributionTestCase(TestCase):
)
def testfind_item_in_distribution_bad_config(self, *mocks):
"""Test find_item_in_distribution for bad config result."""
- public_id = PublicIdMock.from_str("fetchai/echo:0.3.0")
+ public_id = PublicIdMock.from_str("fetchai/echo:0.4.0")
with self.assertRaises(ClickException) as cm:
find_item_in_distribution(ContextMock(), "skill", public_id)
@@ -317,7 +317,7 @@ def testfind_item_in_distribution_bad_config(self, *mocks):
@mock.patch("aea.cli.utils.package_utils.Path.exists", return_value=False)
def testfind_item_in_distribution_not_found(self, *mocks):
"""Test find_item_in_distribution for not found result."""
- public_id = PublicIdMock.from_str("fetchai/echo:0.3.0")
+ public_id = PublicIdMock.from_str("fetchai/echo:0.4.0")
with self.assertRaises(ClickException) as cm:
find_item_in_distribution(ContextMock(), "skill", public_id)
@@ -331,7 +331,7 @@ def testfind_item_in_distribution_not_found(self, *mocks):
)
def testfind_item_in_distribution_cant_find(self, from_conftype_mock, *mocks):
"""Test find_item_locally for can't find result."""
- public_id = PublicIdMock.from_str("fetchai/echo:0.3.0")
+ public_id = PublicIdMock.from_str("fetchai/echo:0.4.0")
with self.assertRaises(ClickException) as cm:
find_item_in_distribution(ContextMock(), "skill", public_id)
diff --git a/tests/test_cli_gui/test_run_agent.py b/tests/test_cli_gui/test_run_agent.py
index 0e840f7ade..e88796c009 100644
--- a/tests/test_cli_gui/test_run_agent.py
+++ b/tests/test_cli_gui/test_run_agent.py
@@ -64,7 +64,7 @@ def test_create_and_run_agent():
response_add = app.post(
"api/agent/" + agent_id + "/connection",
content_type="application/json",
- data=json.dumps("fetchai/local:0.4.0"),
+ data=json.dumps("fetchai/local:0.5.0"),
)
assert response_add.status_code == 201
diff --git a/tests/test_configurations/test_aea_config.py b/tests/test_configurations/test_aea_config.py
index 2c717be957..60ee503df0 100644
--- a/tests/test_configurations/test_aea_config.py
+++ b/tests/test_configurations/test_aea_config.py
@@ -55,7 +55,7 @@ class NotSet(type):
contracts: []
protocols: []
skills: []
-default_connection: fetchai/stub:0.6.0
+default_connection: fetchai/stub:0.7.0
default_ledger: cosmos
private_key_paths:
cosmos: tests/data/cosmos_private_key.txt
diff --git a/tests/test_configurations/test_loader.py b/tests/test_configurations/test_loader.py
index e96d1bc802..834178ade9 100644
--- a/tests/test_configurations/test_loader.py
+++ b/tests/test_configurations/test_loader.py
@@ -88,6 +88,24 @@ def test_load_protocol_specification_only_first_part():
load_protocol_specification("foo")
+def test_load_protocol_specification_two_parts():
+ """Test 'load_protocol_specification' with two parts."""
+ valid_protocol_specification = dict(
+ name="name",
+ author="author",
+ version="0.1.0",
+ license="",
+ aea_version="0.1.0",
+ speech_acts={"example": {}},
+ )
+ with mock.patch.object(
+ yaml,
+ "safe_load_all",
+ return_value=[valid_protocol_specification, valid_protocol_specification],
+ ), mock.patch("builtins.open"), mock.patch("jsonschema.Draft4Validator.validate"):
+ load_protocol_specification("foo")
+
+
def test_load_protocol_specification_too_many_parts():
"""Test 'load_protocol_specification' with more than three parts."""
with pytest.raises(
diff --git a/tests/test_connections/test_stub.py b/tests/test_connections/test_stub.py
index 42a31ade40..b5b19ef376 100644
--- a/tests/test_connections/test_stub.py
+++ b/tests/test_connections/test_stub.py
@@ -137,11 +137,11 @@ def test_reception_b(self):
def test_reception_c(self):
"""Test that the connection receives what has been enqueued in the input file."""
- encoded_envelope = b"0x5E22777dD831A459535AA4306AceC9cb22eC4cB5,default_oef,fetchai/oef_search:0.3.0,\x08\x02\x12\x011\x1a\x011 \x01:,\n*0x32468dB8Ab79549B49C88DC991990E7910891dbd,"
+ encoded_envelope = b"0x5E22777dD831A459535AA4306AceC9cb22eC4cB5,default_oef,fetchai/oef_search:0.4.0,\x08\x02\x12\x011\x1a\x011 \x01:,\n*0x32468dB8Ab79549B49C88DC991990E7910891dbd,"
expected_envelope = Envelope(
to="0x5E22777dD831A459535AA4306AceC9cb22eC4cB5",
sender="default_oef",
- protocol_id=PublicId.from_str("fetchai/oef_search:0.3.0"),
+ protocol_id=PublicId.from_str("fetchai/oef_search:0.4.0"),
message=b"\x08\x02\x12\x011\x1a\x011 \x01:,\n*0x32468dB8Ab79549B49C88DC991990E7910891dbd",
)
with open(self.input_file_path, "ab+") as f:
@@ -199,7 +199,7 @@ def setup_class(cls):
def test_connection_is_established(self):
"""Test the stub connection is established and then bad formatted messages."""
- assert self.connection.connection_status.is_connected
+ assert self.connection.is_connected
msg = DefaultMessage(
dialogue_reference=("", ""),
message_id=1,
@@ -287,9 +287,9 @@ async def test_disconnection_when_already_disconnected():
output_file_path = d / "output_file.csv"
connection = _make_stub_connection(input_file_path, output_file_path)
- assert not connection.connection_status.is_connected
+ assert not connection.is_connected
await connection.disconnect()
- assert not connection.connection_status.is_connected
+ assert not connection.is_connected
@pytest.mark.asyncio
@@ -302,11 +302,11 @@ async def test_connection_when_already_connected():
output_file_path = d / "output_file.csv"
connection = _make_stub_connection(input_file_path, output_file_path)
- assert not connection.connection_status.is_connected
+ assert not connection.is_connected
await connection.connect()
- assert connection.connection_status.is_connected
+ assert connection.is_connected
await connection.connect()
- assert connection.connection_status.is_connected
+ assert connection.is_connected
await connection.disconnect()
diff --git a/tests/test_crypto/test_cosmos.py b/tests/test_crypto/test_cosmos.py
index 84adf7630a..909390c7b0 100644
--- a/tests/test_crypto/test_cosmos.py
+++ b/tests/test_crypto/test_cosmos.py
@@ -66,6 +66,13 @@ def test_sign_and_recover_message():
), "Failed to recover the correct address."
+def test_get_hash():
+ """Test the get hash functionality."""
+ expected_hash = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
+ hash_ = CosmosApi.get_hash(message=b"hello")
+ assert expected_hash == hash_
+
+
def test_dump_positive():
"""Test dump."""
account = CosmosCrypto(COSMOS_PRIVATE_KEY_PATH)
@@ -169,3 +176,97 @@ def test_get_wealth_positive(caplog):
cc = CosmosCrypto()
cosmos_faucet_api.get_wealth(cc.address)
assert "Wealth generated" in caplog.text
+
+
+@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
+@pytest.mark.integration
+@pytest.mark.ledger
+def test_format_default():
+ """Test if default CosmosSDK transaction is correctly formated."""
+ account = CosmosCrypto(COSMOS_PRIVATE_KEY_PATH)
+ cc2 = CosmosCrypto()
+ cosmos_api = CosmosApi(**COSMOS_TESTNET_CONFIG)
+
+ amount = 10000
+
+ transfer_transaction = cosmos_api.get_transfer_transaction(
+ sender_address=account.address,
+ destination_address=cc2.address,
+ amount=amount,
+ tx_fee=1000,
+ tx_nonce="something",
+ )
+
+ signed_transaction = cc2.sign_transaction(transfer_transaction)
+
+ assert "tx" in signed_transaction
+ assert "signatures" in signed_transaction["tx"]
+ assert len(signed_transaction["tx"]["signatures"]) == 1
+
+ assert "pub_key" in signed_transaction["tx"]["signatures"][0]
+ assert "value" in signed_transaction["tx"]["signatures"][0]["pub_key"]
+ base64_pbk = signed_transaction["tx"]["signatures"][0]["pub_key"]["value"]
+
+ assert "signature" in signed_transaction["tx"]["signatures"][0]
+ signature = signed_transaction["tx"]["signatures"][0]["signature"]
+
+ default_formated_transaction = cc2.format_default_transaction(
+ transfer_transaction, signature, base64_pbk
+ )
+
+ # Compare default formatted transaction with signed transaction
+ assert signed_transaction == default_formated_transaction
+
+
+@pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS)
+@pytest.mark.integration
+@pytest.mark.ledger
+def test_format_cosmwasm():
+ """Test if CosmWasm transaction is correctly formated."""
+ cc2 = CosmosCrypto()
+
+ # Dummy CosmWasm transaction
+ wasm_transaction = {
+ "account_number": "8",
+ "chain_id": "agent-land",
+ "fee": {"amount": [], "gas": "200000"},
+ "memo": "",
+ "msgs": [
+ {
+ "type": "wasm/execute",
+ "value": {
+ "sender": "cosmos14xjnl2mwwfz6pztpwzj6s89npxr0e3lhxl52nv",
+ "contract": "cosmos1xzlgeyuuyqje79ma6vllregprkmgwgav5zshcm",
+ "msg": {
+ "create_single": {
+ "item_owner": "cosmos1fz0dcvvqv5at6dl39804jy92lnndf3d5saalx6",
+ "id": "1234",
+ "path": "SOME_URI",
+ }
+ },
+ "sent_funds": [],
+ },
+ }
+ ],
+ "sequence": "25",
+ }
+
+ signed_transaction = cc2.sign_transaction(wasm_transaction)
+
+ assert "value" in signed_transaction
+ assert "signatures" in signed_transaction["value"]
+ assert len(signed_transaction["value"]["signatures"]) == 1
+
+ assert "pub_key" in signed_transaction["value"]["signatures"][0]
+ assert "value" in signed_transaction["value"]["signatures"][0]["pub_key"]
+ base64_pbk = signed_transaction["value"]["signatures"][0]["pub_key"]["value"]
+
+ assert "signature" in signed_transaction["value"]["signatures"][0]
+ signature = signed_transaction["value"]["signatures"][0]["signature"]
+
+ wasm_formated_transaction = cc2.format_wasm_transaction(
+ wasm_transaction, signature, base64_pbk
+ )
+
+ # Compare Wasm formatted transaction with signed transaction
+ assert signed_transaction == wasm_formated_transaction
diff --git a/tests/test_crypto/test_ethereum.py b/tests/test_crypto/test_ethereum.py
index 3ff715ae20..6cbf0b79f7 100644
--- a/tests/test_crypto/test_ethereum.py
+++ b/tests/test_crypto/test_ethereum.py
@@ -95,6 +95,13 @@ def test_sign_and_recover_message_deprecated():
), "Failed to recover the correct address."
+def test_get_hash():
+ """Test the get hash functionality."""
+ expected_hash = "0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"
+ hash_ = EthereumApi.get_hash(message=b"hello")
+ assert expected_hash == hash_
+
+
def test_dump_positive():
"""Test dump."""
account = EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH)
diff --git a/tests/test_crypto/test_fetchai.py b/tests/test_crypto/test_fetchai.py
index 7bdb7471d7..41421b7f8f 100644
--- a/tests/test_crypto/test_fetchai.py
+++ b/tests/test_crypto/test_fetchai.py
@@ -69,6 +69,13 @@ def test_get_address_from_public_key():
assert address == fet_crypto.address, "The address must be the same."
+def test_get_hash():
+ """Test the get hash functionality."""
+ expected_hash = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
+ hash_ = FetchAIApi.get_hash(message=b"hello")
+ assert expected_hash == hash_
+
+
def test_dump_positive():
"""Test dump."""
account = FetchAICrypto(FETCHAI_PRIVATE_KEY_PATH)
diff --git a/tests/test_crypto/test_helpers.py b/tests/test_crypto/test_helpers.py
index 653e048b21..cbd558893b 100644
--- a/tests/test_crypto/test_helpers.py
+++ b/tests/test_crypto/test_helpers.py
@@ -21,6 +21,7 @@
import logging
import os
+from pathlib import Path
from unittest.mock import mock_open, patch
import pytest
@@ -34,9 +35,16 @@
create_private_key,
try_generate_testnet_wealth,
try_validate_private_key_path,
+ verify_or_create_private_keys,
)
-from tests.conftest import CUR_PATH, ETHEREUM_PRIVATE_KEY_PATH, FETCHAI_PRIVATE_KEY_PATH
+from tests.conftest import (
+ COSMOS_PRIVATE_KEY_FILE,
+ CUR_PATH,
+ ETHEREUM_PRIVATE_KEY_FILE,
+ ETHEREUM_PRIVATE_KEY_PATH,
+ FETCHAI_PRIVATE_KEY_PATH,
+)
logger = logging.getLogger(__name__)
@@ -129,9 +137,15 @@ def test_try_validate_private_key_path_positive(self):
@patch("builtins.open", mock_open())
def test__create_ethereum_private_key_positive(self, *mocks):
"""Test _create_ethereum_private_key positive result."""
- create_private_key(EthereumCrypto.identifier)
+ create_private_key(EthereumCrypto.identifier, ETHEREUM_PRIVATE_KEY_FILE)
@patch("builtins.open", mock_open())
def test__create_cosmos_private_key_positive(self, *mocks):
"""Test _create_cosmos_private_key positive result."""
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
+
+ @patch("aea.crypto.helpers.create_private_key")
+ @patch("aea.crypto.helpers.try_validate_private_key_path")
+ def test_verify_or_create_private_keys(self, *mocks):
+ """Test _create_ethereum_private_key positive result."""
+ verify_or_create_private_keys(Path(os.path.join(CUR_PATH, "data", "dummy_aea")))
diff --git a/tests/test_crypto/test_ledger_apis.py b/tests/test_crypto/test_ledger_apis.py
index 82a3f0a8b8..a308cc991b 100644
--- a/tests/test_crypto/test_ledger_apis.py
+++ b/tests/test_crypto/test_ledger_apis.py
@@ -28,15 +28,11 @@
from aea.crypto.ethereum import EthereumApi
from aea.crypto.fetchai import FetchAIApi
from aea.crypto.ledger_apis import LedgerApis
-from aea.exceptions import AEAException
from tests.conftest import (
- COSMOS_TESTNET_CONFIG,
ETHEREUM_ADDRESS_ONE,
- ETHEREUM_TESTNET_CONFIG,
FETCHAI,
FETCHAI_ADDRESS_ONE,
- FETCHAI_TESTNET_CONFIG,
)
logger = logging.getLogger(__name__)
@@ -48,24 +44,15 @@ def _raise_exception(*args, **kwargs):
def test_initialisation():
"""Test the initialisation of the ledger APIs."""
- ledger_apis = LedgerApis(
- {
- EthereumApi.identifier: ETHEREUM_TESTNET_CONFIG,
- FetchAIApi.identifier: FETCHAI_TESTNET_CONFIG,
- CosmosApi.identifier: COSMOS_TESTNET_CONFIG,
- },
- FetchAIApi.identifier,
- )
- assert ledger_apis.configs.get(EthereumApi.identifier) == ETHEREUM_TESTNET_CONFIG
+ ledger_apis = LedgerApis
assert ledger_apis.has_ledger(FetchAIApi.identifier)
- assert type(ledger_apis.get_api(FetchAIApi.identifier)) == FetchAIApi
- assert ledger_apis.has_ledger(EthereumApi.identifier)
- assert type(ledger_apis.get_api(EthereumApi.identifier)) == EthereumApi
- assert ledger_apis.has_ledger(CosmosApi.identifier)
- assert type(ledger_apis.get_api(CosmosApi.identifier)) == CosmosApi
- unknown_config = {"UnknownPath": 8080}
- with pytest.raises(AEAException):
- LedgerApis({"UNKNOWN": unknown_config}, FetchAIApi.identifier)
+ assert type(LedgerApis.get_api(FetchAIApi.identifier)) == FetchAIApi
+ assert LedgerApis.has_ledger(EthereumApi.identifier)
+ assert type(LedgerApis.get_api(EthereumApi.identifier)) == EthereumApi
+ assert LedgerApis.has_ledger(CosmosApi.identifier)
+ assert type(LedgerApis.get_api(CosmosApi.identifier)) == CosmosApi
+ with pytest.raises(AssertionError):
+ ledger_apis.get_api("UNKNOWN")
class TestLedgerApis:
@@ -74,37 +61,20 @@ class TestLedgerApis:
@classmethod
def setup_class(cls):
"""Setup the test case."""
- cls.ledger_apis = LedgerApis(
- {
- EthereumApi.identifier: ETHEREUM_TESTNET_CONFIG,
- FetchAIApi.identifier: FETCHAI_TESTNET_CONFIG,
- },
- FetchAIApi.identifier,
- )
+ cls.ledger_apis = LedgerApis
def test_get_balance(self):
"""Test the get_balance."""
- api = self.ledger_apis.apis[EthereumApi.identifier]
- with mock.patch.object(api.api.eth, "getBalance", return_value=10):
+ with mock.patch.object(EthereumApi, "get_balance", return_value=10):
balance = self.ledger_apis.get_balance(
EthereumApi.identifier, ETHEREUM_ADDRESS_ONE
)
assert balance == 10
- with mock.patch.object(
- api.api.eth, "getBalance", return_value=0, side_effect=Exception
- ):
- balance = self.ledger_apis.get_balance(
- EthereumApi.identifier, FETCHAI_ADDRESS_ONE
- )
- assert balance is None, "This must be None since the address is wrong"
-
def test_get_transfer_transaction(self):
"""Test the get_transfer_transaction."""
with mock.patch.object(
- self.ledger_apis.apis.get(FetchAIApi.identifier),
- "get_transfer_transaction",
- return_value="mock_transaction",
+ FetchAIApi, "get_transfer_transaction", return_value="mock_transaction",
):
tx = self.ledger_apis.get_transfer_transaction(
identifier=FETCHAI,
@@ -119,7 +89,7 @@ def test_get_transfer_transaction(self):
def test_send_signed_transaction(self):
"""Test the send_signed_transaction."""
with mock.patch.object(
- self.ledger_apis.apis.get(FetchAIApi.identifier),
+ FetchAIApi,
"send_signed_transaction",
return_value="mock_transaction_digest",
):
@@ -131,7 +101,7 @@ def test_send_signed_transaction(self):
def test_get_transaction_receipt(self):
"""Test the get_transaction_receipt."""
with mock.patch.object(
- self.ledger_apis.apis.get(FetchAIApi.identifier),
+ FetchAIApi,
"get_transaction_receipt",
return_value="mock_transaction_receipt",
):
@@ -143,9 +113,7 @@ def test_get_transaction_receipt(self):
def test_get_transaction(self):
"""Test the get_transaction."""
with mock.patch.object(
- self.ledger_apis.apis.get(FetchAIApi.identifier),
- "get_transaction",
- return_value="mock_transaction",
+ FetchAIApi, "get_transaction", return_value="mock_transaction",
):
tx = self.ledger_apis.get_transaction(
identifier=FETCHAI, tx_digest="tx_digest",
@@ -177,13 +145,27 @@ def test_is_transaction_valid(self):
)
assert is_valid
+ def test_recover_message(self):
+ """Test the is_transaction_valid."""
+ expected_addresses = ("address_1", "address_2")
+ with mock.patch.object(
+ FetchAIApi, "recover_message", return_value=expected_addresses,
+ ):
+ addresses = self.ledger_apis.recover_message(
+ identifier="fetchai", message="message", signature="signature",
+ )
+ assert addresses == expected_addresses
+
+ def test_get_hash(self):
+ """Test the is_transaction_valid."""
+ expected_hash = "hash"
+ with mock.patch.object(
+ FetchAIApi, "get_hash", return_value=expected_hash,
+ ):
+ hash_ = self.ledger_apis.get_hash(identifier="fetchai", message=b"message",)
+ assert hash_ == expected_hash
+
def test_generate_tx_nonce_positive(self):
"""Test generate_tx_nonce positive result."""
- result = self.ledger_apis.generate_tx_nonce(
- FetchAIApi.identifier, "seller", "client"
- )
+ result = LedgerApis.generate_tx_nonce(FetchAIApi.identifier, "seller", "client")
assert int(result, 16)
-
- def test_has_default_ledger_positive(self):
- """Test has_default_ledger init positive result."""
- assert self.ledger_apis.has_default_ledger
diff --git a/tests/test_crypto/test_wallet.py b/tests/test_crypto/test_wallet.py
index b1eff2adf0..2cb4df79ab 100644
--- a/tests/test_crypto/test_wallet.py
+++ b/tests/test_crypto/test_wallet.py
@@ -104,6 +104,18 @@ def test_wallet_addresses_positive(self):
tuple(addresses), (EthereumCrypto.identifier, FetchAICrypto.identifier)
)
+ def test_wallet_private_keys_positive(self):
+ """Test Wallet.private_keys init positive result."""
+ private_key_paths = {
+ EthereumCrypto.identifier: ETHEREUM_PRIVATE_KEY_PATH,
+ FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_PATH,
+ }
+ wallet = Wallet(private_key_paths)
+ private_keys = wallet.private_keys
+ self.assertTupleEqual(
+ tuple(private_keys), (EthereumCrypto.identifier, FetchAICrypto.identifier)
+ )
+
def test_wallet_cryptos_positive(self):
"""Test Wallet.main_cryptos and connection cryptos init positive result."""
private_key_paths = {
diff --git a/tests/test_decision_maker/test_default.py b/tests/test_decision_maker/test_default.py
index 906abd92fc..820070df92 100644
--- a/tests/test_decision_maker/test_default.py
+++ b/tests/test_decision_maker/test_default.py
@@ -157,7 +157,7 @@ def _unpatch_logger(cls):
cls.mocked_logger_warning.__exit__()
@classmethod
- def setup_class(cls):
+ def setup(cls):
"""Initialise the decision maker."""
cls._patch_logger()
cls.wallet = Wallet(
@@ -239,7 +239,7 @@ def test_decision_maker_handle_state_update_initialize_and_apply(self):
quantities_by_good_id=good_deltas,
)
state_update_message_2.counterparty = "decision_maker"
- state_update_dialogue.update(state_update_message_2)
+ assert state_update_dialogue.update(state_update_message_2)
self.decision_maker.handle(state_update_message_2)
expected_amount_by_currency_id = {
key: currency_holdings.get(key, 0) + currency_deltas.get(key, 0)
@@ -259,7 +259,7 @@ def test_decision_maker_handle_state_update_initialize_and_apply(self):
)
@classmethod
- def teardown_class(cls):
+ def teardown(cls):
"""Tear the tests down."""
cls._unpatch_logger()
cls.decision_maker.stop()
@@ -280,7 +280,7 @@ def _unpatch_logger(cls):
cls.mocked_logger_warning.__exit__()
@classmethod
- def setup_class(cls):
+ def setup(cls):
"""Initialise the decision maker."""
cls._patch_logger()
cls.wallet = Wallet(
@@ -333,7 +333,7 @@ def test_handle_tx_signing_fetchai(self):
1,
[],
)
- signing_dialogues = SigningDialogues("agent1")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_TRANSACTION,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -351,8 +351,14 @@ def test_handle_tx_signing_fetchai(self):
raw_transaction=RawTransaction(FETCHAI, tx),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert (
signing_msg_response.performative
== SigningMessage.Performative.SIGNED_TRANSACTION
@@ -363,7 +369,7 @@ def test_handle_tx_signing_fetchai(self):
def test_handle_tx_signing_ethereum(self):
"""Test tx signing for ethereum."""
tx = {"gasPrice": 30, "nonce": 1, "gas": 20000}
- signing_dialogues = SigningDialogues("agent2")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_TRANSACTION,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -381,8 +387,14 @@ def test_handle_tx_signing_ethereum(self):
raw_transaction=RawTransaction(ETHEREUM, tx),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert (
signing_msg_response.performative
== SigningMessage.Performative.SIGNED_TRANSACTION
@@ -396,7 +408,7 @@ def test_handle_tx_signing_ethereum(self):
def test_handle_tx_signing_unknown(self):
"""Test tx signing for unknown."""
tx = {}
- signing_dialogues = SigningDialogues("agent3")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_TRANSACTION,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -414,8 +426,14 @@ def test_handle_tx_signing_unknown(self):
raw_transaction=RawTransaction("unknown", tx),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert signing_msg_response.performative == SigningMessage.Performative.ERROR
assert signing_msg_response.skill_callback_ids == signing_msg.skill_callback_ids
assert (
@@ -426,7 +444,7 @@ def test_handle_tx_signing_unknown(self):
def test_handle_message_signing_fetchai(self):
"""Test message signing for fetchai."""
message = b"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d"
- signing_dialogues = SigningDialogues("agent4")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_MESSAGE,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -444,8 +462,14 @@ def test_handle_message_signing_fetchai(self):
raw_message=RawMessage(FETCHAI, message),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert (
signing_msg_response.performative
== SigningMessage.Performative.SIGNED_MESSAGE
@@ -456,7 +480,7 @@ def test_handle_message_signing_fetchai(self):
def test_handle_message_signing_ethereum(self):
"""Test message signing for ethereum."""
message = b"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d"
- signing_dialogues = SigningDialogues("agent4")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_MESSAGE,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -474,8 +498,14 @@ def test_handle_message_signing_ethereum(self):
raw_message=RawMessage(ETHEREUM, message),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert (
signing_msg_response.performative
== SigningMessage.Performative.SIGNED_MESSAGE
@@ -486,7 +516,7 @@ def test_handle_message_signing_ethereum(self):
def test_handle_message_signing_ethereum_deprecated(self):
"""Test message signing for ethereum deprecated."""
message = b"0x11f3f9487724404e3a1fb7252a3226"
- signing_dialogues = SigningDialogues("agent5")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_MESSAGE,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -504,8 +534,14 @@ def test_handle_message_signing_ethereum_deprecated(self):
raw_message=RawMessage(ETHEREUM, message, is_deprecated_mode=True),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert (
signing_msg_response.performative
== SigningMessage.Performative.SIGNED_MESSAGE
@@ -514,10 +550,10 @@ def test_handle_message_signing_ethereum_deprecated(self):
assert type(signing_msg_response.signed_message) == SignedMessage
assert signing_msg_response.signed_message.is_deprecated_mode
- def test_handle_message_signing_unknown(self):
+ def test_handle_message_signing_unknown_and_two_dialogues(self):
"""Test message signing for unknown."""
message = b"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d"
- signing_dialogues = SigningDialogues("agent6")
+ signing_dialogues = SigningDialogues("agent")
signing_msg = SigningMessage(
performative=SigningMessage.Performative.SIGN_MESSAGE,
dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
@@ -535,8 +571,14 @@ def test_handle_message_signing_unknown(self):
raw_message=RawMessage("unknown", message),
)
signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
self.decision_maker.message_in_queue.put_nowait(signing_msg)
signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ signing_msg_response.counterparty = signing_msg.counterparty
+ signing_msg_response.is_incoming = True
+ recovered_dialogue = signing_dialogues.update(signing_msg_response)
+ assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue
assert signing_msg_response.performative == SigningMessage.Performative.ERROR
assert signing_msg_response.skill_callback_ids == signing_msg.skill_callback_ids
assert (
@@ -544,8 +586,59 @@ def test_handle_message_signing_unknown(self):
== SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING
)
+ def test_handle_messages_from_two_dialogues_same_agent(self):
+ """Test message signing for unknown."""
+ message = b"0x11f3f9487724404e3a1fb7252a322656b90ba0455a2ca5fcdcbe6eeee5f8126d"
+ signing_dialogues = SigningDialogues("agent")
+ signing_msg = SigningMessage(
+ performative=SigningMessage.Performative.SIGN_MESSAGE,
+ dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
+ skill_callback_ids=(str(PublicId("author", "a_skill", "0.1.0")),),
+ skill_callback_info={},
+ terms=Terms(
+ ledger_id="unknown",
+ sender_address="pk1",
+ counterparty_address="pk2",
+ amount_by_currency_id={"FET": -1},
+ is_sender_payable_tx_fee=True,
+ quantities_by_good_id={"good_id": 10},
+ nonce="transaction nonce",
+ ),
+ raw_message=RawMessage("unknown", message),
+ )
+ signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
+ self.decision_maker.message_in_queue.put_nowait(signing_msg)
+ signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2)
+ assert signing_msg_response is not None
+ signing_dialogues = SigningDialogues("agent")
+ signing_msg = SigningMessage(
+ performative=SigningMessage.Performative.SIGN_MESSAGE,
+ dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(),
+ skill_callback_ids=(str(PublicId("author", "a_skill", "0.1.0")),),
+ skill_callback_info={},
+ terms=Terms(
+ ledger_id="unknown",
+ sender_address="pk1",
+ counterparty_address="pk2",
+ amount_by_currency_id={"FET": -1},
+ is_sender_payable_tx_fee=True,
+ quantities_by_good_id={"good_id": 10},
+ nonce="transaction nonce",
+ ),
+ raw_message=RawMessage("unknown", message),
+ )
+ signing_msg.counterparty = "decision_maker"
+ signing_dialogue = signing_dialogues.update(signing_msg)
+ assert signing_dialogue is not None
+ self.decision_maker.message_in_queue.put_nowait(signing_msg)
+ with pytest.raises(Exception):
+ # Exception occurs because the same counterparty sends two identical dialogue references
+ self.decision_maker.message_out_queue.get(timeout=1)
+
@classmethod
- def teardown_class(cls):
+ def teardown(cls):
"""Tear the tests down."""
cls._unpatch_logger()
cls.decision_maker.stop()
diff --git a/tests/test_docs/test_agent_vs_aea/agent_code_block.py b/tests/test_docs/test_agent_vs_aea/agent_code_block.py
index 9ea0ac8d70..f7125f336e 100644
--- a/tests/test_docs/test_agent_vs_aea/agent_code_block.py
+++ b/tests/test_docs/test_agent_vs_aea/agent_code_block.py
@@ -60,6 +60,8 @@ def react(self):
envelope.to = sender
envelope.sender = receiver
envelope.message = DefaultMessage.serializer.decode(envelope.message)
+ envelope.message.sender = receiver
+ envelope.message.counterparty = sender
print(
"Received envelope from {} with protocol_id={}".format(
sender, envelope.protocol_id
@@ -105,7 +107,7 @@ def run():
# Create a message inside an envelope and get the stub connection to pass it into the agent
message_text = (
- b"my_agent,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ b"my_agent,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "wb") as f:
f.write(message_text)
diff --git a/tests/test_docs/test_agent_vs_aea/test_agent_vs_aea.py b/tests/test_docs/test_agent_vs_aea/test_agent_vs_aea.py
index fc04436a4d..49c063d050 100644
--- a/tests/test_docs/test_agent_vs_aea/test_agent_vs_aea.py
+++ b/tests/test_docs/test_agent_vs_aea/test_agent_vs_aea.py
@@ -60,7 +60,7 @@ def test_run_agent(self):
assert os.path.exists(Path(self.t, "input_file"))
message_text = (
- b"other_agent,my_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ b"other_agent,my_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
path = os.path.join(self.t, "output_file")
with open(path, "rb") as file:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md b/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md
index 01ed53e241..318725812a 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-aries-cloud-agent-demo.md
@@ -11,53 +11,23 @@ aca-py start --admin 127.0.0.1 8021 --admin-insecure-mode --inbound-transport ht
aca-py start --admin 127.0.0.1 8031 --admin-insecure-mode --inbound-transport http 0.0.0.0 8030 --outbound-transp http --webhook-url http://127.0.0.1:8032/webhooks
```
``` bash
-aea create aries_alice
+aea fetch fetchai/aries_alice:0.7.0
cd aries_alice
```
``` bash
-aea add skill fetchai/aries_alice:0.3.0
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_port 8031
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_port 8031
-```
-``` bash
-aea add connection fetchai/http_client:0.5.0
-aea add connection fetchai/webhook:0.4.0
-aea add connection fetchai/oef:0.6.0
-```
-``` bash
-aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032
-```
-``` bash
-aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
-```
-``` bash
-aea config set agent.default_connection fetchai/oef:0.6.0
-```
-``` bash
-aea fetch fetchai/aries_alice:0.6.0
+aea create aries_alice
cd aries_alice
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/http_client:0.6.0
+aea add connection fetchai/webhook:0.5.0
+aea add skill fetchai/aries_alice:0.4.0
```
``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_host 127.0.0.1
+aea config set vendor.fetchai.skills.aries_alice.behaviours.alice.args.admin_host 127.0.0.1
```
``` bash
-aea config set vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_default.args.admin_port 8031
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_alice.handlers.aries_demo_http.args.admin_port 8031
+aea config set --type int vendor.fetchai.skills.aries_alice.behaviours.alice.args.admin_port 8031
```
``` bash
aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8032
@@ -72,34 +42,23 @@ aea install
aea run
```
``` bash
-My address is: YrP7H2qdCb3VyPwpQa53o39cWCDHhVcjwCtJLes6HKWM8FpVK
+aea fetch fetchai/aries_faber:0.7.0
+cd aries_faber
```
``` bash
aea create aries_faber
cd aries_faber
-```
-``` bash
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/http_client:0.6.0
+aea add connection fetchai/webhook:0.5.0
aea add skill fetchai/aries_faber:0.3.0
```
``` bash
-aea config set vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_host 127.0.0.1
+aea config set vendor.fetchai.skills.aries_faber.behaviours.faber.args.admin_host 127.0.0.1
```
``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_port 8021
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_port 8021
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.alice_id
-```
-``` bash
-aea add connection fetchai/http_client:0.5.0
-aea add connection fetchai/webhook:0.4.0
-aea add connection fetchai/oef:0.6.0
+aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.faber.args.admin_port 8021
```
``` bash
aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022
@@ -107,33 +66,13 @@ aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port
``` bash
aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
```
-``` bash
-aea config set agent.default_connection fetchai/http_client:0.5.0
-```
-``` bash
-aea fetch fetchai/aries_faber:0.6.0
-cd aries_faber
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_host 127.0.0.1
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.behaviours.aries_demo_faber.args.admin_port 8021
-```
-``` bash
-aea config set --type int vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.admin_port 8021
-```
-``` bash
-aea config set vendor.fetchai.skills.aries_faber.handlers.aries_demo_http.args.alice_id
-```
-``` bash
-aea config set --type int vendor.fetchai.connections.webhook.config.webhook_port 8022
-```
-``` bash
-aea config set vendor.fetchai.connections.webhook.config.webhook_url_path /webhooks/topic/{topic}/
+``` yaml
+config:
+ delegate_uri: 127.0.0.1:11001
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9001
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9001
```
``` bash
aea install
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md
index 0b697f31f2..bb97393016 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-car-park-skills.md
@@ -1,32 +1,32 @@
``` bash
-aea fetch fetchai/car_detector:0.8.0
+aea fetch fetchai/car_detector:0.9.0
cd car_detector
aea install
```
``` bash
aea create car_detector
cd car_detector
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/carpark_detection:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/carpark_detection:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/car_data_buyer:0.8.0
+aea fetch fetchai/car_data_buyer:0.9.0
cd car_data_buyer
aea install
```
``` bash
aea create car_data_buyer
cd car_data_buyer
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/carpark_client:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/carpark_client:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea generate-key cosmos
@@ -54,13 +54,13 @@ aea delete car_data_buyer
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
config:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md b/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md
index 89452aad60..d125e1fbee 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-cli-how-to.md
@@ -7,3 +7,9 @@ pip install aea[all]
``` bash
pip install aea[all] --force --no-cache-dir
```
+```bash
+aea
+```
+``` bash
+python -m aea.cli
+```
\ No newline at end of file
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md b/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md
index 4cd58d6a40..1c74dc9202 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-cli-vs-programmatic-aeas.md
@@ -2,7 +2,7 @@
svn export https://github.com/fetchai/agents-aea.git/trunk/packages
```
``` bash
-aea fetch fetchai/weather_station:0.8.0
+aea fetch fetchai/weather_station:0.9.0
cd weather_station
```
``` bash
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-config.md b/tests/test_docs/test_bash_yaml/md_files/bash-config.md
index d96c6f3cfe..b65193795b 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-config.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-config.md
@@ -14,13 +14,13 @@ aea_version: '>=0.5.0, <0.6.0' # AEA framework version(s) compa
fingerprint: {} # Fingerprint of AEA project components.
fingerprint_ignore_patterns: [] # Ignore pattern for the fingerprinting tool.
connections: # The list of connection public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX)
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
contracts: [] # The list of contract public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
protocols: # The list of protocol public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills: # The list of skill public ids the AEA project depends on (each public id must satisfy PUBLIC_ID_REGEX).
-- fetchai/error:0.3.0
-default_connection: fetchai/oef:0.6.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).
+- fetchai/error:0.4.0
+default_connection: fetchai/p2p_libp2p:0.6.0 # The default connection used for envelopes sent by the AEA (must satisfy PUBLIC_ID_REGEX).
default_ledger: cosmos # The default ledger identifier the AEA project uses (must satisfy LEDGER_ID_REGEX)
logging_config: # The logging configurations the AEA project uses
disable_existing_loggers: false
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md
index 84c7c81516..c389beb6ab 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-erc1155-skills.md
@@ -1,19 +1,17 @@
``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-``` bash
-aea fetch fetchai/erc1155_deployer:0.9.0
+aea fetch fetchai/erc1155_deployer:0.10.0
cd erc1155_deployer
aea install
```
``` bash
aea create erc1155_deployer
cd erc1155_deployer
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/erc1155_deploy:0.9.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/erc1155_deploy:0.10.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea config set agent.default_ledger ethereum
@@ -23,18 +21,23 @@ aea generate-key ethereum
aea add-key ethereum eth_private_key.txt
```
``` bash
-aea fetch fetchai/erc1155_client:0.9.0
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt --connection
+```
+``` bash
+aea fetch fetchai/erc1155_client:0.10.0
cd erc1155_client
aea install
```
``` bash
aea create erc1155_client
cd erc1155_client
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/erc1155_client:0.8.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/erc1155_client:0.9.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea config set agent.default_ledger ethereum
@@ -44,12 +47,19 @@ aea generate-key ethereum
aea add-key ethereum eth_private_key.txt
```
``` bash
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt --connection
+```
+``` bash
aea generate-wealth ethereum
```
``` bash
aea get-wealth ethereum
```
``` bash
+aea config set vendor.fetchai.connections.soef.config.chain_identifier ethereum
+```
+``` bash
aea run
```
``` bash
@@ -65,11 +75,13 @@ aea delete erc1155_client
```
``` yaml
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/contract_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/contract_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md
index d88dfec621..76e2da3eae 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills-step-by-step.md
@@ -5,15 +5,15 @@ sudo nano 99-hidraw-permissions.rules
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"
```
``` bash
-aea fetch fetchai/generic_seller:0.5.0
+aea fetch fetchai/generic_seller:0.6.0
cd generic_seller
-aea eject skill fetchai/generic_seller:0.8.0
+aea eject skill fetchai/generic_seller:0.9.0
cd ..
```
``` bash
-aea fetch fetchai/generic_buyer:0.5.0
+aea fetch fetchai/generic_buyer:0.6.0
cd generic_buyer
-aea eject skill fetchai/generic_buyer:0.7.0
+aea eject skill fetchai/generic_buyer:0.8.0
cd ..
```
``` bash
@@ -47,10 +47,11 @@ aea add-key fetchai fet_private_key.txt
aea generate-wealth fetchai
```
``` bash
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea run
```
``` bash
@@ -58,10 +59,11 @@ aea generate-key ethereum
aea add-key ethereum eth_private_key.txt
```
``` bash
-aea add connection fetchai/oef:0.6.0
-aea add connection fetchai/ledger:0.2.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea run
```
``` bash
@@ -86,10 +88,10 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
service_registration:
@@ -154,10 +156,10 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/default:0.3.0
-- fetchai/fipa:0.4.0
-- fetchai/ledger_api:0.1.0
-- fetchai/oef_search:0.3.0
+- fetchai/default:0.4.0
+- fetchai/fipa:0.5.0
+- fetchai/ledger_api:0.2.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
search:
@@ -218,7 +220,7 @@ addr: ${OEF_ADDR: 127.0.0.1}
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
```
``` yaml
currency_id: 'ETH'
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md
index 179ffe3f5d..3b480ae1ee 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-generic-skills.md
@@ -1,32 +1,32 @@
``` bash
-aea fetch fetchai/generic_seller:0.5.0 --alias my_seller_aea
+aea fetch fetchai/generic_seller:0.6.0 --alias my_seller_aea
cd my_seller_aea
aea install
```
``` bash
aea create my_seller_aea
cd my_seller_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/generic_seller:0.8.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/generic_seller:0.9.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/generic_buyer:0.5.0 --alias my_buyer_aea
+aea fetch fetchai/generic_buyer:0.6.0 --alias my_buyer_aea
cd my_buyer_aea
aea install
```
``` bash
aea create my_buyer_aea
cd my_buyer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/generic_buyer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/generic_buyer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea generate-key cosmos
@@ -62,13 +62,13 @@ aea delete my_buyer_aea
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
models:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md
index 0fc25aad6c..7f0ac07917 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-gym-skill.md
@@ -1,5 +1,5 @@
``` bash
-aea fetch fetchai/gym_aea:0.6.0 --alias my_gym_aea
+aea fetch fetchai/gym_aea:0.7.0 --alias my_gym_aea
cd my_gym_aea
aea install
```
@@ -8,11 +8,11 @@ aea create my_gym_aea
cd my_gym_aea
```
``` bash
-aea add skill fetchai/gym:0.4.0
+aea add skill fetchai/gym:0.5.0
```
``` bash
-aea add connection fetchai/gym:0.4.0
-aea config set agent.default_connection fetchai/gym:0.4.0
+aea add connection fetchai/gym:0.5.0
+aea config set agent.default_connection fetchai/gym:0.5.0
```
``` bash
aea install
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md
index 38af6c6f41..1d8ef32e2b 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-http-connection-and-skill.md
@@ -3,10 +3,10 @@ aea create my_aea
cd my_aea
```
``` bash
-aea add connection fetchai/http_server:0.5.0
+aea add connection fetchai/http_server:0.6.0
```
``` bash
-aea config set agent.default_connection fetchai/http_server:0.5.0
+aea config set agent.default_connection fetchai/http_server:0.6.0
```
``` bash
aea config set vendor.fetchai.connections.http_server.config.api_spec_path "../examples/http_ex/petstore.yaml"
@@ -18,7 +18,7 @@ aea install
aea scaffold skill http_echo
```
``` bash
-aea fingerprint skill fetchai/http_echo:0.3.0
+aea fingerprint skill fetchai/http_echo:0.4.0
```
``` bash
aea run
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-logging.md b/tests/test_docs/test_bash_yaml/md_files/bash-logging.md
index 0d8b7ccc21..906884ba29 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-logging.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-logging.md
@@ -8,17 +8,17 @@ author: fetchai
version: 0.1.0
description: ''
license: Apache-2.0
-aea_version: 0.5.2
+aea_version: 0.5.3
fingerprint: {}
fingerprint_ignore_patterns: []
connections:
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
contracts: []
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
skills:
-- fetchai/error:0.3.0
-default_connection: fetchai/stub:0.6.0
+- fetchai/error:0.4.0
+default_connection: fetchai/stub:0.7.0
default_ledger: cosmos
logging_config:
disable_existing_loggers: false
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md
index 64f8543f6b..93b4e6afc2 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-ml-skills.md
@@ -1,31 +1,31 @@
``` bash
-aea fetch fetchai/ml_data_provider:0.8.0
+aea fetch fetchai/ml_data_provider:0.9.0
cd ml_data_provider
aea install
```
``` bash
aea create ml_data_provider
cd ml_data_provider
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/ml_data_provider:0.7.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/ml_data_provider:0.8.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea install
```
``` bash
-aea fetch fetchai/ml_model_trainer:0.8.0
+aea fetch fetchai/ml_model_trainer:0.9.0
cd ml_model_trainer
aea install
```
``` bash
aea create ml_model_trainer
cd ml_model_trainer
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/ml_train:0.7.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/ml_train:0.8.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea install
```
``` bash
@@ -54,13 +54,13 @@ aea delete ml_model_trainer
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
config:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md b/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md
index 8ad251bf99..f6c140d02e 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-oef-ledger.md
@@ -1,3 +1,7 @@
``` bash
python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
```
+``` bash
+svn export https://github.com/fetchai/agents-aea.git/trunk/examples
+svn export https://github.com/fetchai/agents-aea.git/trunk/scripts
+```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md b/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md
index f7f3d6c466..afdb1aa3a7 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-orm-integration.md
@@ -1,32 +1,32 @@
``` bash
-aea fetch fetchai/thermometer_aea:0.6.0 --alias my_thermometer_aea
+aea fetch fetchai/thermometer_aea:0.7.0 --alias my_thermometer_aea
cd my_thermometer_aea
aea install
```
``` bash
aea create my_thermometer_aea
cd my_thermometer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/thermometer_client:0.6.0 --alias my_thermometer_client
+aea fetch fetchai/thermometer_client:0.7.0 --alias my_thermometer_client
cd my_thermometer_client
aea install
```
``` bash
aea create my_thermometer_client
cd my_thermometer_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea generate-key cosmos
@@ -45,7 +45,7 @@ aea generate-wealth cosmos
aea install
```
``` bash
-aea eject skill fetchai/thermometer:0.7.0
+aea eject skill fetchai/thermometer:0.8.0
```
``` bash
aea fingerprint skill {YOUR_AUTHOR_HANDLE}/thermometer:0.1.0
@@ -63,13 +63,13 @@ aea delete my_thermometer_client
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
models:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md b/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md
index 35a788621d..40802b1517 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-p2p-connection.md
@@ -1,31 +1,31 @@
``` bash
aea create my_genesis_aea
cd my_genesis_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
-aea run --connections fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea run --connections fetchai/p2p_libp2p:0.6.0
```
``` bash
aea create my_other_aea
cd my_other_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea run --connections fetchai/p2p_libp2p:0.5.0
+aea run --connections fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/weather_station:0.8.0
-aea fetch fetchai/weather_client:0.8.0
+aea fetch fetchai/weather_station:0.9.0
+aea fetch fetchai/weather_client:0.9.0
```
``` bash
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
``` bash
python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
```
``` bash
-aea run --connections "fetchai/p2p_libp2p:0.5.0,fetchai/oef:0.6.0"
+aea run --connections "fetchai/p2p_libp2p:0.6.0,fetchai/oef:0.7.0"
```
``` bash
My libp2p addresses: ...
@@ -38,7 +38,7 @@ aea add-key fetchai fet_private_key.txt
aea generate-wealth fetchai
```
``` bash
-aea run --connections "fetchai/p2p_libp2p:0.5.0,fetchai/oef:0.6.0"
+aea run --connections "fetchai/p2p_libp2p:0.6.0,fetchai/oef:0.7.0"
```
``` yaml
config:
@@ -50,8 +50,8 @@ config:
```
``` yaml
default_routing:
- ? "fetchai/oef_search:0.3.0"
- : "fetchai/oef:0.6.0"
+ ? "fetchai/oef_search:0.4.0"
+ : "fetchai/oef:0.7.0"
```
``` yaml
config:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md b/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md
index 127b7473e5..dfdcf6efd9 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-package-imports.md
@@ -29,5 +29,5 @@ aea_name/
```
``` yaml
connections:
-- fetchai/stub:0.6.0
+- fetchai/stub:0.7.0
```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md b/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md
index 0910cf6eaa..876f641ede 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-quickstart.md
@@ -36,12 +36,12 @@ Confirm password:
/ ___ \ | |___ / ___ \
/_/ \_\|_____|/_/ \_\
-v0.5.2
+v0.5.3
AEA configurations successfully initialized: {'author': 'fetchai'}
```
``` bash
-aea fetch fetchai/my_first_aea:0.7.0
+aea fetch fetchai/my_first_aea:0.8.0
cd my_first_aea
```
``` bash
@@ -49,19 +49,19 @@ aea create my_first_aea
cd my_first_aea
```
``` bash
-aea add skill fetchai/echo:0.3.0
+aea add skill fetchai/echo:0.4.0
```
``` bash
TO,SENDER,PROTOCOL_ID,ENCODED_MESSAGE,
```
``` bash
-recipient_aea,sender_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,
+recipient_aea,sender_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,
```
``` bash
aea run
```
``` bash
-aea run --connections fetchai/stub:0.6.0
+aea run --connections fetchai/stub:0.7.0
```
``` bash
_ _____ _
@@ -70,7 +70,7 @@ aea run --connections fetchai/stub:0.6.0
/ ___ \ | |___ / ___ \
/_/ \_\|_____|/_/ \_\
-v0.5.2
+v0.5.3
Starting AEA 'my_first_aea' in 'async' mode ...
info: Echo Handler: setup method called.
@@ -82,7 +82,7 @@ info: Echo Behaviour: act method called.
...
```
``` bash
-echo 'my_first_aea,sender_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,' >> input_file
+echo 'my_first_aea,sender_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,' >> input_file
```
``` bash
info: Echo Behaviour: act method called.
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md b/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md
index 3bd7c6f51b..492bd564fa 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-skill-guide.md
@@ -6,16 +6,16 @@ aea scaffold skill my_search
aea fingerprint skill fetchai/my_search:0.1.0
```
``` bash
-aea add protocol fetchai/oef_search:0.3.0
+aea add protocol fetchai/oef_search:0.4.0
```
``` bash
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/p2p_libp2p:0.5.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/simple_service_registration:0.8.0 && cd simple_service_registration
+aea fetch fetchai/simple_service_registration:0.9.0 && cd simple_service_registration
```
``` bash
aea generate-key cosmos
@@ -44,7 +44,7 @@ fingerprint: {}
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
my_search_behaviour:
@@ -71,7 +71,7 @@ dependencies: {}
```
``` yaml
default_routing:
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
name: simple_service_registration
@@ -89,7 +89,7 @@ fingerprint:
fingerprint_ignore_patterns: []
contracts: []
protocols:
-- fetchai/oef_search:0.3.0
+- fetchai/oef_search:0.4.0
skills: []
behaviours:
service:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-skill.md b/tests/test_docs/test_bash_yaml/md_files/bash-skill.md
index a63e02ac49..c357c98963 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-skill.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-skill.md
@@ -16,5 +16,5 @@ handlers:
models: {}
dependencies: {}
protocols:
-- fetchai/default:0.3.0
+- fetchai/default:0.4.0
```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md
index 874b3eb6c0..cdd661c9ca 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills-contract.md
@@ -1,18 +1,17 @@
``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-``` bash
-aea fetch fetchai/tac_controller_contract:0.6.0
+aea fetch fetchai/tac_controller_contract:0.7.0
cd tac_controller_contract
aea install
```
``` bash
aea create tac_controller_contract
cd tac_controller_contract
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_control_contract:0.4.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_control_contract:0.5.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
```
``` bash
@@ -26,12 +25,12 @@ aea generate-wealth ethereum
aea get-wealth ethereum
```
``` bash
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_one
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_one
cd tac_participant_one
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
cd ..
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_two
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_two
cd tac_participant_two
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
@@ -43,22 +42,26 @@ aea create tac_participant_two
```
``` bash
cd tac_participant_one
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
```
``` bash
cd tac_participant_two
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
aea config set agent.default_ledger ethereum
aea config set vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract 'True' --type bool
aea config set vendor.fetchai.skills.tac_negotiation.models.strategy.args.is_contract_tx 'True' --type bool
@@ -121,5 +124,5 @@ models:
class_name: Transactions
args:
pending_transaction_timeout: 30
-protocols: ['fetchai/oef_search:0.3.0', 'fetchai/fipa:0.4.0']
+protocols: ['fetchai/oef_search:0.4.0', 'fetchai/fipa:0.5.0']
```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md
index 0d2d887ca5..ace9e449ac 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-tac-skills.md
@@ -1,23 +1,22 @@
``` bash
-python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
-```
-``` bash
-aea fetch fetchai/tac_controller:0.5.0
+aea fetch fetchai/tac_controller:0.6.0
cd tac_controller
aea install
```
``` bash
aea create tac_controller
cd tac_controller
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_control:0.3.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_control:0.4.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
```
``` bash
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_one
-aea fetch fetchai/tac_participant:0.6.0 --alias tac_participant_two
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_one
+aea fetch fetchai/tac_participant:0.7.0 --alias tac_participant_two
cd tac_participant_two
aea install
```
@@ -27,27 +26,39 @@ aea create tac_participant_two
```
``` bash
cd tac_participant_one
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
```
``` bash
cd tac_participant_two
-aea add connection fetchai/oef:0.6.0
-aea add skill fetchai/tac_participation:0.4.0
-aea add skill fetchai/tac_negotiation:0.5.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/tac_participation:0.5.0
+aea add skill fetchai/tac_negotiation:0.6.0
aea install
-aea config set agent.default_connection fetchai/oef:0.6.0
-aea config set agent.default_ledger ethereum
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
+aea config set agent.default_ledger cosmos
+```
+``` bash
+aea generate-key cosmos
+aea add-key cosmos cosmos_private_key.txt
+aea add-key cosmos cosmos_private_key.txt --connection
```
``` bash
aea config get vendor.fetchai.skills.tac_control.models.parameters.args.start_time
aea config set vendor.fetchai.skills.tac_control.models.parameters.args.start_time '01 01 2020 00:01'
```
``` bash
+aea run
+```
+``` bash
aea launch tac_controller tac_participant_one tac_participant_two
```
``` bash
@@ -56,6 +67,22 @@ aea delete tac_participant_one
aea delete tac_participant_two
```
``` yaml
+config:
+ delegate_uri: 127.0.0.1:11001
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9001
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9001
+```
+``` yaml
+config:
+ delegate_uri: 127.0.0.1:11002
+ entry_peers: ['SOME_ADDRESS']
+ local_uri: 127.0.0.1:9002
+ log_file: libp2p_node.log
+ public_uri: 127.0.0.1:9002
+```
+``` yaml
name: tac_negotiation
authors: fetchai
version: 0.1.0
@@ -101,5 +128,5 @@ models:
class_name: Transactions
args:
pending_transaction_timeout: 30
-protocols: ['fetchai/oef_search:0.3.0', 'fetchai/fipa:0.4.0']
+protocols: ['fetchai/oef_search:0.4.0', 'fetchai/fipa:0.5.0']
```
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md
index 70939c45b0..f3342bbf90 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-thermometer-skills.md
@@ -1,32 +1,32 @@
``` bash
-aea fetch fetchai/thermometer_aea:0.6.0 --alias my_thermometer_aea
+aea fetch fetchai/thermometer_aea:0.7.0 --alias my_thermometer_aea
cd thermometer_aea
aea install
```
``` bash
aea create my_thermometer_aea
cd my_thermometer_aea
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/thermometer_client:0.6.0 --alias my_thermometer_client
+aea fetch fetchai/thermometer_client:0.7.0 --alias my_thermometer_client
cd my_thermometer_client
aea install
```
``` bash
aea create my_thermometer_client
cd my_thermometer_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/thermometer_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/thermometer_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea generate-key cosmos
@@ -54,13 +54,13 @@ aea delete my_thermometer_client
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
config:
diff --git a/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md b/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md
index 62d92bff4d..78c468e108 100644
--- a/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md
+++ b/tests/test_docs/test_bash_yaml/md_files/bash-weather-skills.md
@@ -1,32 +1,32 @@
``` bash
-aea fetch fetchai/weather_station:0.8.0 --alias my_weather_station
+aea fetch fetchai/weather_station:0.9.0 --alias my_weather_station
cd my_weather_station
aea install
```
``` bash
aea create my_weather_station
cd my_weather_station
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/weather_station:0.7.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/weather_station:0.8.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
-aea fetch fetchai/weather_client:0.8.0 --alias my_weather_client
+aea fetch fetchai/weather_client:0.9.0 --alias my_weather_client
cd my_weather_client
aea install
```
``` bash
aea create my_weather_client
cd my_weather_client
-aea add connection fetchai/p2p_libp2p:0.5.0
-aea add connection fetchai/soef:0.5.0
-aea add connection fetchai/ledger:0.2.0
-aea add skill fetchai/weather_client:0.6.0
+aea add connection fetchai/p2p_libp2p:0.6.0
+aea add connection fetchai/soef:0.6.0
+aea add connection fetchai/ledger:0.3.0
+aea add skill fetchai/weather_client:0.7.0
aea install
-aea config set agent.default_connection fetchai/p2p_libp2p:0.5.0
+aea config set agent.default_connection fetchai/p2p_libp2p:0.6.0
```
``` bash
aea generate-key cosmos
@@ -54,13 +54,13 @@ aea delete my_weather_client
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
default_routing:
- fetchai/ledger_api:0.1.0: fetchai/ledger:0.2.0
- fetchai/oef_search:0.3.0: fetchai/soef:0.5.0
+ fetchai/ledger_api:0.2.0: fetchai/ledger:0.3.0
+ fetchai/oef_search:0.4.0: fetchai/soef:0.6.0
```
``` yaml
config:
diff --git a/tests/test_docs/test_build_aea_programmatically/programmatic_aea.py b/tests/test_docs/test_build_aea_programmatically/programmatic_aea.py
index cf4f8048c6..9f8aed8abf 100644
--- a/tests/test_docs/test_build_aea_programmatically/programmatic_aea.py
+++ b/tests/test_docs/test_build_aea_programmatically/programmatic_aea.py
@@ -36,7 +36,7 @@
def run():
# Create a private key
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
# Ensure the input and output files do not exist initially
if os.path.isfile(INPUT_FILE):
@@ -96,7 +96,7 @@ def handle(self, message: Message) -> None:
# Create a message inside an envelope and get the stub connection to pass it on to the echo skill
message_text = (
- "my_aea,other_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "my_aea,other_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
diff --git a/tests/test_docs/test_build_aea_programmatically/test_programmatic_aea.py b/tests/test_docs/test_build_aea_programmatically/test_programmatic_aea.py
index 006a93a15a..401bc511ae 100644
--- a/tests/test_docs/test_build_aea_programmatically/test_programmatic_aea.py
+++ b/tests/test_docs/test_build_aea_programmatically/test_programmatic_aea.py
@@ -61,7 +61,7 @@ def test_run_agent(self):
assert os.path.exists(Path(self.t, DEFAULT_PRIVATE_KEY_FILE))
message_text = (
- "other_agent,my_aea,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "other_agent,my_aea,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
path = os.path.join(self.t, "output_file")
with open(path, "r") as file:
diff --git a/tests/test_docs/test_cli_vs_programmatic_aeas/cosmos_private_key.txt b/tests/test_docs/test_cli_vs_programmatic_aeas/cosmos_private_key.txt
deleted file mode 100644
index e2b2a4b904..0000000000
--- a/tests/test_docs/test_cli_vs_programmatic_aeas/cosmos_private_key.txt
+++ /dev/null
@@ -1 +0,0 @@
-e613db13d8ba93cacb0ca3c0e0e074c9bdb404d816a4749f8d96d2c13d5fad5b
\ No newline at end of file
diff --git a/tests/test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py b/tests/test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py
index 5bcaedba20..38691d6fa1 100644
--- a/tests/test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py
+++ b/tests/test_docs/test_cli_vs_programmatic_aeas/programmatic_aea.py
@@ -46,6 +46,7 @@
ENTRY_PEER_ADDRESS = (
"/dns4/127.0.0.1/tcp/9000/p2p/16Uiu2HAmAzvu5uNbcnD2qaqrkSULhJsc6GJUg3iikWerJkoD72pr"
)
+COSMOS_PRIVATE_KEY_FILE_CONNECTION = "cosmos_connection_private_key.txt"
ROOT_DIR = os.getcwd()
logger = logging.getLogger("aea")
@@ -54,22 +55,25 @@
def run():
# Create a private key
- create_private_key(CosmosCrypto.identifier)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE)
+ create_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
# Set up the wallet, identity and (empty) resources
wallet = Wallet(
private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
- connection_private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
+ connection_private_key_paths={
+ CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ },
)
identity = Identity("my_aea", address=wallet.addresses.get(CosmosCrypto.identifier))
resources = Resources()
# specify the default routing for some protocols
default_routing = {
- PublicId.from_str("fetchai/ledger_api:0.1.0"): LedgerConnection.connection_id,
- PublicId.from_str("fetchai/oef_search:0.3.0"): SOEFConnection.connection_id,
+ PublicId.from_str("fetchai/ledger_api:0.2.0"): LedgerConnection.connection_id,
+ PublicId.from_str("fetchai/oef_search:0.4.0"): SOEFConnection.connection_id,
}
- default_connection = SOEFConnection.connection_id
+ default_connection = P2PLibp2pConnection.connection_id
# create the AEA
my_aea = AEA(
@@ -134,13 +138,8 @@ def run():
api_key=API_KEY,
soef_addr=SOEF_ADDR,
soef_port=SOEF_PORT,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
- delegate_uri="127.0.0.1:11001",
- entry_peers=[ENTRY_PEER_ADDRESS],
- local_uri="127.0.0.1:9001",
- log_file="libp2p_node.log",
- public_uri="127.0.0.1:9001",
)
soef_connection = SOEFConnection(configuration=configuration, identity=identity)
resources.add_connection(soef_connection)
diff --git a/tests/test_docs/test_cli_vs_programmatic_aeas/test_cli_vs_programmatic_aea.py b/tests/test_docs/test_cli_vs_programmatic_aeas/test_cli_vs_programmatic_aea.py
index 20b34c64d1..dac85e9f68 100644
--- a/tests/test_docs/test_cli_vs_programmatic_aeas/test_cli_vs_programmatic_aea.py
+++ b/tests/test_docs/test_cli_vs_programmatic_aeas/test_cli_vs_programmatic_aea.py
@@ -21,6 +21,8 @@
import os
import shutil
+from pathlib import Path
+from random import uniform
import pytest
@@ -29,9 +31,12 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
CUR_PATH,
+ MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
ROOT_DIR,
+ wait_for_localhost_ports_to_close,
)
from tests.test_docs.helper import extract_code_blocks, extract_python_code
@@ -51,12 +56,13 @@ def test_read_md_file(self):
python_file = extract_python_code(test_code_path)
assert code_blocks[-1] == python_file, "Files must be exactly the same."
+ @pytest.mark.flaky(reruns=MAX_FLAKY_RERUNS_INTEGRATION)
@pytest.mark.integration
def test_cli_programmatic_communication(self):
"""Test the communication of the two agents."""
weather_station = "weather_station"
- self.fetch_agent("fetchai/weather_station:0.8.0", weather_station)
+ self.fetch_agent("fetchai/weather_station:0.9.0", weather_station)
self.set_agent_context(weather_station)
self.set_config(
"vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx",
@@ -67,11 +73,23 @@ def test_cli_programmatic_communication(self):
# add non-funded key
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
+ }
+ setting_path = (
+ "vendor.fetchai.skills.weather_station.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
weather_station_process = self.run_agent()
@@ -93,6 +111,7 @@ def test_cli_programmatic_communication(self):
src_file_path = os.path.join(ROOT_DIR, "tests", PY_FILE)
dst_file_path = os.path.join(ROOT_DIR, self.t, DEST)
shutil.copyfile(src_file_path, dst_file_path)
+ self._inject_location(location, dst_file_path)
weather_client_process = self.start_subprocess(DEST, cwd=self.t)
check_strings = (
@@ -147,3 +166,18 @@ def test_cli_programmatic_communication(self):
assert (
self.is_successfully_terminated()
), "Agents weren't successfully terminated."
+ wait_for_localhost_ports_to_close([9000, 9001])
+
+ def _inject_location(self, location, dst_file_path):
+ """Inject location into the weather client strategy."""
+ file = Path(dst_file_path)
+ lines = file.read_text().splitlines()
+ lines.insert(
+ 157,
+ " from packages.fetchai.skills.generic_buyer.strategy import Location",
+ )
+ lines.insert(
+ 158,
+ f" strategy._agent_location = Location({location['longitude']}, {location['latitude']})",
+ )
+ file.write_text("\n".join(lines))
diff --git a/tests/test_docs/test_docs_protocol.py b/tests/test_docs/test_docs_protocol.py
index 4ad323f298..2c3f1151f2 100644
--- a/tests/test_docs/test_docs_protocol.py
+++ b/tests/test_docs/test_docs_protocol.py
@@ -69,7 +69,7 @@ def test_custom_protocol(self):
)
def test_oef_search_protocol(self):
- """Test the fetchai/oef_search:0.3.0 protocol documentation."""
+ """Test the fetchai/oef_search:0.4.0 protocol documentation."""
# this is the offset of code blocks for the section under testing
offset = 4
@@ -106,7 +106,7 @@ def test_oef_search_protocol(self):
compare_enum_classes(ExpectedOefErrorOperation, ActualOefErrorOperation)
def test_fipa_protocol(self):
- """Test the fetchai/fipa:0.4.0 documentation."""
+ """Test the fetchai/fipa:0.5.0 documentation."""
offset = 15
locals_dict = {"Enum": Enum}
compile_and_exec(self.code_blocks[offset]["text"], locals_dict=locals_dict)
diff --git a/tests/test_docs/test_docs_skill.py b/tests/test_docs/test_docs_skill.py
index 119adff7f3..00e2b47bb6 100644
--- a/tests/test_docs/test_docs_skill.py
+++ b/tests/test_docs/test_docs_skill.py
@@ -49,10 +49,12 @@ def test_context(self):
assert block["text"].strip() == expected
assert block["info"].strip() == "python"
+ # TODO add tests for new_handlers queue
+
def test_hello_world_behaviour(self):
"""Test the code in the 'behaviours.py' section."""
# here, we test the definition of a custom class
- offset = 1
+ offset = 2
block = self.code_blocks[offset]
text = block["text"]
@@ -85,7 +87,7 @@ def test_hello_world_behaviour(self):
def test_task(self):
"""Test the code blocks of the 'tasks.py' section."""
# test code of task definition
- offset = 4
+ offset = 5
block = self.code_blocks[offset]
locals_dict = compile_and_exec(block["text"])
diff --git a/tests/test_docs/test_multiplexer_standalone/multiplexer_standalone.py b/tests/test_docs/test_multiplexer_standalone/multiplexer_standalone.py
index 022c58c6d6..5208e536b8 100644
--- a/tests/test_docs/test_multiplexer_standalone/multiplexer_standalone.py
+++ b/tests/test_docs/test_multiplexer_standalone/multiplexer_standalone.py
@@ -62,7 +62,7 @@ def run():
# Create a message inside an envelope and get the stub connection to pass it into the multiplexer
message_text = (
- "multiplexer,some_agent,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "multiplexer,some_agent,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
with open(INPUT_FILE, "w") as f:
f.write(message_text)
diff --git a/tests/test_docs/test_multiplexer_standalone/test_multiplexer_standalone.py b/tests/test_docs/test_multiplexer_standalone/test_multiplexer_standalone.py
index 299f6c19f1..c4ac19c26c 100644
--- a/tests/test_docs/test_multiplexer_standalone/test_multiplexer_standalone.py
+++ b/tests/test_docs/test_multiplexer_standalone/test_multiplexer_standalone.py
@@ -60,7 +60,7 @@ def test_run_agent(self):
assert os.path.exists(Path(self.t, "output.txt"))
message_text = (
- "some_agent,multiplexer,fetchai/default:0.3.0,\x08\x01*\x07\n\x05hello,"
+ "some_agent,multiplexer,fetchai/default:0.4.0,\x08\x01*\x07\n\x05hello,"
)
path = os.path.join(str(self.t), "output.txt")
with open(path, "r", encoding="utf-8") as file:
diff --git a/tests/test_docs/test_orm_integration/test_orm_integration.py b/tests/test_docs/test_orm_integration/test_orm_integration.py
index da209667e9..39a8fd4baf 100644
--- a/tests/test_docs/test_orm_integration/test_orm_integration.py
+++ b/tests/test_docs/test_orm_integration/test_orm_integration.py
@@ -19,6 +19,7 @@
"""This module contains the tests for the orm-integration.md guide."""
from pathlib import Path
+from random import uniform
import mistune
@@ -31,7 +32,7 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -125,21 +126,27 @@ def test_orm_integration_docs_example(self):
self.create_agents(seller_aea_name, buyer_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# Setup seller
self.set_agent_context(seller_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
# ejecting changes author and version!
- self.eject_item("skill", "fetchai/thermometer:0.7.0")
+ self.eject_item("skill", "fetchai/thermometer:0.8.0")
seller_skill_config_replacement = yaml.safe_load(seller_strategy_replacement)
self.force_set_config(
"skills.thermometer.models", seller_skill_config_replacement["models"],
@@ -152,27 +159,34 @@ def test_orm_integration_docs_example(self):
seller_stategy_path = Path(
seller_aea_name, "skills", "thermometer", "strategy.py",
)
- self.replace_file_content(seller_stategy_path, ORM_SELLER_STRATEGY_PATH)
+ self.replace_file_content(ORM_SELLER_STRATEGY_PATH, seller_stategy_path)
self.fingerprint_item(
"skill", "{}/thermometer:0.1.0".format(self.author),
)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
+ # replace location
+ setting_path = "skills.thermometer.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
# Setup Buyer
self.set_agent_context(buyer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer_client:0.6.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer_client:0.7.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
buyer_skill_config_replacement = yaml.safe_load(buyer_strategy_replacement)
@@ -182,16 +196,27 @@ def test_orm_integration_docs_example(self):
)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.thermometer_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# Fire the sub-processes and the threads.
self.set_agent_context(seller_aea_name)
seller_aea_process = self.run_agent()
diff --git a/tests/test_docs/test_skill_guide/test_skill_guide.py b/tests/test_docs/test_skill_guide/test_skill_guide.py
index b5dc15ec54..d260fecbd6 100644
--- a/tests/test_docs/test_skill_guide/test_skill_guide.py
+++ b/tests/test_docs/test_skill_guide/test_skill_guide.py
@@ -22,6 +22,7 @@
import filecmp
import os
from pathlib import Path
+from random import uniform
import pytest
@@ -33,7 +34,7 @@
AUTHOR,
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -66,32 +67,45 @@ def test_update_skill_and_run(self):
"""Test that the resource folder contains scaffold handlers.py module."""
self.initialize_aea(AUTHOR)
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
+ }
+
simple_service_registration_aea = "simple_service_registration"
self.fetch_agent(
- "fetchai/simple_service_registration:0.8.0", simple_service_registration_aea
+ "fetchai/simple_service_registration:0.9.0", simple_service_registration_aea
)
self.set_agent_context(simple_service_registration_aea)
# add non-funded key
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
default_routing = {
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
}
+ # replace location
+ setting_path = "vendor.fetchai.skills.simple_service_registration.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
search_aea = "search_aea"
self.create_agents(search_aea)
self.set_agent_context(search_aea)
skill_name = "my_search"
skill_id = AUTHOR + "/" + skill_name + ":" + DEFAULT_VERSION
self.scaffold_item("skill", skill_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
@@ -125,16 +139,27 @@ def test_update_skill_and_run(self):
# update fingerprint
self.fingerprint_item("skill", skill_id)
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = "skills.{}.behaviours.my_search_behaviour.args.location".format(
+ skill_name
+ )
+ self.force_set_config(setting_path, location)
+
# run agents
self.set_agent_context(simple_service_registration_aea)
simple_service_registration_aea_process = self.run_agent()
diff --git a/tests/test_docs/test_standalone_transaction/standalone_transaction.py b/tests/test_docs/test_standalone_transaction/standalone_transaction.py
index 69c3a475e7..46f8a61608 100644
--- a/tests/test_docs/test_standalone_transaction/standalone_transaction.py
+++ b/tests/test_docs/test_standalone_transaction/standalone_transaction.py
@@ -23,7 +23,7 @@
from aea.crypto.cosmos import CosmosCrypto
from aea.crypto.helpers import create_private_key, try_generate_testnet_wealth
-from aea.crypto.ledger_apis import DEFAULT_LEDGER_CONFIGS, LedgerApis
+from aea.crypto.ledger_apis import LedgerApis
from aea.crypto.wallet import Wallet
@@ -47,9 +47,6 @@ def run():
wallet_1 = Wallet({CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_1})
wallet_2 = Wallet({CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_2})
- # Set up the LedgerApis
- ledger_apis = LedgerApis(DEFAULT_LEDGER_CONFIGS, CosmosCrypto.identifier)
-
# Generate some wealth
try_generate_testnet_wealth(
CosmosCrypto.identifier, wallet_1.addresses[CosmosCrypto.identifier]
@@ -60,12 +57,12 @@ def run():
)
# Create the transaction and send it to the ledger.
- tx_nonce = ledger_apis.generate_tx_nonce(
+ tx_nonce = LedgerApis.generate_tx_nonce(
CosmosCrypto.identifier,
wallet_2.addresses.get(CosmosCrypto.identifier),
wallet_1.addresses.get(CosmosCrypto.identifier),
)
- transaction = ledger_apis.get_transfer_transaction(
+ transaction = LedgerApis.get_transfer_transaction(
identifier=CosmosCrypto.identifier,
sender_address=wallet_1.addresses.get(CosmosCrypto.identifier),
destination_address=wallet_2.addresses.get(CosmosCrypto.identifier),
@@ -74,7 +71,7 @@ def run():
tx_nonce=tx_nonce,
)
signed_transaction = wallet_1.sign_transaction(CosmosCrypto.identifier, transaction)
- transaction_digest = ledger_apis.send_signed_transaction(
+ transaction_digest = LedgerApis.send_signed_transaction(
CosmosCrypto.identifier, signed_transaction
)
diff --git a/tests/test_docs/test_standalone_transaction/test_standalone_transaction.py b/tests/test_docs/test_standalone_transaction/test_standalone_transaction.py
index f842c65c95..6c5ec74b1a 100644
--- a/tests/test_docs/test_standalone_transaction/test_standalone_transaction.py
+++ b/tests/test_docs/test_standalone_transaction/test_standalone_transaction.py
@@ -23,9 +23,11 @@
import os
from unittest.mock import patch
+import pytest
+
from aea.test_tools.test_cases import BaseAEATestCase
-from tests.conftest import CUR_PATH, ROOT_DIR
+from tests.conftest import CUR_PATH, MAX_FLAKY_RERUNS_INTEGRATION, ROOT_DIR
from tests.test_docs.helper import extract_code_blocks, extract_python_code
from .standalone_transaction import (
@@ -39,6 +41,7 @@
test_logger = logging.getLogger(__name__)
+@pytest.mark.integration(reruns=MAX_FLAKY_RERUNS_INTEGRATION)
class TestStandaloneTransaction(BaseAEATestCase):
"""This class contains the tests for the code-blocks in the agent-vs-aea.md file."""
diff --git a/tests/test_examples/test_http_client_connection_to_aries_cloud_agent.py b/tests/test_examples/test_http_client_connection_to_aries_cloud_agent.py
index c78c91aa20..9fd0ed9e7f 100644
--- a/tests/test_examples/test_http_client_connection_to_aries_cloud_agent.py
+++ b/tests/test_examples/test_http_client_connection_to_aries_cloud_agent.py
@@ -113,7 +113,7 @@ async def test_connecting_to_aca(self):
# Request messages
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
+ dialogue_reference=("1", ""),
target=0,
message_id=1,
performative=HttpMessage.Performative.REQUEST,
@@ -136,7 +136,7 @@ async def test_connecting_to_aca(self):
try:
# connect to ACA
await http_client_connection.connect()
- assert http_client_connection.connection_status.is_connected is True
+ assert http_client_connection.is_connected is True
# send request to ACA
await http_client_connection.send(envelope=request_envelope)
@@ -162,7 +162,7 @@ async def test_connecting_to_aca(self):
finally:
# disconnect from ACA
await http_client_connection.disconnect()
- assert http_client_connection.connection_status.is_connected is False
+ assert http_client_connection.is_connected is False
@pytest.mark.asyncio
async def test_end_to_end_aea_aca(self):
diff --git a/tests/test_helpers/test_async_utils.py b/tests/test_helpers/test_async_utils.py
index fe4501887e..dcfc5ba115 100644
--- a/tests/test_helpers/test_async_utils.py
+++ b/tests/test_helpers/test_async_utils.py
@@ -65,6 +65,43 @@ async def test_async_state():
await state.wait(2)
+@pytest.mark.asyncio
+async def test_asyncstate_with_list_of_valid_states():
+ """Test various cases for AsyncState."""
+ states = [1, 2, 3]
+ state = AsyncState(1, states)
+
+ state.set(2)
+ assert state.get() == 2
+
+ with pytest.raises(ValueError):
+ state.set("anything")
+
+ assert state.get() == 2
+
+
+@pytest.mark.asyncio
+async def test_asyncstate_callback():
+ """Test various cases for AsyncState.callback."""
+ state = AsyncState()
+
+ called = False
+
+ def callback_err(state):
+ raise Exception("expected")
+
+ def callback(state):
+ nonlocal called
+ called = True
+
+ state.add_callback(callback_err)
+ state.add_callback(callback)
+
+ state.set(2)
+ assert state.get() == 2
+ assert called
+
+
@pytest.mark.asyncio
async def test_periodic_caller_start_stop():
"""Test start stop calls for PeriodicCaller."""
diff --git a/tests/test_helpers/test_dialogue/test_base.py b/tests/test_helpers/test_dialogue/test_base.py
index 910f59e2e4..0f64ed1d2f 100644
--- a/tests/test_helpers/test_dialogue/test_base.py
+++ b/tests/test_helpers/test_dialogue/test_base.py
@@ -19,7 +19,9 @@
"""This module contains the tests for the dialogue/base.py module."""
-from typing import Dict, FrozenSet, Optional, cast
+from typing import Dict, FrozenSet, Optional, Type, cast
+
+import pytest
from aea.helpers.dialogue.base import Dialogue as BaseDialogue
from aea.helpers.dialogue.base import DialogueLabel, DialogueStats
@@ -27,6 +29,7 @@
from aea.mail.base import Address
from aea.protocols.base import Message
from aea.protocols.default.message import DefaultMessage
+from aea.protocols.state_update.message import StateUpdateMessage
class Dialogue(BaseDialogue):
@@ -60,7 +63,7 @@ class EndState(BaseDialogue.EndState):
def __init__(
self,
dialogue_label: DialogueLabel,
- message_class=DefaultMessage,
+ message_class: Type[Message] = DefaultMessage,
agent_address: Optional[Address] = "agent 1",
role: Optional[BaseDialogue.Role] = Role.ROLE1,
) -> None:
@@ -158,10 +161,12 @@ class TestDialogueLabel:
@classmethod
def setup(cls):
"""Initialise the environment to test DialogueLabel."""
+ cls.agent_address = "agent 1"
+ cls.opponent_address = "agent 2"
cls.dialogue_label = DialogueLabel(
dialogue_reference=(str(1), ""),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_opponent_addr=cls.opponent_address,
+ dialogue_starter_addr=cls.agent_address,
)
def test_all_methods(self):
@@ -169,8 +174,8 @@ def test_all_methods(self):
assert self.dialogue_label.dialogue_reference == (str(1), "")
assert self.dialogue_label.dialogue_starter_reference == str(1)
assert self.dialogue_label.dialogue_responder_reference == ""
- assert self.dialogue_label.dialogue_opponent_addr == "agent 2"
- assert self.dialogue_label.dialogue_starter_addr == "agent 1"
+ assert self.dialogue_label.dialogue_opponent_addr == self.opponent_address
+ assert self.dialogue_label.dialogue_starter_addr == self.agent_address
assert str(self.dialogue_label) == "{}_{}_{}_{}".format(
self.dialogue_label.dialogue_starter_reference,
self.dialogue_label.dialogue_responder_reference,
@@ -180,8 +185,8 @@ def test_all_methods(self):
dialogue_label_eq = DialogueLabel(
dialogue_reference=(str(1), ""),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_opponent_addr=self.opponent_address,
+ dialogue_starter_addr=self.agent_address,
)
assert dialogue_label_eq == self.dialogue_label
@@ -195,10 +200,11 @@ def test_all_methods(self):
assert self.dialogue_label.json == dict(
dialogue_starter_reference=str(1),
dialogue_responder_reference="",
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_opponent_addr=self.opponent_address,
+ dialogue_starter_addr=self.agent_address,
)
assert DialogueLabel.from_json(self.dialogue_label.json) == self.dialogue_label
+ assert DialogueLabel.from_str(str(self.dialogue_label)) == self.dialogue_label
class TestDialogueBase:
@@ -207,12 +213,24 @@ class TestDialogueBase:
@classmethod
def setup(cls):
"""Initialise the environment to test Dialogue."""
+ cls.incomplete_reference = (str(1), "")
+ cls.complete_reference = (str(1), str(1))
+ cls.opponent_address = "agent 2"
+ cls.agent_address = "agent 1"
cls.dialogue_label = DialogueLabel(
- dialogue_reference=(str(1), ""),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_reference=cls.incomplete_reference,
+ dialogue_opponent_addr=cls.opponent_address,
+ dialogue_starter_addr=cls.agent_address,
)
cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)
+ cls.dialogue_label_opponent_started = DialogueLabel(
+ dialogue_reference=cls.complete_reference,
+ dialogue_opponent_addr=cls.opponent_address,
+ dialogue_starter_addr=cls.opponent_address,
+ )
+ cls.dialogue_opponent_started = Dialogue(
+ dialogue_label=cls.dialogue_label_opponent_started
+ )
def test_inner_classes(self):
"""Test the inner classes: Role and EndStates."""
@@ -224,7 +242,8 @@ def test_inner_classes(self):
def test_dialogue_properties(self):
"""Test dialogue properties."""
assert self.dialogue.dialogue_label == self.dialogue_label
- assert self.dialogue.agent_address == "agent 1"
+ assert self.dialogue.incomplete_dialogue_label == self.dialogue_label
+ assert self.dialogue.agent_address == self.agent_address
self.dialogue.agent_address = "this agent's address"
assert self.dialogue.agent_address == "this agent's address"
@@ -273,7 +292,7 @@ def test_update_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
assert self.dialogue.update(valid_initial_msg)
assert self.dialogue.last_outgoing_message == valid_initial_msg
@@ -304,49 +323,15 @@ def test_update_negative_not_is_extendible(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- invalid_message_id.counterparty = "agent 2"
+ invalid_message_id.counterparty = self.opponent_address
assert not self.dialogue.update(invalid_message_id)
assert self.dialogue.last_outgoing_message is None
- def test_update_self_initiated_dialogue_label_on_second_message_positive(self):
- """Positive test for the '_update_self_initiated_dialogue_label_on_second_message' method."""
- valid_initial_msg = DefaultMessage(
- dialogue_reference=(str(1), ""),
- message_id=1,
- target=0,
- performative=DefaultMessage.Performative.BYTES,
- content=b"Hello",
- )
- valid_initial_msg.counterparty = "agent 2"
- valid_initial_msg._is_incoming = False
-
- assert self.dialogue.update(valid_initial_msg)
-
- valid_second_msg = DefaultMessage(
- dialogue_reference=(str(1), str(1)),
- message_id=2,
- target=1,
- performative=DefaultMessage.Performative.BYTES,
- content=b"Hello Back",
- )
- valid_second_msg.counterparty = "agent 2"
- valid_second_msg._is_incoming = True
-
- try:
- self.dialogue._update_self_initiated_dialogue_label_on_second_message(
- valid_second_msg
- )
- result = True
- except Exception:
- result = False
-
- assert result
-
- def test_update_self_initiated_dialogue_label_on_second_message_negative_empty_dialogue(
+ def test_update_self_initiated_dialogue_label_on_message_with_complete_reference_negative_not_second_message(
self,
):
- """Negative test for the '_update_self_initiated_dialogue_label_on_second_message' method: called on an empty dialogue."""
+ """Negative test for the '_update_self_initiated_dialogue_label_on_message_with_complete_reference' method: input message is not the second message in the dialogue."""
initial_msg = DefaultMessage(
dialogue_reference=(str(1), ""),
message_id=1,
@@ -354,34 +339,10 @@ def test_update_self_initiated_dialogue_label_on_second_message_negative_empty_d
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = False
-
- try:
- self.dialogue._update_self_initiated_dialogue_label_on_second_message(
- initial_msg
- )
- result = True
- except Exception:
- result = False
-
- assert not result
-
- def test_update_self_initiated_dialogue_label_on_second_message_negative_not_second_message(
- self,
- ):
- """Negative test for the '_update_self_initiated_dialogue_label_on_second_message' method: input message is not the second message in the dialogue."""
- initial_msg = DefaultMessage(
- dialogue_reference=(str(1), ""),
- message_id=1,
- target=0,
- performative=DefaultMessage.Performative.BYTES,
- content=b"Hello",
- )
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = False
-
- assert self.dialogue.update(initial_msg)
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = False
+ dialogue = self.dialogue.update(initial_msg)
+ assert dialogue is not None
second_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -390,10 +351,11 @@ def test_update_self_initiated_dialogue_label_on_second_message_negative_not_sec
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
-
- assert self.dialogue.update(second_msg)
+ second_msg.counterparty = self.opponent_address
+ second_msg.sender = self.agent_address
+ second_msg.is_incoming = True
+ dialogue = self.dialogue.update(second_msg)
+ assert dialogue is not None
third_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -402,11 +364,11 @@ def test_update_self_initiated_dialogue_label_on_second_message_negative_not_sec
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back 2",
)
- third_msg.counterparty = "agent 2"
- third_msg._is_incoming = False
+ third_msg.counterparty = self.opponent_address
+ third_msg.is_incoming = False
try:
- self.dialogue._update_self_initiated_dialogue_label_on_second_message(
+ self.dialogue._update_self_initiated_dialogue_label_on_message_with_complete_reference(
third_msg
)
result = True
@@ -424,8 +386,8 @@ def test_reply_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = False
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = False
assert self.dialogue.update(initial_msg)
@@ -446,8 +408,8 @@ def test_reply_negative_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = False
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = False
assert self.dialogue.update(initial_msg)
@@ -458,8 +420,8 @@ def test_reply_negative_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello There",
)
- invalid_initial_msg.counterparty = "agent 2"
- invalid_initial_msg._is_incoming = False
+ invalid_initial_msg.counterparty = self.opponent_address
+ invalid_initial_msg.is_incoming = False
try:
self.dialogue.reply(
@@ -482,7 +444,7 @@ def test_basic_rules_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
assert self.dialogue._basic_rules(valid_initial_msg)
@@ -495,7 +457,7 @@ def test_basic_rules_negative_initial_message_invalid_dialogue_reference(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- invalid_initial_msg.counterparty = "agent 2"
+ invalid_initial_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_initial_msg)
@@ -508,7 +470,7 @@ def test_basic_rules_negative_initial_message_invalid_message_id(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- invalid_initial_msg.counterparty = "agent 2"
+ invalid_initial_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_initial_msg)
@@ -521,7 +483,7 @@ def test_basic_rules_negative_initial_message_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- invalid_initial_msg.counterparty = "agent 2"
+ invalid_initial_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_initial_msg)
@@ -536,7 +498,7 @@ def test_basic_rules_negative_initial_message_invalid_performative(self):
error_msg="some_error_message",
error_data={"some_data": b"some_bytes"},
)
- invalid_initial_msg.counterparty = "agent 2"
+ invalid_initial_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_initial_msg)
@@ -549,7 +511,7 @@ def test_basic_rules_negative_non_initial_message_invalid_dialogue_reference(sel
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
@@ -561,7 +523,7 @@ def test_basic_rules_negative_non_initial_message_invalid_dialogue_reference(sel
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- invalid_msg.counterparty = "agent 2"
+ invalid_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_msg)
@@ -574,7 +536,7 @@ def test_basic_rules_negative_non_initial_message_invalid_message_id(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
@@ -586,7 +548,7 @@ def test_basic_rules_negative_non_initial_message_invalid_message_id(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- invalid_msg.counterparty = "agent 2"
+ invalid_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_msg)
@@ -599,7 +561,7 @@ def test_basic_rules_negative_non_initial_message_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
@@ -611,38 +573,23 @@ def test_basic_rules_negative_non_initial_message_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- invalid_msg.counterparty = "agent 2"
+ invalid_msg.counterparty = self.opponent_address
assert not self.dialogue._basic_rules(invalid_msg)
- # ToDo change to another Message class to test invalid non-initial performative
- # since default message does not provide this
- # def test_basic_rules_negative_non_initial_message_invalid_performative(self):
- # """Negative test for the '_basic_rules' method: input message is not the first message, and its performative is invalid."""
- # valid_initial_msg = DefaultMessage(
- # dialogue_reference=(str(1), ""),
- # message_id=1,
- # target=0,
- # performative=DefaultMessage.Performative.BYTES,
- # content=b"Hello",
- # )
- # valid_initial_msg.counterparty = "agent 2"
- # valid_initial_msg._is_incoming = False
- #
- # assert self.dialogue.update(valid_initial_msg)
- #
- # invalid_msg = DefaultMessage(
- # dialogue_reference=(str(1), str(1)),
- # message_id=1,
- # target=0,
- # performative=DefaultMessage.Performative.ERROR,
- # error_code=DefaultMessage.ErrorCode.INVALID_MESSAGE,
- # error_msg="some_error_message",
- # error_data={"some_data": b"some_bytes"},
- # )
- # invalid_msg.counterparty = "agent 2"
- #
- # assert not self.dialogue._basic_rules(invalid_msg)
+ def test_basic_rules_negative_non_initial_message_invalid_performative(self):
+ """Negative test for the '_basic_rules' method: input message is not the first message, and its performative is invalid."""
+ invalid_initial_msg = StateUpdateMessage(
+ dialogue_reference=(str(1), ""),
+ message_id=1,
+ target=0,
+ performative=StateUpdateMessage.Performative.APPLY,
+ amount_by_currency_id={},
+ quantities_by_good_id={},
+ )
+ invalid_initial_msg.counterparty = self.opponent_address
+
+ assert not self.dialogue.update(invalid_initial_msg)
def test_additional_rules_positive(self):
"""Positive test for the '_additional_rules' method."""
@@ -653,7 +600,7 @@ def test_additional_rules_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
@@ -665,7 +612,7 @@ def test_additional_rules_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- valid_second_msg.counterparty = "agent 2"
+ valid_second_msg.counterparty = self.opponent_address
valid_second_msg._is_incoming = True
assert self.dialogue.update(valid_second_msg)
@@ -677,7 +624,7 @@ def test_additional_rules_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back 2",
)
- valid_third_msg.counterparty = "agent 2"
+ valid_third_msg.counterparty = self.opponent_address
valid_third_msg._is_incoming = False
assert self.dialogue._additional_rules(valid_third_msg)
@@ -691,8 +638,8 @@ def test_additional_rules_negative_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
- valid_initial_msg._is_incoming = False
+ valid_initial_msg.counterparty = self.opponent_address
+ valid_initial_msg.is_incoming = False
assert self.dialogue.update(valid_initial_msg)
@@ -703,8 +650,8 @@ def test_additional_rules_negative_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- valid_second_msg.counterparty = "agent 2"
- valid_second_msg._is_incoming = True
+ valid_second_msg.counterparty = self.opponent_address
+ valid_second_msg.is_incoming = True
assert self.dialogue.update(valid_second_msg)
@@ -715,7 +662,7 @@ def test_additional_rules_negative_invalid_target(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back 2",
)
- invalid_third_msg.counterparty = "agent 2"
+ invalid_third_msg.counterparty = self.opponent_address
invalid_third_msg._is_incoming = False
assert not self.dialogue._additional_rules(invalid_third_msg)
@@ -729,54 +676,74 @@ def test_update_dialogue_label_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
new_label = DialogueLabel(
- (str(1), str(1)), valid_initial_msg.counterparty, "agent 1"
+ (str(1), str(1)), valid_initial_msg.counterparty, self.agent_address
)
self.dialogue.update_dialogue_label(new_label)
assert self.dialogue.dialogue_label == new_label
+ def test_update_dialogue_negative(self):
+ """Positive test for the 'update' method in dialogue with wrong message not belonging to dialogue."""
+ valid_initial_msg = DefaultMessage(
+ dialogue_reference=(str(2), ""),
+ message_id=1,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"Hello",
+ )
+ valid_initial_msg.counterparty = self.opponent_address
+ valid_initial_msg.is_incoming = False
+
+ assert not self.dialogue.update(valid_initial_msg)
+
def test_update_dialogue_label_negative_invalid_existing_label(self):
"""Negative test for the 'update_dialogue_label' method: existing dialogue reference is invalid."""
+ incomplete_reference = (str(1), "")
valid_initial_msg = DefaultMessage(
- dialogue_reference=(str(1), ""),
+ dialogue_reference=incomplete_reference,
message_id=1,
target=0,
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
- valid_initial_msg._is_incoming = False
+ valid_initial_msg.counterparty = self.opponent_address
+ valid_initial_msg.is_incoming = False
assert self.dialogue.update(valid_initial_msg)
+ complete_reference = (str(1), str(1))
valid_second_msg = DefaultMessage(
- dialogue_reference=(str(1), str(1)),
+ dialogue_reference=complete_reference,
message_id=2,
target=1,
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- valid_second_msg.counterparty = "agent 2"
- valid_second_msg._is_incoming = True
+ valid_second_msg.counterparty = self.opponent_address
+ valid_second_msg.sender = self.agent_address
+ valid_second_msg.is_incoming = True
assert self.dialogue.update(valid_second_msg)
new_label = DialogueLabel(
- (str(1), str(2)), valid_initial_msg.counterparty, "agent 1"
+ complete_reference, valid_initial_msg.counterparty, self.agent_address
)
- try:
+ self.dialogue.update_dialogue_label(new_label)
+ assert self.dialogue.dialogue_label == new_label
+
+ new_label = DialogueLabel(
+ (str(1), str(2)), valid_initial_msg.counterparty, self.agent_address
+ )
+ with pytest.raises(AssertionError):
self.dialogue.update_dialogue_label(new_label)
- result = True
- except AssertionError:
- result = False
- assert not result and self.dialogue.dialogue_label != new_label
+ assert self.dialogue.dialogue_label != new_label
def test_update_dialogue_label_negative_invalid_input_label(self):
"""Negative test for the 'update_dialogue_label' method: input dialogue label's dialogue reference is invalid."""
@@ -787,13 +754,13 @@ def test_update_dialogue_label_negative_invalid_input_label(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
+ valid_initial_msg.counterparty = self.opponent_address
valid_initial_msg._is_incoming = False
assert self.dialogue.update(valid_initial_msg)
new_label = DialogueLabel(
- (str(2), ""), valid_initial_msg.counterparty, "agent 1"
+ (str(2), ""), valid_initial_msg.counterparty, self.agent_address
)
try:
self.dialogue.update_dialogue_label(new_label)
@@ -823,10 +790,11 @@ def test___str__1(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
- valid_initial_msg._is_incoming = False
+ valid_initial_msg.counterparty = self.opponent_address
+ valid_initial_msg.is_incoming = False
- assert self.dialogue.update(valid_initial_msg)
+ dialogue = self.dialogue.update(valid_initial_msg)
+ assert dialogue is not None
valid_second_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -835,10 +803,12 @@ def test___str__1(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- valid_second_msg.counterparty = "agent 2"
- valid_second_msg._is_incoming = True
+ valid_second_msg.counterparty = self.opponent_address
+ valid_second_msg.sender = self.agent_address
+ valid_second_msg.is_incoming = True
- assert self.dialogue.update(valid_second_msg)
+ dialogue = self.dialogue.update(valid_second_msg)
+ assert dialogue is not None
valid_third_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -847,26 +817,19 @@ def test___str__1(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back 2",
)
- valid_third_msg.counterparty = "agent 2"
+ valid_third_msg.counterparty = self.opponent_address
valid_third_msg._is_incoming = False
assert self.dialogue.update(valid_third_msg)
dialogue_str = (
- "Dialogue Label: 1_1_agent 2_agent 1\nbytes( )\nbytes( )\nbytes( )"
+ "Dialogue Label: 1__agent 2_agent 1\nbytes( )\nbytes( )\nbytes( )"
)
assert str(self.dialogue) == dialogue_str
def test___str__2(self):
"""Test the '__str__' method: dialogue is other initiated"""
- self.dialogue._dialogue_label = DialogueLabel(
- dialogue_reference=(str(1), str(1)),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 2",
- )
- self.dialogue._is_self_initiated = False
-
valid_initial_msg = DefaultMessage(
dialogue_reference=(str(1), ""),
message_id=1,
@@ -874,10 +837,11 @@ def test___str__2(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- valid_initial_msg.counterparty = "agent 2"
- valid_initial_msg._is_incoming = True
+ valid_initial_msg.counterparty = self.opponent_address
+ valid_initial_msg.sender = self.agent_address
+ valid_initial_msg.is_incoming = True
- assert self.dialogue.update(valid_initial_msg)
+ assert self.dialogue_opponent_started.update(valid_initial_msg)
valid_second_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -886,10 +850,10 @@ def test___str__2(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- valid_second_msg.counterparty = "agent 2"
+ valid_second_msg.counterparty = self.opponent_address
valid_second_msg._is_incoming = False
- assert self.dialogue.update(valid_second_msg)
+ assert self.dialogue_opponent_started.update(valid_second_msg)
valid_third_msg = DefaultMessage(
dialogue_reference=(str(1), str(1)),
@@ -898,16 +862,17 @@ def test___str__2(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back 2",
)
- valid_third_msg.counterparty = "agent 2"
- valid_third_msg._is_incoming = True
+ valid_third_msg.counterparty = self.opponent_address
+ valid_third_msg.sender = self.agent_address
+ valid_third_msg.is_incoming = True
- assert self.dialogue.update(valid_third_msg)
+ assert self.dialogue_opponent_started.update(valid_third_msg)
dialogue_str = (
"Dialogue Label: 1_1_agent 2_agent 2\nbytes( )\nbytes( )\nbytes( )"
)
- assert str(self.dialogue) == dialogue_str
+ assert str(self.dialogue_opponent_started) == dialogue_str
class TestDialogueStats:
@@ -916,10 +881,12 @@ class TestDialogueStats:
@classmethod
def setup(cls):
"""Initialise the environment to test DialogueStats."""
+ cls.agent_address = "agent 1"
+ cls.opponent_address = "agent 2"
cls.dialogue_label = DialogueLabel(
dialogue_reference=(str(1), ""),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_opponent_addr=cls.opponent_address,
+ dialogue_starter_addr=cls.agent_address,
)
cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)
end_states = frozenset(
@@ -977,18 +944,20 @@ class TestDialoguesBase:
@classmethod
def setup(cls):
"""Initialise the environment to test Dialogue."""
+ cls.agent_address = "agent 1"
+ cls.opponent_address = "agent 2"
cls.dialogue_label = DialogueLabel(
dialogue_reference=(str(1), ""),
- dialogue_opponent_addr="agent 2",
- dialogue_starter_addr="agent 1",
+ dialogue_opponent_addr=cls.opponent_address,
+ dialogue_starter_addr=cls.agent_address,
)
cls.dialogue = Dialogue(dialogue_label=cls.dialogue_label)
- cls.dialogues = Dialogues("agent 1")
+ cls.dialogues = Dialogues(cls.agent_address)
def test_dialogues_properties(self):
"""Test dialogue properties."""
assert self.dialogues.dialogues == dict()
- assert self.dialogues.agent_address == "agent 1"
+ assert self.dialogues.agent_address == self.agent_address
assert self.dialogues.dialogue_stats.other_initiated == {
Dialogue.EndState.SUCCESSFUL: 0,
Dialogue.EndState.FAILED: 0,
@@ -1000,18 +969,25 @@ def test_dialogues_properties(self):
def test_new_self_initiated_dialogue_reference(self):
"""Test the 'new_self_initiated_dialogue_reference' method."""
- assert self.dialogues.new_self_initiated_dialogue_reference() == ("1", "")
+ nonce = self.dialogues._dialogue_nonce
+ assert self.dialogues.new_self_initiated_dialogue_reference() == (
+ str(nonce + 1),
+ "",
+ )
self.dialogues._create_opponent_initiated(
- "agent 2", ("1", ""), Dialogue.Role.ROLE1
+ self.opponent_address, ("1", ""), Dialogue.Role.ROLE1
+ ) # increments dialogue nonce
+ assert self.dialogues.new_self_initiated_dialogue_reference() == (
+ str(nonce + 3),
+ "",
)
- assert self.dialogues.new_self_initiated_dialogue_reference() == ("2", "")
def test_create_positive(self):
"""Positive test for the 'create' method."""
assert len(self.dialogues.dialogues) == 0
self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
assert len(self.dialogues.dialogues) == 1
@@ -1020,7 +996,9 @@ def test_create_negative_incorrect_performative_content_combination(self):
assert len(self.dialogues.dialogues) == 0
try:
self.dialogues.create(
- "agent 2", DefaultMessage.Performative.ERROR, content=b"Hello"
+ self.opponent_address,
+ DefaultMessage.Performative.ERROR,
+ content=b"Hello",
)
result = True
except Exception:
@@ -1029,6 +1007,19 @@ def test_create_negative_incorrect_performative_content_combination(self):
assert not result
assert len(self.dialogues.dialogues) == 0
+ def test_update_negative_invalid_label(self):
+ """Negative test for the 'update' method: dialogue is not extendable with the input message."""
+ invalid_message_id = DefaultMessage(
+ dialogue_reference=("", ""),
+ message_id=0,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"Hello",
+ )
+ invalid_message_id.counterparty = self.opponent_address
+
+ assert not self.dialogues.update(invalid_message_id)
+
def test_update_positive_new_dialogue_by_other(self):
"""Positive test for the 'update' method: the input message is for a new dialogue dialogue by other."""
initial_msg = DefaultMessage(
@@ -1038,8 +1029,9 @@ def test_update_positive_new_dialogue_by_other(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = True
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = True
+ initial_msg.sender = self.agent_address
assert len(self.dialogues.dialogues) == 0
@@ -1062,7 +1054,7 @@ def test_update_positive_new_dialogue_by_self(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
+ initial_msg.counterparty = self.opponent_address
initial_msg._is_incoming = False
assert len(self.dialogues.dialogues) == 0
@@ -1080,7 +1072,7 @@ def test_update_positive_new_dialogue_by_self(self):
def test_update_positive_existing_dialogue(self):
"""Positive test for the 'update' method: the input message is for an existing dialogue."""
self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1090,8 +1082,9 @@ def test_update_positive_existing_dialogue(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = True
+ second_msg.sender = self.agent_address
assert len(self.dialogues.dialogues) == 1
@@ -1114,24 +1107,38 @@ def test_update_negative_new_dialogue_by_self_no_counterparty(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg._is_incoming = False
+ initial_msg.is_incoming = False
assert len(self.dialogues.dialogues) == 0
- try:
+ with pytest.raises(ValueError):
self.dialogues.update(initial_msg)
- result = True
- except AssertionError:
- result = False
- assert not result
+ assert len(self.dialogues.dialogues) == 0
+
+ def test_update_negative_new_dialogue_by_other_no_sender(self):
+ """Negative test for the 'update' method: the counterparty of the input message is not set."""
+ initial_msg = DefaultMessage(
+ dialogue_reference=(str(1), ""),
+ message_id=1,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"Hello",
+ )
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = True
+
+ assert len(self.dialogues.dialogues) == 0
+
+ with pytest.raises(ValueError):
+ self.dialogues.update(initial_msg)
assert len(self.dialogues.dialogues) == 0
def test_update_negative_existing_dialogue_non_nonexistent(self):
"""Negative test for the 'update' method: the dialogue referred by the input message does not exist."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1141,8 +1148,9 @@ def test_update_negative_existing_dialogue_non_nonexistent(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = True
+ second_msg.sender = self.agent_address
updated_dialogue = self.dialogues.update(second_msg)
@@ -1166,10 +1174,12 @@ def test_update_negative_existing_dialogue_non_nonexistent(self):
== b"Hello"
)
- def test_update_self_initiated_dialogue_label_on_second_message_positive(self):
- """Positive test for the '_update_self_initiated_dialogue_label_on_second_message' method."""
+ def test_update_self_initiated_dialogue_label_on_message_with_complete_reference_positive(
+ self,
+ ):
+ """Positive test for the '_update_self_initiated_dialogue_label_on_message_with_complete_reference' method."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1179,10 +1189,11 @@ def test_update_self_initiated_dialogue_label_on_second_message_positive(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = True
+ second_msg.sender = self.agent_address
- self.dialogues._update_self_initiated_dialogue_label_on_second_message(
+ self.dialogues._update_self_initiated_dialogue_label_on_message_with_complete_reference(
second_msg
)
@@ -1190,12 +1201,12 @@ def test_update_self_initiated_dialogue_label_on_second_message_positive(self):
dialogue.dialogue_label
].dialogue_label.dialogue_reference == (str(1), str(1))
- def test_update_self_initiated_dialogue_label_on_second_message_negative_incorrect_reference(
+ def test_update_self_initiated_dialogue_label_on_message_with_complete_reference_negative_incorrect_reference(
self,
):
- """Negative test for the '_update_self_initiated_dialogue_label_on_second_message' method: the input message has invalid dialogue reference."""
+ """Negative test for the '_update_self_initiated_dialogue_label_on_message_with_complete_reference' method: the input message has invalid dialogue reference."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1205,10 +1216,11 @@ def test_update_self_initiated_dialogue_label_on_second_message_negative_incorre
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = True
+ second_msg.sender = self.agent_address
- self.dialogues._update_self_initiated_dialogue_label_on_second_message(
+ self.dialogues._update_self_initiated_dialogue_label_on_message_with_complete_reference(
second_msg
)
@@ -1219,7 +1231,7 @@ def test_update_self_initiated_dialogue_label_on_second_message_negative_incorre
def test_get_dialogue_positive_1(self):
"""Positive test for the 'get_dialogue' method: the dialogue is self initiated and the second message is by the other agent."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1229,10 +1241,10 @@ def test_get_dialogue_positive_1(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
+ second_msg.counterparty = self.opponent_address
second_msg._is_incoming = True
- self.dialogues._update_self_initiated_dialogue_label_on_second_message(
+ self.dialogues._update_self_initiated_dialogue_label_on_message_with_complete_reference(
second_msg
)
@@ -1248,13 +1260,14 @@ def test_get_dialogue_positive_2(self):
"""Positive test for the 'get_dialogue' method: the dialogue is other initiated and the second message is by this agent."""
initial_msg = DefaultMessage(
dialogue_reference=(str(1), ""),
- message_id=2,
- target=1,
+ message_id=1,
+ target=0,
performative=DefaultMessage.Performative.BYTES,
content=b"Hello",
)
- initial_msg.counterparty = "agent 2"
- initial_msg._is_incoming = True
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = True
+ initial_msg.sender = self.agent_address
dialogue = self.dialogues.update(initial_msg)
@@ -1265,17 +1278,45 @@ def test_get_dialogue_positive_2(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
+ second_msg.counterparty = self.opponent_address
second_msg._is_incoming = False
retrieved_dialogue = self.dialogues.get_dialogue(second_msg)
assert retrieved_dialogue.dialogue_label == dialogue.dialogue_label
+ def test_update_positive_3(self):
+ """Positive test for the 'get_dialogue' method: the dialogue is reference is incomplete and not a first message."""
+ initial_msg = DefaultMessage(
+ dialogue_reference=(str(1), ""),
+ message_id=1,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"Hello",
+ )
+ initial_msg.counterparty = self.opponent_address
+ initial_msg.is_incoming = False
+
+ dialogue = self.dialogues.update(initial_msg)
+
+ second_msg = DefaultMessage(
+ dialogue_reference=(str(1), ""),
+ message_id=2,
+ target=1,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"Hello back",
+ )
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = False
+
+ retrieved_dialogue = self.dialogues.update(second_msg)
+
+ assert retrieved_dialogue.dialogue_label == dialogue.dialogue_label
+
def test_get_dialogue_negative_invalid_reference(self):
"""Negative test for the 'get_dialogue' method: the inpute message has invalid dialogue reference."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
second_msg = DefaultMessage(
@@ -1285,10 +1326,11 @@ def test_get_dialogue_negative_invalid_reference(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- second_msg.counterparty = "agent 2"
- second_msg._is_incoming = True
-
- self.dialogues.update(second_msg)
+ second_msg.counterparty = self.opponent_address
+ second_msg.is_incoming = True
+ second_msg.sender = self.agent_address
+ dialogue = self.dialogues.update(second_msg)
+ assert dialogue is not None
third_msg = DefaultMessage(
dialogue_reference=(str(2), str(1)),
@@ -1297,8 +1339,8 @@ def test_get_dialogue_negative_invalid_reference(self):
performative=DefaultMessage.Performative.BYTES,
content=b"Hello back",
)
- third_msg.counterparty = "agent 2"
- third_msg._is_incoming = False
+ third_msg.counterparty = self.opponent_address
+ third_msg.is_incoming = False
retrieved_dialogue = self.dialogues.get_dialogue(third_msg)
@@ -1307,7 +1349,7 @@ def test_get_dialogue_negative_invalid_reference(self):
def test_get_dialogue_from_label_positive(self):
"""Positive test for the 'get_dialogue_from_label' method."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
retrieved_dialogue = self.dialogues.get_dialogue_from_label(
@@ -1318,10 +1360,12 @@ def test_get_dialogue_from_label_positive(self):
def test_get_dialogue_from_label_negative_incorrect_input_label(self):
"""Negative test for the 'get_dialogue_from_label' method: the input dialogue label does not exist."""
_, dialogue = self.dialogues.create(
- "agent 2", DefaultMessage.Performative.BYTES, content=b"Hello"
+ self.opponent_address, DefaultMessage.Performative.BYTES, content=b"Hello"
)
- incorrect_label = DialogueLabel((str(1), "error"), "agent 2", "agent 1")
+ incorrect_label = DialogueLabel(
+ (str(1), "error"), self.opponent_address, self.agent_address
+ )
retrieved_dialogue = self.dialogues.get_dialogue_from_label(incorrect_label)
assert retrieved_dialogue is None
@@ -1330,7 +1374,9 @@ def test_create_self_initiated_positive(self):
"""Positive test for the '_create_self_initiated' method."""
assert len(self.dialogues.dialogues) == 0
- self.dialogues._create_self_initiated("agent 2", Dialogue.Role.ROLE1)
+ self.dialogues._create_self_initiated(
+ self.opponent_address, (str(1), ""), Dialogue.Role.ROLE1
+ )
assert len(self.dialogues.dialogues) == 1
def test_create_opponent_initiated_positive(self):
@@ -1338,7 +1384,7 @@ def test_create_opponent_initiated_positive(self):
assert len(self.dialogues.dialogues) == 0
self.dialogues._create_opponent_initiated(
- "agent 2", (str(1), ""), Dialogue.Role.ROLE2
+ self.opponent_address, (str(1), ""), Dialogue.Role.ROLE2
)
assert len(self.dialogues.dialogues) == 1
@@ -1348,7 +1394,7 @@ def test_create_opponent_initiated_negative_invalid_input_dialogue_reference(sel
try:
self.dialogues._create_opponent_initiated(
- "agent 2", ("", str(1)), Dialogue.Role.ROLE2
+ self.opponent_address, ("", str(1)), Dialogue.Role.ROLE2
)
result = True
except AssertionError:
diff --git a/tests/test_helpers/test_logging.py b/tests/test_helpers/test_logging.py
new file mode 100644
index 0000000000..1a0b893875
--- /dev/null
+++ b/tests/test_helpers/test_logging.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 tests for the helpers/logging module."""
+import logging
+
+from aea.helpers.logging import AgentLoggerAdapter, WithLogger
+
+
+def test_agent_logger_adapter(caplog):
+ """Test the agent logger adapter."""
+ logger = logging.getLogger("some.logger")
+ logger = AgentLoggerAdapter(logger, agent_name="some_agent")
+ with caplog.at_level(logging.DEBUG, logger="some.logger"):
+ logger.debug("Some log message.")
+ assert "[some_agent] Some log message." in caplog.text
+
+
+def test_with_logger_default_logger_name(caplog):
+ """Test the WithLogger interface, default logger name."""
+
+ class SomeClass(WithLogger):
+ pass
+
+ x = SomeClass()
+ assert isinstance(x.logger, logging.Logger)
+
+ with caplog.at_level(logging.DEBUG, logger="aea"):
+ x.logger.debug("Some log message.")
+ assert "Some log message." in caplog.text
+
+
+def test_with_logger_custom_logger_name(caplog):
+ """Test the WithLogger interface, custom logger name."""
+
+ class SomeClass(WithLogger):
+ pass
+
+ x = SomeClass(default_logger_name="some.logger")
+ assert isinstance(x.logger, logging.Logger)
+
+ with caplog.at_level(logging.DEBUG, logger="some.logger"):
+ x.logger.debug("Some log message.")
+ assert "Some log message." in caplog.text
+
+
+def test_with_logger_custom_logger(caplog):
+ """Test the WithLogger interface, custom logger."""
+
+ class SomeClass(WithLogger):
+ pass
+
+ logger = logging.getLogger("some.logger")
+ x = SomeClass(logger=logger)
+ assert isinstance(x.logger, logging.Logger)
+
+ with caplog.at_level(logging.DEBUG, logger="some.logger"):
+ x.logger.debug("Some log message.")
+ assert "Some log message." in caplog.text
+
+
+def test_with_logger_setter():
+ """Test the WithLogger interface, logger setter."""
+
+ class SomeClass(WithLogger):
+ pass
+
+ logger_1 = logging.getLogger("some.logger")
+ x = SomeClass(logger=logger_1)
+ assert isinstance(x.logger, logging.Logger)
+ assert x.logger.name == "some.logger"
+ logger_2 = logging.getLogger("another.logger")
+ x.logger = logger_2
+ assert x.logger.name == "another.logger"
diff --git a/tests/test_helpers/test_transaction/test_base.py b/tests/test_helpers/test_transaction/test_base.py
index 63d1cc5574..e1a96f7238 100644
--- a/tests/test_helpers/test_transaction/test_base.py
+++ b/tests/test_helpers/test_transaction/test_base.py
@@ -21,6 +21,7 @@
import pytest
+from aea.configurations.constants import DEFAULT_LEDGER
from aea.helpers.transaction.base import (
RawMessage,
RawTransaction,
@@ -35,7 +36,7 @@
def test_init_terms():
"""Test the terms object initialization."""
- ledger_id = "some_ledger"
+ ledger_id = DEFAULT_LEDGER
sender_addr = "SenderAddress"
counterparty_addr = "CounterpartyAddress"
amount_by_currency_id = {"FET": -10}
@@ -43,6 +44,7 @@ def test_init_terms():
is_sender_payable_tx_fee = True
nonce = "somestring"
kwargs = {"key": "value"}
+ fee_by_currency_id = {}
terms = Terms(
ledger_id=ledger_id,
sender_address=sender_addr,
@@ -53,6 +55,10 @@ def test_init_terms():
nonce=nonce,
**kwargs
)
+ sender_hash = "9af02c24bdb18b73aad129291dc9eee008f9bcf62f5a6e91b5cb7427f146ca3b"
+ counterparty_hash = (
+ "174c1321c0eb4a49bf99d783b56f4fc30d0ee558106454c56d1c0fad295ccc79"
+ )
assert terms.ledger_id == ledger_id
assert terms.sender_address == sender_addr
assert terms.counterparty_address == counterparty_addr
@@ -61,9 +67,23 @@ def test_init_terms():
assert terms.is_sender_payable_tx_fee == is_sender_payable_tx_fee
assert terms.nonce == nonce
assert terms.kwargs == kwargs
- assert (
- str(terms)
- == "Terms: ledger_id=some_ledger, sender_address=SenderAddress, counterparty_address=CounterpartyAddress, amount_by_currency_id={'FET': -10}, quantities_by_good_id={'good_1': 20}, is_sender_payable_tx_fee=True, nonce=somestring, fee_by_currency_id=None, kwargs={'key': 'value'}"
+ assert terms.fee_by_currency_id == fee_by_currency_id
+ assert terms.id == sender_hash
+ assert terms.sender_hash == sender_hash
+ assert terms.counterparty_hash == counterparty_hash
+ assert terms.currency_id == next(iter(amount_by_currency_id.keys()))
+ assert str(
+ terms
+ ) == "Terms: ledger_id={}, sender_address={}, counterparty_address={}, amount_by_currency_id={}, quantities_by_good_id={}, is_sender_payable_tx_fee={}, nonce={}, fee_by_currency_id={}, kwargs={}".format(
+ ledger_id,
+ sender_addr,
+ counterparty_addr,
+ amount_by_currency_id,
+ quantities_by_good_id,
+ is_sender_payable_tx_fee,
+ nonce,
+ fee_by_currency_id,
+ kwargs,
)
assert terms == terms
with pytest.raises(AssertionError):
@@ -72,14 +92,14 @@ def test_init_terms():
def test_init_terms_w_fee():
"""Test the terms object initialization with fee."""
- ledger_id = "some_ledger"
+ ledger_id = DEFAULT_LEDGER
sender_addr = "SenderAddress"
counterparty_addr = "CounterpartyAddress"
amount_by_currency_id = {"FET": -10}
quantities_by_good_id = {"good_1": 20}
is_sender_payable_tx_fee = True
nonce = "somestring"
- fee = {"FET": 1}
+ fee_by_currency_id = {"FET": 1}
terms = Terms(
ledger_id=ledger_id,
sender_address=sender_addr,
@@ -88,17 +108,176 @@ def test_init_terms_w_fee():
quantities_by_good_id=quantities_by_good_id,
is_sender_payable_tx_fee=is_sender_payable_tx_fee,
nonce=nonce,
- fee_by_currency_id=fee,
+ fee_by_currency_id=fee_by_currency_id,
)
new_counterparty_address = "CounterpartyAddressNew"
terms.counterparty_address = new_counterparty_address
assert terms.counterparty_address == new_counterparty_address
- assert terms.fee == fee["FET"]
- assert terms.fee_by_currency_id == fee
+ assert terms.fee == next(iter(fee_by_currency_id.values()))
+ assert terms.fee_by_currency_id == fee_by_currency_id
+ assert terms.counterparty_payable_amount == 0
+ assert terms.sender_payable_amount == -next(iter(amount_by_currency_id.values()))
+ assert terms.sender_payable_amount_incl_fee == -next(
+ iter(amount_by_currency_id.values())
+ ) + next(iter(fee_by_currency_id.values()))
+ assert terms.sender_fee == next(iter(fee_by_currency_id.values()))
+ assert terms.counterparty_fee == 0
+
+
+def test_init_terms_w_fee_counterparty():
+ """Test the terms object initialization with fee."""
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {"FET": 10}
+ quantities_by_good_id = {"good_1": -20}
+ is_sender_payable_tx_fee = False
+ nonce = "somestring"
+ fee_by_currency_id = {"FET": 1}
+ terms = Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ fee_by_currency_id=fee_by_currency_id,
+ )
+ new_counterparty_address = "CounterpartyAddressNew"
+ terms.counterparty_address = new_counterparty_address
+ assert terms.counterparty_address == new_counterparty_address
+ assert terms.fee == next(iter(fee_by_currency_id.values()))
+ assert terms.fee_by_currency_id == fee_by_currency_id
assert terms.counterparty_payable_amount == next(
iter(amount_by_currency_id.values())
)
- assert terms.sender_payable_amount == -next(iter(amount_by_currency_id.values()))
+ assert terms.counterparty_payable_amount_incl_fee == next(
+ iter(amount_by_currency_id.values())
+ ) + next(iter(fee_by_currency_id.values()))
+ assert terms.sender_payable_amount == 0
+ assert terms.sender_fee == 0
+ assert terms.counterparty_fee == next(iter(fee_by_currency_id.values()))
+
+
+def test_init_terms_strict_positive():
+ """Test the terms object initialization in strict mode."""
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {"FET": -10}
+ quantities_by_good_id = {"good_1": 20}
+ is_sender_payable_tx_fee = True
+ nonce = "somestring"
+ assert Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ is_strict=True,
+ )
+
+
+def test_init_terms_strict_negative():
+ """Test the terms object initialization in strict mode."""
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {"FET": 10}
+ quantities_by_good_id = {"good_1": 20}
+ is_sender_payable_tx_fee = True
+ nonce = "somestring"
+ with pytest.raises(AssertionError):
+ Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ is_strict=True,
+ )
+
+
+def test_init_terms_multiple_goods():
+ """Test the terms object initialization with multiple goods."""
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {"FET": -10}
+ quantities_by_good_id = {"good_1": 20, "good_2": -10}
+ is_sender_payable_tx_fee = True
+ nonce = "somestring"
+ terms = Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ )
+ assert (
+ terms.id == "f81812773f5242d0cb52cfa82bc08bdba8d17b1e56e2cf02b3056749184e198c"
+ )
+
+
+def test_init_terms_no_amount_and_quantity():
+ """Test the terms object initialization with no amount."""
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {}
+ quantities_by_good_id = {}
+ nonce = "somestring"
+ terms = Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ nonce=nonce,
+ )
+ new_counterparty_address = "CounterpartyAddressNew"
+ terms.counterparty_address = new_counterparty_address
+ assert terms.counterparty_address == new_counterparty_address
+ assert not terms.has_fee
+ assert terms.counterparty_payable_amount == 0
+ assert terms.counterparty_payable_amount_incl_fee == 0
+ assert terms.sender_payable_amount == 0
+ assert terms.sender_payable_amount_incl_fee == 0
+
+
+def test_terms_encode_decode():
+ """Test encoding and decoding of terms."""
+
+ class TermsProtobufObject:
+ terms_bytes = b""
+
+ ledger_id = DEFAULT_LEDGER
+ sender_addr = "SenderAddress"
+ counterparty_addr = "CounterpartyAddress"
+ amount_by_currency_id = {"FET": -10}
+ quantities_by_good_id = {"good_1": 20}
+ is_sender_payable_tx_fee = True
+ nonce = "somestring"
+ terms = Terms(
+ ledger_id=ledger_id,
+ sender_address=sender_addr,
+ counterparty_address=counterparty_addr,
+ amount_by_currency_id=amount_by_currency_id,
+ quantities_by_good_id=quantities_by_good_id,
+ is_sender_payable_tx_fee=is_sender_payable_tx_fee,
+ nonce=nonce,
+ is_strict=True,
+ )
+ Terms.encode(TermsProtobufObject, terms)
+ recovered_terms = Terms.decode(TermsProtobufObject)
+ assert terms == recovered_terms
def test_init_raw_transaction():
@@ -112,6 +291,20 @@ def test_init_raw_transaction():
assert rt == rt
+def test_raw_transaction_encode_decode():
+ """Test encoding and decoding of terms."""
+
+ class RawTransactionProtobufObject:
+ raw_transaction_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "body"
+ rt = RawTransaction(ledger_id, body)
+ RawTransaction.encode(RawTransactionProtobufObject, rt)
+ recovered_rt = RawTransaction.decode(RawTransactionProtobufObject)
+ assert rt == recovered_rt
+
+
def test_init_raw_message():
"""Test the raw_message object initialization."""
ledger_id = "some_ledger"
@@ -127,6 +320,20 @@ def test_init_raw_message():
assert rm == rm
+def test_raw_message_encode_decode():
+ """Test encoding and decoding of raw_message."""
+
+ class RawMessageProtobufObject:
+ raw_message_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "body"
+ rm = RawMessage(ledger_id, body)
+ RawMessage.encode(RawMessageProtobufObject, rm)
+ recovered_rm = RawMessage.decode(RawMessageProtobufObject)
+ assert rm == recovered_rm
+
+
def test_init_signed_transaction():
"""Test the signed_transaction object initialization."""
ledger_id = "some_ledger"
@@ -138,6 +345,20 @@ def test_init_signed_transaction():
assert st == st
+def test_signed_transaction_encode_decode():
+ """Test encoding and decoding of signed_transaction."""
+
+ class SignedTransactionProtobufObject:
+ signed_transaction_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "body"
+ st = SignedTransaction(ledger_id, body)
+ SignedTransaction.encode(SignedTransactionProtobufObject, st)
+ recovered_st = SignedTransaction.decode(SignedTransactionProtobufObject)
+ assert st == recovered_st
+
+
def test_init_signed_message():
"""Test the signed_message object initialization."""
ledger_id = "some_ledger"
@@ -153,6 +374,20 @@ def test_init_signed_message():
assert sm == sm
+def test_signed_message_encode_decode():
+ """Test encoding and decoding of signed_message."""
+
+ class SignedMessageProtobufObject:
+ signed_message_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "body"
+ sm = SignedMessage(ledger_id, body)
+ SignedMessage.encode(SignedMessageProtobufObject, sm)
+ recovered_sm = SignedMessage.decode(SignedMessageProtobufObject)
+ assert sm == recovered_sm
+
+
def test_init_transaction_receipt():
"""Test the transaction_receipt object initialization."""
ledger_id = "some_ledger"
@@ -169,6 +404,21 @@ def test_init_transaction_receipt():
assert tr == tr
+def test_transaction_receipt_encode_decode():
+ """Test encoding and decoding of transaction_receipt."""
+
+ class TransactionReceiptProtobufObject:
+ transaction_receipt_bytes = b""
+
+ ledger_id = "some_ledger"
+ receipt = "receipt"
+ transaction = "transaction"
+ tr = TransactionReceipt(ledger_id, receipt, transaction)
+ TransactionReceipt.encode(TransactionReceiptProtobufObject, tr)
+ recovered_tr = TransactionReceipt.decode(TransactionReceiptProtobufObject)
+ assert tr == recovered_tr
+
+
def test_init_state():
"""Test the state object initialization."""
ledger_id = "some_ledger"
@@ -180,12 +430,40 @@ def test_init_state():
assert state == state
+def test_state_encode_decode():
+ """Test encoding and decoding of state."""
+
+ class StateProtobufObject:
+ state_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "state"
+ state = State(ledger_id, body)
+ State.encode(StateProtobufObject, state)
+ recovered_state = State.decode(StateProtobufObject)
+ assert state == recovered_state
+
+
def test_init_transaction_digest():
"""Test the transaction_digest object initialization."""
ledger_id = "some_ledger"
- body = "state"
+ body = "digest"
td = TransactionDigest(ledger_id, body)
assert td.ledger_id == ledger_id
assert td.body == body
- assert str(td) == "TransactionDigest: ledger_id=some_ledger, body=state"
+ assert str(td) == "TransactionDigest: ledger_id={}, body={}".format(ledger_id, body)
assert td == td
+
+
+def test_transaction_digest_encode_decode():
+ """Test encoding and decoding of transaction_digest."""
+
+ class TransactionDigestProtobufObject:
+ transaction_digest_bytes = b""
+
+ ledger_id = "some_ledger"
+ body = "digest"
+ td = TransactionDigest(ledger_id, body)
+ TransactionDigest.encode(TransactionDigestProtobufObject, td)
+ recovered_td = TransactionDigest.decode(TransactionDigestProtobufObject)
+ assert td == recovered_td
diff --git a/tests/test_launcher.py b/tests/test_launcher.py
index 61c8f154c3..aa41aded02 100644
--- a/tests/test_launcher.py
+++ b/tests/test_launcher.py
@@ -141,10 +141,11 @@ def test_one_fails(self) -> None:
runner.stop()
def test_run_agent_in_thread(self):
- """Test agent started ans stopped in thread."""
+ """Test agent started and stopped in thread."""
stop_event = Event()
t = Thread(target=_run_agent, args=(self.agent_name_1, stop_event))
t.start()
+ time.sleep(1)
stop_event.set()
t.join(10)
diff --git a/tests/test_mail/test_base.py b/tests/test_mail/test_base.py
index f6aace7334..3b4a3db371 100644
--- a/tests/test_mail/test_base.py
+++ b/tests/test_mail/test_base.py
@@ -175,6 +175,7 @@ def test_outbox_put():
content=b"hello",
)
msg.counterparty = receiver_address
+ msg.sender = agent_address
dummy_connection = _make_dummy_connection()
multiplexer = Multiplexer([dummy_connection])
outbox = OutBox(multiplexer, agent_address)
@@ -204,6 +205,7 @@ def test_outbox_put_message():
content=b"hello",
)
msg.counterparty = receiver_address
+ msg.sender = agent_address
dummy_connection = _make_dummy_connection()
multiplexer = Multiplexer([dummy_connection])
outbox = OutBox(multiplexer, agent_address)
diff --git a/tests/test_multiplexer.py b/tests/test_multiplexer.py
index 9fc8210532..21dedf10fc 100644
--- a/tests/test_multiplexer.py
+++ b/tests/test_multiplexer.py
@@ -35,7 +35,7 @@
from aea.configurations.base import PublicId
from aea.identity.base import Identity
from aea.mail.base import AEAConnectionError, Envelope, EnvelopeContext
-from aea.multiplexer import AsyncMultiplexer, InBox, Multiplexer
+from aea.multiplexer import AsyncMultiplexer, InBox, Multiplexer, OutBox
from aea.protocols.default.message import DefaultMessage
from packages.fetchai.connections.local.connection import LocalNode
@@ -156,9 +156,9 @@ def test_multiplexer_connect_one_raises_error_many_connections():
connection_3 = _make_dummy_connection()
multiplexer = Multiplexer([connection_1, connection_2, connection_3])
- assert not connection_1.connection_status.is_connected
- assert not connection_2.connection_status.is_connected
- assert not connection_3.connection_status.is_connected
+ assert not connection_1.is_connected
+ assert not connection_2.is_connected
+ assert not connection_3.is_connected
with unittest.mock.patch.object(connection_3, "connect", side_effect=Exception):
with pytest.raises(
@@ -166,9 +166,9 @@ def test_multiplexer_connect_one_raises_error_many_connections():
):
multiplexer.connect()
- assert not connection_1.connection_status.is_connected
- assert not connection_2.connection_status.is_connected
- assert not connection_3.connection_status.is_connected
+ assert not connection_1.is_connected
+ assert not connection_2.is_connected
+ assert not connection_3.is_connected
multiplexer.disconnect()
try:
@@ -228,15 +228,15 @@ async def test_multiplexer_disconnect_one_raises_error_many_connections():
connection_3 = _make_dummy_connection()
multiplexer = Multiplexer([connection_1, connection_2, connection_3])
- assert not connection_1.connection_status.is_connected
- assert not connection_2.connection_status.is_connected
- assert not connection_3.connection_status.is_connected
+ assert not connection_1.is_connected
+ assert not connection_2.is_connected
+ assert not connection_3.is_connected
multiplexer.connect()
- assert connection_1.connection_status.is_connected
- assert connection_2.connection_status.is_connected
- assert connection_3.connection_status.is_connected
+ assert connection_1.is_connected
+ assert connection_2.is_connected
+ assert connection_3.is_connected
with unittest.mock.patch.object(
connection_3, "disconnect", side_effect=Exception
@@ -246,9 +246,9 @@ async def test_multiplexer_disconnect_one_raises_error_many_connections():
):
multiplexer.disconnect()
- assert not connection_1.connection_status.is_connected
- assert not connection_2.connection_status.is_connected
- assert connection_3.connection_status.is_connected
+ assert not connection_1.is_connected
+ assert not connection_2.is_connected
+ assert connection_3.is_connected
# clean the test up.
await connection_3.disconnect()
@@ -371,13 +371,13 @@ def test_get_from_multiplexer_when_empty():
# multiplexer = Multiplexer([connection_1, connection_2])
-# assert not connection_1.connection_status.is_connected
-# assert not connection_2.connection_status.is_connected
+# assert not connection_1.is_connected
+# assert not connection_2.is_connected
# multiplexer.connect()
-# assert connection_1.connection_status.is_connected
-# assert connection_2.connection_status.is_connected
+# assert connection_1.is_connected
+# assert connection_2.is_connected
# message = DefaultMessage(
# dialogue_reference=("", ""),
# message_id=1,
@@ -489,23 +489,91 @@ async def test_inbox_outbox():
connection_1 = _make_dummy_connection()
connections = [connection_1]
multiplexer = AsyncMultiplexer(connections, loop=asyncio.get_event_loop())
+ msg = DefaultMessage(performative=DefaultMessage.Performative.BYTES, content=b"",)
+ msg.counterparty = "to"
+ msg.sender = "sender"
+ context = EnvelopeContext(connection_id=connection_1.connection_id)
envelope = Envelope(
- to="",
- sender="",
- protocol_id=DefaultMessage.protocol_id,
- message=b"",
- context=EnvelopeContext(connection_id=connection_1.connection_id),
+ to="to",
+ sender="sender",
+ protocol_id=msg.protocol_id,
+ message=msg,
+ context=context,
)
try:
await multiplexer.connect()
inbox = InBox(multiplexer)
- outbox = InBox(multiplexer)
+ outbox = OutBox(multiplexer, "default_address")
assert inbox.empty()
assert outbox.empty()
- multiplexer.put(envelope)
- await outbox.async_get()
+ outbox.put(envelope)
+ received = await inbox.async_get()
+ assert received == envelope
+
+ assert inbox.empty()
+ assert outbox.empty()
+
+ outbox.put_message(msg, context=context)
+ await inbox.async_wait()
+ received = inbox.get_nowait()
+ assert received == envelope
+
+ finally:
+ await multiplexer.disconnect()
+
+
+@pytest.mark.asyncio
+async def test_outbox_negative():
+ """Test InBox OutBox objects."""
+ connection_1 = _make_dummy_connection()
+ connections = [connection_1]
+ multiplexer = AsyncMultiplexer(connections, loop=asyncio.get_event_loop())
+ msg = DefaultMessage(performative=DefaultMessage.Performative.BYTES, content=b"",)
+ context = EnvelopeContext(connection_id=connection_1.connection_id)
+ envelope = Envelope(
+ to="to",
+ sender="sender",
+ protocol_id=msg.protocol_id,
+ message=b"",
+ context=context,
+ )
+
+ try:
+ await multiplexer.connect()
+ outbox = OutBox(multiplexer, "default_address")
+
+ assert outbox.empty()
+
+ with pytest.raises(ValueError) as execinfo:
+ outbox.put(envelope)
+ assert (
+ str(execinfo.value)
+ == "Only Message type allowed in envelope message field when putting into outbox."
+ )
+
+ assert outbox.empty()
+
+ with pytest.raises(ValueError) as execinfo:
+ outbox.put_message("")
+ assert str(execinfo.value) == "Provided message not of type Message."
+
+ assert outbox.empty()
+
+ with pytest.raises(ValueError) as execinfo:
+ outbox.put_message(msg)
+ assert (
+ str(execinfo.value) == "Provided message has message.counterparty not set."
+ )
+
+ assert outbox.empty()
+ msg.counterparty = "to"
+
+ with pytest.raises(ValueError) as execinfo:
+ outbox.put_message(msg)
+ assert str(execinfo.value) == "Provided message has message.sender not set."
+
finally:
await multiplexer.disconnect()
diff --git a/tests/test_packages/test_connections/test_gym/test_gym.py b/tests/test_packages/test_connections/test_gym/test_gym.py
index 32c23eba3b..077823c301 100644
--- a/tests/test_packages/test_connections/test_gym/test_gym.py
+++ b/tests/test_packages/test_connections/test_gym/test_gym.py
@@ -18,8 +18,10 @@
# ------------------------------------------------------------------------------
"""This module contains the tests of the gym connection module."""
import asyncio
+import copy
import logging
import os
+from typing import cast
from unittest.mock import patch
import gym
@@ -30,7 +32,9 @@
from aea.identity.base import Identity
from aea.mail.base import Envelope
+
from packages.fetchai.connections.gym.connection import GymConnection
+from packages.fetchai.protocols.gym.dialogues import GymDialogue, GymDialogues
from packages.fetchai.protocols.gym.message import GymMessage
from tests.conftest import ROOT_DIR, UNKNOWN_PROTOCOL_PUBLIC_ID
@@ -45,12 +49,14 @@ def setup(self):
"""Initialise the class."""
self.env = gym.GoalEnv()
configuration = ConnectionConfig(connection_id=GymConnection.connection_id)
- self.my_address = "my_key"
- identity = Identity("name", address=self.my_address)
+ self.agent_address = "my_address"
+ identity = Identity("name", address=self.agent_address)
self.gym_con = GymConnection(
gym_env=self.env, identity=identity, configuration=configuration
)
self.loop = asyncio.get_event_loop()
+ self.gym_address = str(GymConnection.connection_id)
+ self.dialogues = GymDialogues(self.gym_address)
def teardown(self):
"""Clean up after tests."""
@@ -68,8 +74,8 @@ async def test_decode_envelope_error(self):
"""Test the decoding error for the envelopes."""
await self.gym_con.connect()
envelope = Envelope(
- to="_to_key",
- sender=self.my_address,
+ to=self.gym_address,
+ sender=self.agent_address,
protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
message=b"hello",
)
@@ -81,15 +87,16 @@ async def test_decode_envelope_error(self):
async def test_send_connection_error(self):
"""Test send connection error."""
msg = GymMessage(
- performative=GymMessage.Performative.ACT,
- action=GymMessage.AnyObject("any_action"),
- step_id=1,
+ performative=GymMessage.Performative.RESET,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
)
- msg.counterparty = "_to_key"
+ msg.counterparty = self.gym_address
+ sending_dialogue = self.dialogues.update(msg)
+ assert sending_dialogue is not None
envelope = Envelope(
- to="_to_key",
- sender="_from_key",
- protocol_id=GymMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
@@ -99,64 +106,138 @@ async def test_send_connection_error(self):
@pytest.mark.asyncio
async def test_send_act(self):
"""Test send act message."""
+ sending_dialogue = await self.send_reset()
+ last_message = sending_dialogue.last_message
+ assert last_message is not None
msg = GymMessage(
performative=GymMessage.Performative.ACT,
action=GymMessage.AnyObject("any_action"),
step_id=1,
+ dialogue_reference=sending_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_message.message_id + 1,
+ target=last_message.message_id,
)
- msg.counterparty = "_to_key"
+ msg.counterparty = self.gym_address
+ assert sending_dialogue.update(msg)
envelope = Envelope(
- to="_to_key",
- sender=self.my_address,
- protocol_id=GymMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
await self.gym_con.connect()
+ observation = 1
+ reward = 1.0
+ done = True
+ info = "some info"
with patch.object(
- self.env, "step", return_value=(1, 1.0, True, "some info")
+ self.env, "step", return_value=(observation, reward, done, info)
) as mock:
await self.gym_con.send(envelope)
mock.assert_called()
- assert await asyncio.wait_for(self.gym_con.receive(), timeout=3) is not None
+ response = await asyncio.wait_for(self.gym_con.receive(), timeout=3)
+ response_msg_orig = cast(GymMessage, response.message)
+ response_msg = copy.copy(response_msg_orig)
+ response_msg.is_incoming = True
+ response_msg.counterparty = response_msg_orig.sender
+ response_dialogue = self.dialogues.update(response_msg)
+
+ assert response_msg.performative == GymMessage.Performative.PERCEPT
+ assert response_msg.step_id == msg.step_id
+ assert response_msg.observation.any == observation
+ assert response_msg.reward == reward
+ assert response_msg.done == done
+ assert response_msg.info.any == info
+ assert sending_dialogue == response_dialogue
@pytest.mark.asyncio
async def test_send_reset(self):
"""Test send reset message."""
- msg = GymMessage(performative=GymMessage.Performative.RESET,)
- msg.counterparty = "_to_key"
+ _ = await self.send_reset()
+
+ @pytest.mark.asyncio
+ async def test_send_close(self):
+ """Test send close message."""
+ sending_dialogue = await self.send_reset()
+ last_message = sending_dialogue.last_message
+ assert last_message is not None
+ msg = GymMessage(
+ performative=GymMessage.Performative.CLOSE,
+ dialogue_reference=sending_dialogue.dialogue_label.dialogue_reference,
+ message_id=last_message.message_id + 1,
+ target=last_message.message_id,
+ )
+ msg.counterparty = self.gym_address
+ assert sending_dialogue.update(msg)
envelope = Envelope(
- to="_to_key",
- sender=self.my_address,
- protocol_id=GymMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
await self.gym_con.connect()
- with pytest.raises(gym.error.Error):
+ with patch.object(self.env, "close") as mock:
await self.gym_con.send(envelope)
-
- with pytest.raises(asyncio.TimeoutError):
- await asyncio.wait_for(self.gym_con.receive(), timeout=0.5)
+ mock.assert_called()
@pytest.mark.asyncio
- async def test_send_close(self):
- """Test send close message."""
- msg = GymMessage(performative=GymMessage.Performative.CLOSE,)
- msg.counterparty = "_to_key"
+ async def test_send_close_negative(self):
+ """Test send close message with invalid reference and message id and target."""
+ msg = GymMessage(
+ performative=GymMessage.Performative.CLOSE,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
+ )
+ msg.counterparty = self.gym_address
+ dialogue = self.dialogues.update(msg)
+ assert dialogue is None
+ msg.sender = self.agent_address
+ envelope = Envelope(
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
+ message=msg,
+ )
+ await self.gym_con.connect()
+
+ with patch.object(self.gym_con.channel.logger, "warning") as mock_logger:
+ await self.gym_con.send(envelope)
+ mock_logger.assert_any_call(f"Could not create dialogue from message={msg}")
+
+ async def send_reset(self) -> GymDialogue:
+ """Send a reset."""
+ msg = GymMessage(
+ performative=GymMessage.Performative.RESET,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
+ )
+ msg.counterparty = self.gym_address
+ sending_dialogue = self.dialogues.update(msg)
+ assert sending_dialogue is not None
envelope = Envelope(
- to="_to_key",
- sender=self.my_address,
- protocol_id=GymMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
await self.gym_con.connect()
- await self.gym_con.send(envelope)
+ with patch.object(self.env, "reset") as mock:
+ await self.gym_con.send(envelope)
+ mock.assert_called()
+
+ response = await asyncio.wait_for(self.gym_con.receive(), timeout=3)
+ response_msg_orig = cast(GymMessage, response.message)
+ response_msg = copy.copy(response_msg_orig)
+ response_msg.is_incoming = True
+ response_msg.counterparty = response_msg_orig.sender
+ response_dialogue = self.dialogues.update(response_msg)
- with pytest.raises(asyncio.TimeoutError):
- await asyncio.wait_for(self.gym_con.receive(), timeout=0.5)
+ assert response_msg.performative == GymMessage.Performative.STATUS
+ assert response_msg.content == {"reset": "success"}
+ assert sending_dialogue == response_dialogue
+ return sending_dialogue
@pytest.mark.asyncio
async def test_receive_connection_error(self):
@@ -172,7 +253,7 @@ def test_gym_env_load(self):
configuration = ConnectionConfig(
connection_id=GymConnection.connection_id, env=gym_env_path
)
- identity = Identity("name", address=self.my_address)
+ identity = Identity("name", address=self.agent_address)
gym_con = GymConnection(
gym_env=None, identity=identity, configuration=configuration
)
diff --git a/tests/test_packages/test_connections/test_http_client/test_http_client.py b/tests/test_packages/test_connections/test_http_client/test_http_client.py
index 8479732f5e..f2709a08fd 100644
--- a/tests/test_packages/test_connections/test_http_client/test_http_client.py
+++ b/tests/test_packages/test_connections/test_http_client/test_http_client.py
@@ -18,6 +18,7 @@
# ------------------------------------------------------------------------------
"""Tests for the HTTP Client connection and channel."""
import asyncio
+import copy
import logging
from asyncio import CancelledError
from unittest.mock import Mock, patch
@@ -32,8 +33,10 @@
from aea.mail.base import Envelope
from packages.fetchai.connections.http_client.connection import HTTPClientConnection
+from packages.fetchai.protocols.http.dialogues import HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
+from tests.common.mocks import AnyStringWith
from tests.conftest import (
UNKNOWN_PROTOCOL_PUBLIC_ID,
get_host,
@@ -68,6 +71,7 @@ def setup(self):
self.address = get_host()
self.port = get_unused_tcp_port()
self.agent_identity = Identity("name", address="some string")
+ self.agent_address = self.agent_identity.address
configuration = ConnectionConfig(
host=self.address,
port=self.port,
@@ -77,6 +81,8 @@ def setup(self):
configuration=configuration, identity=self.agent_identity
)
self.http_client_connection.loop = asyncio.get_event_loop()
+ self.connection_address = str(HTTPClientConnection.connection_id)
+ self.http_dialogs = HttpDialogues(self.connection_address)
@pytest.mark.asyncio
async def test_initialization(self):
@@ -87,16 +93,16 @@ async def test_initialization(self):
async def test_connection(self):
"""Test the connect functionality of the http client connection."""
await self.http_client_connection.connect()
- assert self.http_client_connection.connection_status.is_connected is True
+ assert self.http_client_connection.is_connected is True
@pytest.mark.asyncio
async def test_disconnect(self):
"""Test the disconnect functionality of the http client connection."""
await self.http_client_connection.connect()
- assert self.http_client_connection.connection_status.is_connected is True
+ assert self.http_client_connection.is_connected is True
await self.http_client_connection.disconnect()
- assert self.http_client_connection.connection_status.is_connected is False
+ assert self.http_client_connection.is_connected is False
@pytest.mark.asyncio
async def test_http_send_error(self):
@@ -104,9 +110,7 @@ async def test_http_send_error(self):
await self.http_client_connection.connect()
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
- target=0,
- message_id=1,
+ dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="get",
url="bad url",
@@ -114,9 +118,12 @@ async def test_http_send_error(self):
version="",
bodyy=b"",
)
+ request_http_message.counterparty = self.connection_address
+ sending_dialogue = self.http_dialogs.update(request_http_message)
+ assert sending_dialogue is not None
request_envelope = Envelope(
- to="receiver",
- sender="sender",
+ to=self.connection_address,
+ sender=self.agent_address,
protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
message=request_http_message,
)
@@ -150,9 +157,7 @@ async def test_http_channel_send_not_connected_error(self):
async def test_send_envelope_excluded_protocol_fail(self):
"""Test send error if protocol not supported."""
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
- target=0,
- message_id=1,
+ dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="get",
url="bad url",
@@ -160,9 +165,12 @@ async def test_send_envelope_excluded_protocol_fail(self):
version="",
bodyy=b"",
)
+ request_http_message.counterparty = self.connection_address
+ sending_dialogue = self.http_dialogs.update(request_http_message)
+ assert sending_dialogue is not None
request_envelope = Envelope(
- to="receiver",
- sender="sender",
+ to=self.connection_address,
+ sender=self.agent_address,
protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
message=request_http_message,
)
@@ -198,9 +206,7 @@ async def test_channel_cancel_tasks_on_disconnect(self):
await self.http_client_connection.connect()
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
- target=0,
- message_id=1,
+ dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="get",
url="https://not-a-google.com",
@@ -208,9 +214,12 @@ async def test_channel_cancel_tasks_on_disconnect(self):
version="",
bodyy=b"",
)
+ request_http_message.counterparty = self.connection_address
+ sending_dialogue = self.http_dialogs.update(request_http_message)
+ assert sending_dialogue is not None
request_envelope = Envelope(
- to="receiver",
- sender="sender",
+ to=self.connection_address,
+ sender=self.agent_address,
protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
message=request_http_message,
)
@@ -246,9 +255,7 @@ async def test_http_send_ok(self):
await self.http_client_connection.connect()
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
- target=0,
- message_id=1,
+ dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),
performative=HttpMessage.Performative.REQUEST,
method="get",
url="https://not-a-google.com",
@@ -256,10 +263,13 @@ async def test_http_send_ok(self):
version="",
bodyy=b"",
)
+ request_http_message.counterparty = self.connection_address
+ sending_dialogue = self.http_dialogs.update(request_http_message)
+ assert sending_dialogue is not None
request_envelope = Envelope(
- to="receiver",
- sender="sender",
- protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
+ to=self.connection_address,
+ sender=self.agent_address,
+ protocol_id=request_http_message.protocol_id,
message=request_http_message,
)
@@ -283,9 +293,45 @@ async def test_http_send_ok(self):
self.http_client_connection.receive(), timeout=10
)
- assert envelope
- assert (
- envelope.message.status_code == response_mock.status
- ), envelope.message.bodyy.decode("utf-8")
-
+ assert envelope is not None and envelope.message is not None
+ response = copy.copy(envelope.message)
+ response.is_incoming = True
+ response.counterparty = envelope.message.sender
+ response_dialogue = self.http_dialogs.update(response)
+ assert response.status_code == response_mock.status, response.bodyy.decode(
+ "utf-8"
+ )
+ assert sending_dialogue == response_dialogue
await self.http_client_connection.disconnect()
+
+ @pytest.mark.asyncio
+ async def test_http_dialogue_construct_fail(self):
+ """Test dialogue not properly constructed."""
+ await self.http_client_connection.connect()
+
+ http_message = HttpMessage(
+ dialogue_reference=self.http_dialogs.new_self_initiated_dialogue_reference(),
+ performative=HttpMessage.Performative.RESPONSE,
+ status_code=500,
+ headers="",
+ status_text="",
+ bodyy=b"",
+ version="",
+ )
+ http_message.counterparty = self.connection_address
+ http_dialogue = self.http_dialogs.update(http_message)
+ http_message.sender = self.agent_address
+ assert http_dialogue is None
+ envelope = Envelope(
+ to=http_message.counterparty,
+ sender=http_message.sender,
+ protocol_id=http_message.protocol_id,
+ message=http_message,
+ )
+ with patch.object(
+ self.http_client_connection.channel.logger, "warning"
+ ) as mock_logger:
+ await self.http_client_connection.channel._http_request_task(envelope)
+ mock_logger.assert_any_call(
+ AnyStringWith("Could not create dialogue for message=")
+ )
diff --git a/tests/test_packages/test_connections/test_http_server/__init__.py b/tests/test_packages/test_connections/test_http_server/__init__.py
index 548d74c2c5..8b4d45bce1 100644
--- a/tests/test_packages/test_connections/test_http_server/__init__.py
+++ b/tests/test_packages/test_connections/test_http_server/__init__.py
@@ -16,5 +16,4 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
-
"""This module contains the tests of the HTTP Server connection implementation."""
diff --git a/tests/test_packages/test_connections/test_http_server/test_http_server.py b/tests/test_packages/test_connections/test_http_server/test_http_server.py
index d568fb66eb..c60e514d78 100644
--- a/tests/test_packages/test_connections/test_http_server/test_http_server.py
+++ b/tests/test_packages/test_connections/test_http_server/test_http_server.py
@@ -16,12 +16,15 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
"""This module contains the tests of the HTTP Server connection module."""
+
import asyncio
+import copy
import logging
import os
from traceback import print_exc
-from typing import cast
+from typing import Tuple, cast
from unittest.mock import Mock, patch
import aiohttp
@@ -38,8 +41,10 @@
HTTPServerConnection,
Response,
)
+from packages.fetchai.protocols.http.dialogues import HttpDialogue, HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
+from tests.common.mocks import RegexComparator
from tests.conftest import (
HTTP_PROTOCOL_PUBLIC_ID,
ROOT_DIR,
@@ -77,13 +82,14 @@ async def request(self, method: str, path: str, **kwargs) -> ClientResponse:
def setup(self):
"""Initialise the test case."""
self.identity = Identity("name", address="my_key")
+ self.agent_address = self.identity.address
self.host = get_host()
self.port = get_unused_tcp_port()
self.api_spec_path = os.path.join(
ROOT_DIR, "tests", "data", "petstore_sim.yaml"
)
self.connection_id = HTTPServerConnection.connection_id
- self.protocol_id = PublicId.from_str("fetchai/http:0.3.0")
+ self.protocol_id = PublicId.from_str("fetchai/http:0.4.0")
self.configuration = ConnectionConfig(
host=self.host,
@@ -97,6 +103,9 @@ def setup(self):
)
self.loop = asyncio.get_event_loop()
self.loop.run_until_complete(self.http_connection.connect())
+ self.connection_address = str(HTTPServerConnection.connection_id)
+ self._dialogues = HttpDialogues(self.connection_address)
+ self.original_timeout = self.http_connection.channel.RESPONSE_TIMEOUT
@pytest.mark.asyncio
async def test_http_connection_disconnect_channel(self):
@@ -104,24 +113,39 @@ async def test_http_connection_disconnect_channel(self):
await self.http_connection.channel.disconnect()
assert self.http_connection.channel.is_stopped
+ def _get_message_and_dialogue(
+ self, envelope: Envelope
+ ) -> Tuple[HttpMessage, HttpDialogue]:
+ message = cast(HttpMessage, envelope.message)
+ message = copy.copy(
+ message
+ ) # TODO: fix; need to copy atm to avoid overwriting "is_incoming"
+ message.is_incoming = True # TODO: fix; should be done by framework
+ message.counterparty = envelope.sender # TODO: fix; should be done by framework
+ dialogue = cast(HttpDialogue, self._dialogues.update(message))
+ assert dialogue is not None
+ return message, dialogue
+
@pytest.mark.asyncio
async def test_get_200(self):
"""Test send get request w/ 200 response."""
request_task = self.loop.create_task(self.request("get", "/pets"))
envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)
assert envelope
- incoming_message = cast(HttpMessage, envelope.message)
+ incoming_message, dialogue = self._get_message_and_dialogue(envelope)
message = HttpMessage(
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
performative=HttpMessage.Performative.RESPONSE,
- dialogue_reference=("", ""),
- target=incoming_message.message_id,
- message_id=incoming_message.message_id + 1,
version=incoming_message.version,
headers=incoming_message.headers,
+ message_id=incoming_message.message_id + 1,
+ target=incoming_message.message_id,
status_code=200,
status_text="Success",
bodyy=b"Response body",
)
+ message.counterparty = incoming_message.counterparty
+ assert dialogue.update(message)
response_envelope = Envelope(
to=envelope.sender,
sender=envelope.to,
@@ -140,15 +164,58 @@ async def test_get_200(self):
)
@pytest.mark.asyncio
- async def test_bad_performative_get_server_error(self):
+ async def test_bad_performative_get_timeout_error(self):
"""Test send get request w/ 200 response."""
+ self.http_connection.channel.RESPONSE_TIMEOUT = 3
request_task = self.loop.create_task(self.request("get", "/pets"))
- envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)
+ envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=10)
assert envelope
- incoming_message = cast(HttpMessage, envelope.message)
+ incoming_message, dialogue = self._get_message_and_dialogue(envelope)
message = HttpMessage(
performative=HttpMessage.Performative.REQUEST,
- dialogue_reference=("", ""),
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
+ target=incoming_message.message_id,
+ message_id=incoming_message.message_id + 1,
+ method="post",
+ url="/pets",
+ version=incoming_message.version,
+ headers=incoming_message.headers,
+ bodyy=b"Request body",
+ )
+ message.counterparty = incoming_message.counterparty
+ assert not dialogue.update(message)
+ response_envelope = Envelope(
+ to=envelope.sender,
+ sender=envelope.to,
+ protocol_id=envelope.protocol_id,
+ context=envelope.context,
+ message=message,
+ )
+ with patch.object(self.http_connection.logger, "warning") as mock_logger:
+ await self.http_connection.send(response_envelope)
+ mock_logger.assert_any_call(
+ f"Could not create dialogue for message={message}"
+ )
+
+ response = await asyncio.wait_for(request_task, timeout=10)
+
+ assert (
+ response.status == 408
+ and response.reason == "Request Timeout"
+ and await response.text() == ""
+ )
+
+ @pytest.mark.asyncio
+ async def test_late_message_get_timeout_error(self):
+ """Test send get request w/ 200 response."""
+ self.http_connection.channel.RESPONSE_TIMEOUT = 1
+ request_task = self.loop.create_task(self.request("get", "/pets"))
+ envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=10)
+ assert envelope
+ incoming_message, dialogue = self._get_message_and_dialogue(envelope)
+ message = HttpMessage(
+ performative=HttpMessage.Performative.RESPONSE,
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
target=incoming_message.message_id,
message_id=incoming_message.message_id + 1,
version=incoming_message.version,
@@ -157,6 +224,8 @@ async def test_bad_performative_get_server_error(self):
status_text="Success",
bodyy=b"Response body",
)
+ message.counterparty = incoming_message.counterparty
+ assert dialogue.update(message)
response_envelope = Envelope(
to=envelope.sender,
sender=envelope.to,
@@ -164,11 +233,22 @@ async def test_bad_performative_get_server_error(self):
context=envelope.context,
message=message,
)
- await self.http_connection.send(response_envelope)
+ await asyncio.sleep(1.5)
+ with patch.object(self.http_connection.logger, "warning") as mock_logger:
+ await self.http_connection.send(response_envelope)
+ mock_logger.assert_any_call(
+ RegexComparator(
+ "Dropping message=.* for incomplete_dialogue_label=.* which has timed out."
+ )
+ )
- response = await asyncio.wait_for(request_task, timeout=20,)
+ response = await asyncio.wait_for(request_task, timeout=10)
- assert response.status == 500 and await response.text() == "Server error"
+ assert (
+ response.status == 408
+ and response.reason == "Request Timeout"
+ and await response.text() == ""
+ )
@pytest.mark.asyncio
async def test_post_201(self):
@@ -176,10 +256,10 @@ async def test_post_201(self):
request_task = self.loop.create_task(self.request("post", "/pets",))
envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)
assert envelope
- incoming_message = cast(HttpMessage, envelope.message)
+ incoming_message, dialogue = self._get_message_and_dialogue(envelope)
message = HttpMessage(
performative=HttpMessage.Performative.RESPONSE,
- dialogue_reference=("", ""),
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
target=incoming_message.message_id,
message_id=incoming_message.message_id + 1,
version=incoming_message.version,
@@ -188,6 +268,8 @@ async def test_post_201(self):
status_text="Created",
bodyy=b"Response body",
)
+ message.counterparty = incoming_message.counterparty
+ assert dialogue.update(message)
response_envelope = Envelope(
to=envelope.sender,
sender=envelope.to,
@@ -195,6 +277,7 @@ async def test_post_201(self):
context=envelope.context,
message=message,
)
+
await self.http_connection.send(response_envelope)
response = await asyncio.wait_for(request_task, timeout=20,)
@@ -254,7 +337,6 @@ async def test_post_408(self):
@pytest.mark.asyncio
async def test_send_connection_drop(self):
"""Test unexpected response."""
- client_id = "to_key"
message = HttpMessage(
performative=HttpMessage.Performative.RESPONSE,
dialogue_reference=("", ""),
@@ -266,10 +348,12 @@ async def test_send_connection_drop(self):
status_text="Success",
bodyy=b"",
)
+ message.counterparty = "to_key"
+ message.sender = "from_key"
envelope = Envelope(
- to=client_id,
- sender="from_key",
- protocol_id=self.protocol_id,
+ to=message.counterparty,
+ sender=message.sender,
+ protocol_id=message.protocol_id,
message=message,
)
await self.http_connection.send(envelope)
@@ -292,7 +376,7 @@ async def test_fail_connect(self):
side_effect=Exception("expected"),
):
await self.http_connection.connect()
- assert not self.http_connection.connection_status.is_connected
+ assert not self.http_connection.is_connected
@pytest.mark.asyncio
async def test_server_error_on_send_response(self):
@@ -300,10 +384,10 @@ async def test_server_error_on_send_response(self):
request_task = self.loop.create_task(self.request("post", "/pets",))
envelope = await asyncio.wait_for(self.http_connection.receive(), timeout=20)
assert envelope
- incoming_message = cast(HttpMessage, envelope.message)
+ incoming_message, dialogue = self._get_message_and_dialogue(envelope)
message = HttpMessage(
performative=HttpMessage.Performative.RESPONSE,
- dialogue_reference=("", ""),
+ dialogue_reference=dialogue.dialogue_label.dialogue_reference,
target=incoming_message.message_id,
message_id=incoming_message.message_id + 1,
version=incoming_message.version,
@@ -312,6 +396,8 @@ async def test_server_error_on_send_response(self):
status_text="Created",
bodyy=b"Response body",
)
+ message.counterparty = incoming_message.counterparty
+ assert dialogue.update(message)
response_envelope = Envelope(
to=envelope.sender,
sender=envelope.to,
@@ -320,7 +406,7 @@ async def test_server_error_on_send_response(self):
message=message,
)
- with patch.object(Response, "from_envelope", side_effect=Exception("expected")):
+ with patch.object(Response, "from_message", side_effect=Exception("expected")):
await self.http_connection.send(response_envelope)
response = await asyncio.wait_for(request_task, timeout=20,)
@@ -358,6 +444,7 @@ async def test_send_envelope_restricted_to_protocols_fail(self):
def teardown(self):
"""Teardown the test case."""
self.loop.run_until_complete(self.http_connection.disconnect())
+ self.http_connection.channel.RESPONSE_TIMEOUT = self.original_timeout
def test_bad_api_spec():
diff --git a/tests/test_packages/test_connections/test_http_server/test_http_server_and_client.py b/tests/test_packages/test_connections/test_http_server/test_http_server_and_client.py
index 4552231406..065df4994b 100644
--- a/tests/test_packages/test_connections/test_http_server/test_http_server_and_client.py
+++ b/tests/test_packages/test_connections/test_http_server/test_http_server_and_client.py
@@ -16,6 +16,8 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
+
"""Tests for the HTTP Client and Server connections together."""
import asyncio
import logging
@@ -29,10 +31,10 @@
from packages.fetchai.connections.http_client.connection import HTTPClientConnection
from packages.fetchai.connections.http_server.connection import HTTPServerConnection
+from packages.fetchai.protocols.http.dialogues import HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
from tests.conftest import (
- HTTP_PROTOCOL_PUBLIC_ID,
get_host,
get_unused_tcp_port,
)
@@ -50,7 +52,7 @@ def setup_server(self):
self.host = get_host()
self.port = get_unused_tcp_port()
self.connection_id = HTTPServerConnection.connection_id
- self.protocol_id = PublicId.from_str("fetchai/http:0.3.0")
+ self.protocol_id = PublicId.from_str("fetchai/http:0.4.0")
self.configuration = ConnectionConfig(
host=self.host,
@@ -78,6 +80,7 @@ def setup_client(self):
)
self.client.loop = asyncio.get_event_loop()
self.loop.run_until_complete(self.client.connect())
+ self._client_dialogues = HttpDialogues("some_addr")
def setup(self):
"""Set up test case."""
@@ -89,7 +92,7 @@ def _make_request(
) -> Envelope:
"""Make request envelope."""
request_http_message = HttpMessage(
- dialogue_reference=("", ""),
+ dialogue_reference=self._client_dialogues.new_self_initiated_dialogue_reference(),
target=0,
message_id=1,
performative=HttpMessage.Performative.REQUEST,
@@ -99,10 +102,12 @@ def _make_request(
version="",
bodyy=b"",
)
+ request_http_message.counterparty = "receiver"
+ request_http_message.sender = "sender"
request_envelope = Envelope(
- to="receiver",
- sender="sender",
- protocol_id=HTTP_PROTOCOL_PUBLIC_ID,
+ to=request_http_message.counterparty,
+ sender=request_http_message.sender,
+ protocol_id=request_http_message.protocol_id,
message=request_http_message,
)
return request_envelope
@@ -114,7 +119,7 @@ def _make_response(
incoming_message = cast(HttpMessage, request_envelope.message)
message = HttpMessage(
performative=HttpMessage.Performative.RESPONSE,
- dialogue_reference=("", ""),
+ dialogue_reference=("1", ""),
target=incoming_message.message_id,
message_id=incoming_message.message_id + 1,
version=incoming_message.version,
@@ -123,10 +128,12 @@ def _make_response(
status_text=status_text,
bodyy=incoming_message.bodyy,
)
+ message.counterparty = incoming_message.counterparty
+ message.sender = request_envelope.to
response_envelope = Envelope(
- to=request_envelope.sender,
- sender=request_envelope.to,
- protocol_id=request_envelope.protocol_id,
+ to=message.counterparty,
+ sender=message.sender,
+ protocol_id=message.protocol_id,
context=request_envelope.context,
message=message,
)
diff --git a/tests/test_packages/test_connections/test_ledger/test_contract_api.py b/tests/test_packages/test_connections/test_ledger/test_contract_api.py
index 8eb6148b07..f42b1ab8c2 100644
--- a/tests/test_packages/test_connections/test_ledger/test_contract_api.py
+++ b/tests/test_packages/test_connections/test_ledger/test_contract_api.py
@@ -16,44 +16,28 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
"""This module contains the tests of the ledger API connection for the contract APIs."""
import asyncio
-from pathlib import Path
+import copy
+import logging
+import unittest.mock
from typing import cast
import pytest
-from aea.configurations.constants import DEFAULT_LEDGER
-from aea.connections.base import Connection, ConnectionStatus
-from aea.crypto.registries import make_crypto
-from aea.crypto.wallet import CryptoStore
+
from aea.helpers.transaction.base import RawMessage, RawTransaction, State
-from aea.identity.base import Identity
from aea.mail.base import Envelope
+from aea.multiplexer import ConnectionStatus
from packages.fetchai.connections.ledger.contract_dispatcher import (
- ContractApiDialogues,
ContractApiRequestDispatcher,
)
-from packages.fetchai.protocols.contract_api import ContractApiMessage
-
-from tests.conftest import ETHEREUM, ETHEREUM_ADDRESS_ONE, ROOT_DIR
+from packages.fetchai.protocols.contract_api.dialogues import ContractApiDialogues
+from packages.fetchai.protocols.contract_api.message import ContractApiMessage
-
-@pytest.fixture()
-async def ledger_apis_connection(request):
- """Create connection."""
- crypto = make_crypto(DEFAULT_LEDGER)
- identity = Identity("name", crypto.address)
- crypto_store = CryptoStore()
- directory = Path(ROOT_DIR, "packages", "fetchai", "connections", "ledger")
- connection = Connection.from_dir(
- directory, identity=identity, crypto_store=crypto_store
- )
- connection = cast(Connection, connection)
- await connection.connect()
- yield connection
- await connection.disconnect()
+from tests.conftest import ETHEREUM, ETHEREUM_ADDRESS_ONE
@pytest.mark.integration
@@ -61,13 +45,14 @@ async def ledger_apis_connection(request):
@pytest.mark.asyncio
async def test_erc1155_get_deploy_transaction(erc1155_contract, ledger_apis_connection):
"""Test get state with contract erc1155."""
+ # TODO to fix
address = ETHEREUM_ADDRESS_ONE
- contract_api_dialogues = ContractApiDialogues()
+ contract_api_dialogues = ContractApiDialogues("agent_address")
request = ContractApiMessage(
performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
callable="get_deploy_transaction",
kwargs=ContractApiMessage.Kwargs({"deployer_address": address}),
)
@@ -87,7 +72,10 @@ async def test_erc1155_get_deploy_transaction(erc1155_contract, ledger_apis_conn
assert response is not None
assert type(response.message) == ContractApiMessage
- response_message = cast(ContractApiMessage, response.message)
+ response_message_orig = cast(ContractApiMessage, response.message)
+ response_message = copy.copy(response_message_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_message_orig.sender
assert (
response_message.performative == ContractApiMessage.Performative.RAW_TRANSACTION
), "Error: {}".format(response_message.message)
@@ -106,12 +94,12 @@ async def test_erc1155_get_raw_transaction(erc1155_contract, ledger_apis_connect
"""Test get state with contract erc1155."""
address = ETHEREUM_ADDRESS_ONE
contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
- contract_api_dialogues = ContractApiDialogues()
+ contract_api_dialogues = ContractApiDialogues("agent_address")
request = ContractApiMessage(
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=contract_address,
callable="get_create_batch_transaction",
kwargs=ContractApiMessage.Kwargs(
@@ -134,10 +122,14 @@ async def test_erc1155_get_raw_transaction(erc1155_contract, ledger_apis_connect
assert response is not None
assert type(response.message) == ContractApiMessage
- response_message = cast(ContractApiMessage, response.message)
+ response_message_orig = cast(ContractApiMessage, response.message)
+ response_message = copy.copy(response_message_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_message_orig.sender
assert (
response_message.performative == ContractApiMessage.Performative.RAW_TRANSACTION
), "Error: {}".format(response_message.message)
+
response_dialogue = contract_api_dialogues.update(response_message)
assert response_dialogue == contract_api_dialogue
assert type(response_message.raw_transaction) == RawTransaction
@@ -153,12 +145,12 @@ async def test_erc1155_get_raw_message(erc1155_contract, ledger_apis_connection)
"""Test get state with contract erc1155."""
address = ETHEREUM_ADDRESS_ONE
contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
- contract_api_dialogues = ContractApiDialogues()
+ contract_api_dialogues = ContractApiDialogues("agent_address")
request = ContractApiMessage(
performative=ContractApiMessage.Performative.GET_RAW_MESSAGE,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=contract_address,
callable="get_hash_single",
kwargs=ContractApiMessage.Kwargs(
@@ -189,7 +181,10 @@ async def test_erc1155_get_raw_message(erc1155_contract, ledger_apis_connection)
assert response is not None
assert type(response.message) == ContractApiMessage
- response_message = cast(ContractApiMessage, response.message)
+ response_message_orig = cast(ContractApiMessage, response.message)
+ response_message = copy.copy(response_message_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_message_orig.sender
assert (
response_message.performative == ContractApiMessage.Performative.RAW_MESSAGE
), "Error: {}".format(response_message.message)
@@ -207,13 +202,13 @@ async def test_erc1155_get_state(erc1155_contract, ledger_apis_connection):
"""Test get state with contract erc1155."""
address = ETHEREUM_ADDRESS_ONE
contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
- contract_api_dialogues = ContractApiDialogues()
+ contract_api_dialogues = ContractApiDialogues("agent_address")
token_id = 1
request = ContractApiMessage(
performative=ContractApiMessage.Performative.GET_STATE,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address=contract_address,
callable="get_balance",
kwargs=ContractApiMessage.Kwargs(
@@ -236,7 +231,10 @@ async def test_erc1155_get_state(erc1155_contract, ledger_apis_connection):
assert response is not None
assert type(response.message) == ContractApiMessage
- response_message = cast(ContractApiMessage, response.message)
+ response_message_orig = cast(ContractApiMessage, response.message)
+ response_message = copy.copy(response_message_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_message_orig.sender
assert (
response_message.performative == ContractApiMessage.Performative.STATE
), "Error: {}".format(response_message.message)
@@ -256,12 +254,12 @@ async def test_run_async():
def _raise():
raise Exception("Expected")
- contract_api_dialogues = ContractApiDialogues()
+ contract_api_dialogues = ContractApiDialogues("agent_address")
message = ContractApiMessage(
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
- contract_id="fetchai/erc1155:0.6.0",
+ contract_id="fetchai/erc1155:0.7.0",
contract_address="test addr",
callable="get_create_batch_transaction",
kwargs=ContractApiMessage.Kwargs(
@@ -287,3 +285,243 @@ async def test_get_handler():
ContractApiRequestDispatcher(ConnectionStatus()).get_handler(
ContractApiMessage.Performative.ERROR
)
+
+
+@pytest.mark.integration
+@pytest.mark.ledger
+@pytest.mark.asyncio
+async def test_callable_wrong_number_of_arguments_api_and_contract_address(
+ erc1155_contract, ledger_apis_connection
+):
+ """
+ Test a contract callable with wrong number of arguments.
+
+ Test the case of either GET_STATE, GET_RAW_MESSAGE or GET_RAW_TRANSACTION.
+ """
+ address = ETHEREUM_ADDRESS_ONE
+ contract_api_dialogues = ContractApiDialogues("agent_address")
+ token_id = 1
+ contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
+ request = ContractApiMessage(
+ performative=ContractApiMessage.Performative.GET_STATE,
+ dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ ledger_id=ETHEREUM,
+ contract_id="fetchai/erc1155:0.7.0",
+ contract_address=contract_address,
+ callable="get_balance",
+ kwargs=ContractApiMessage.Kwargs(
+ {"agent_address": address, "token_id": token_id}
+ ),
+ )
+ request.counterparty = str(ledger_apis_connection.connection_id)
+ contract_api_dialogue = contract_api_dialogues.update(request)
+ assert contract_api_dialogue is not None
+ envelope = Envelope(
+ to=str(ledger_apis_connection.connection_id),
+ sender=address,
+ protocol_id=request.protocol_id,
+ message=request,
+ )
+
+ with unittest.mock.patch(
+ "inspect.getfullargspec", return_value=unittest.mock.MagicMock(args=[None])
+ ):
+ with unittest.mock.patch.object(
+ ledger_apis_connection._logger, "error"
+ ) as mock_logger:
+ await ledger_apis_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ response = await ledger_apis_connection.receive()
+ mock_logger.assert_any_call(
+ "Expected two or more positional arguments, got 1"
+ )
+ assert (
+ response.message.performative == ContractApiMessage.Performative.ERROR
+ )
+ assert (
+ response.message.message
+ == "Expected two or more positional arguments, got 1"
+ )
+
+
+@pytest.mark.integration
+@pytest.mark.ledger
+@pytest.mark.asyncio
+async def test_callable_wrong_number_of_arguments_apis(
+ erc1155_contract, ledger_apis_connection
+):
+ """
+ Test a contract callable with wrong number of arguments.
+
+ Test the case of either GET_DEPLOY_TRANSACTION.
+ """
+ address = ETHEREUM_ADDRESS_ONE
+ contract_api_dialogues = ContractApiDialogues("agent_address")
+ request = ContractApiMessage(
+ performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
+ dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ ledger_id=ETHEREUM,
+ contract_id="fetchai/erc1155:0.7.0",
+ callable="get_deploy_transaction",
+ kwargs=ContractApiMessage.Kwargs({}),
+ )
+ request.counterparty = str(ledger_apis_connection.connection_id)
+ contract_api_dialogue = contract_api_dialogues.update(request)
+ assert contract_api_dialogue is not None
+ envelope = Envelope(
+ to=str(ledger_apis_connection.connection_id),
+ sender=address,
+ protocol_id=request.protocol_id,
+ message=request,
+ )
+
+ with unittest.mock.patch(
+ "inspect.getfullargspec", return_value=unittest.mock.MagicMock(args=[])
+ ):
+ with unittest.mock.patch.object(
+ ledger_apis_connection._contract_dispatcher, "_call_stub", return_value=None
+ ):
+ with unittest.mock.patch.object(
+ ledger_apis_connection._contract_dispatcher.logger, "error"
+ ) as mock_logger:
+ await ledger_apis_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ response = await ledger_apis_connection.receive()
+ mock_logger.assert_any_call(
+ "Expected one or more positional arguments, got 0"
+ )
+ assert (
+ response.message.performative
+ == ContractApiMessage.Performative.ERROR
+ )
+ assert (
+ response.message.message
+ == "Expected one or more positional arguments, got 0"
+ )
+
+
+@pytest.mark.integration
+@pytest.mark.ledger
+@pytest.mark.asyncio
+async def test_callable_wrong_number_of_arguments_apis_method_call(
+ erc1155_contract, ledger_apis_connection, caplog
+):
+ """
+ Test a contract callable with wrong number of arguments.
+
+ Test the case of either GET_DEPLOY_TRANSACTION.
+ """
+ address = ETHEREUM_ADDRESS_ONE
+ contract_api_dialogues = ContractApiDialogues("agent_address")
+ request = ContractApiMessage(
+ performative=ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION,
+ dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ ledger_id=ETHEREUM,
+ contract_id="fetchai/erc1155:0.7.0",
+ callable="get_deploy_transaction",
+ kwargs=ContractApiMessage.Kwargs({}),
+ )
+ request.counterparty = str(ledger_apis_connection.connection_id)
+ contract_api_dialogue = contract_api_dialogues.update(request)
+ assert contract_api_dialogue is not None
+ envelope = Envelope(
+ to=str(ledger_apis_connection.connection_id),
+ sender=address,
+ protocol_id=request.protocol_id,
+ message=request,
+ )
+
+ with unittest.mock.patch.object(
+ ledger_apis_connection._contract_dispatcher, "_call_stub", return_value=None
+ ):
+ with caplog.at_level(logging.DEBUG, "aea.packages.fetchai.connections.ledger"):
+ await ledger_apis_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ assert (
+ "An error occurred while processing the contract api request: 'get_deploy_transaction() missing 1 required positional argument: 'deployer_address''."
+ in caplog.text
+ )
+
+
+@pytest.mark.integration
+@pytest.mark.ledger
+@pytest.mark.asyncio
+async def test_callable_generic_error(erc1155_contract, ledger_apis_connection):
+ """Test error messages when an exception is raised while processing the request."""
+ address = ETHEREUM_ADDRESS_ONE
+ contract_api_dialogues = ContractApiDialogues("agent_address")
+ token_id = 1
+ contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
+ request = ContractApiMessage(
+ performative=ContractApiMessage.Performative.GET_STATE,
+ dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ ledger_id=ETHEREUM,
+ contract_id="fetchai/erc1155:0.7.0",
+ contract_address=contract_address,
+ callable="get_balance",
+ kwargs=ContractApiMessage.Kwargs(
+ {"agent_address": address, "token_id": token_id}
+ ),
+ )
+ request.counterparty = str(ledger_apis_connection.connection_id)
+ contract_api_dialogue = contract_api_dialogues.update(request)
+ assert contract_api_dialogue is not None
+ envelope = Envelope(
+ to=str(ledger_apis_connection.connection_id),
+ sender=address,
+ protocol_id=request.protocol_id,
+ message=request,
+ )
+
+ with unittest.mock.patch(
+ "inspect.getfullargspec", side_effect=Exception("Generic error")
+ ):
+ with unittest.mock.patch.object(
+ ledger_apis_connection._logger, "error"
+ ) as mock_logger:
+ await ledger_apis_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ response = await ledger_apis_connection.receive()
+ mock_logger.assert_any_call(
+ "An error occurred while processing the contract api request: 'Generic error'."
+ )
+ assert (
+ response.message.performative == ContractApiMessage.Performative.ERROR
+ )
+ assert response.message.message == "Generic error"
+
+
+@pytest.mark.integration
+@pytest.mark.ledger
+@pytest.mark.asyncio
+async def test_callable_cannot_find(erc1155_contract, ledger_apis_connection, caplog):
+ """Test error messages when an exception is raised while processing the request."""
+ address = ETHEREUM_ADDRESS_ONE
+ contract_api_dialogues = ContractApiDialogues("agent_address")
+ token_id = 1
+ contract_address = "0x250A2aeb3eB84782e83365b4c42dbE3CDA9920e4"
+ request = ContractApiMessage(
+ performative=ContractApiMessage.Performative.GET_STATE,
+ dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ ledger_id=ETHEREUM,
+ contract_id="fetchai/erc1155:0.7.0",
+ contract_address=contract_address,
+ callable="unknown_callable",
+ kwargs=ContractApiMessage.Kwargs(
+ {"agent_address": address, "token_id": token_id}
+ ),
+ )
+ request.counterparty = str(ledger_apis_connection.connection_id)
+ contract_api_dialogue = contract_api_dialogues.update(request)
+ assert contract_api_dialogue is not None
+ envelope = Envelope(
+ to=str(ledger_apis_connection.connection_id),
+ sender=address,
+ protocol_id=request.protocol_id,
+ message=request,
+ )
+
+ with caplog.at_level(logging.DEBUG, "aea.packages.fetchai.connections.ledger"):
+ await ledger_apis_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ assert f"Cannot find {request.callable} in contract" in caplog.text
diff --git a/tests/test_packages/test_connections/test_ledger/test_ledger_api.py b/tests/test_packages/test_connections/test_ledger/test_ledger_api.py
index f67be8f881..bf11f6168d 100644
--- a/tests/test_packages/test_connections/test_ledger/test_ledger_api.py
+++ b/tests/test_packages/test_connections/test_ledger/test_ledger_api.py
@@ -16,20 +16,22 @@
# limitations under the License.
#
# ------------------------------------------------------------------------------
+
+
"""This module contains the tests of the ledger API connection module."""
import asyncio
+import copy
import logging
-from pathlib import Path
from typing import cast
from unittest.mock import Mock, patch
import pytest
from aea.configurations.base import ProtocolId
-from aea.configurations.constants import DEFAULT_LEDGER
-from aea.connections.base import Connection, ConnectionStatus
+from aea.connections.base import Connection, ConnectionStates
+from aea.crypto.ledger_apis import LedgerApis
from aea.crypto.registries import make_crypto, make_ledger_api
-from aea.crypto.wallet import CryptoStore
+from aea.helpers.async_utils import AsyncState
from aea.helpers.transaction.base import (
RawTransaction,
SignedTransaction,
@@ -37,18 +39,15 @@
TransactionDigest,
TransactionReceipt,
)
-from aea.identity.base import Identity
from aea.mail.base import Envelope
from packages.fetchai.connections.ledger.connection import LedgerConnection
-from packages.fetchai.connections.ledger.contract_dispatcher import ContractApiDialogues
from packages.fetchai.connections.ledger.ledger_dispatcher import (
- LedgerApiDialogues,
LedgerApiRequestDispatcher,
)
+from packages.fetchai.protocols.ledger_api.dialogues import LedgerApiDialogues
from packages.fetchai.protocols.ledger_api.message import LedgerApiMessage
-
from tests.conftest import (
COSMOS,
COSMOS_ADDRESS_ONE,
@@ -60,7 +59,6 @@
FETCHAI,
FETCHAI_ADDRESS_ONE,
FETCHAI_TESTNET_CONFIG,
- ROOT_DIR,
)
logger = logging.getLogger(__name__)
@@ -76,22 +74,6 @@
)
-@pytest.fixture()
-async def ledger_apis_connection(request):
- """Make a connection."""
- crypto = make_crypto(DEFAULT_LEDGER)
- identity = Identity("name", crypto.address)
- crypto_store = CryptoStore()
- directory = Path(ROOT_DIR, "packages", "fetchai", "connections", "ledger")
- connection = Connection.from_dir(
- directory, identity=identity, crypto_store=crypto_store
- )
- connection = cast(Connection, connection)
- await connection.connect()
- yield connection
- await connection.disconnect()
-
-
@pytest.mark.integration
@pytest.mark.ledger
@pytest.mark.asyncio
@@ -102,7 +84,7 @@ async def test_get_balance(
"""Test get balance."""
import aea # noqa # to load registries
- ledger_api_dialogues = LedgerApiDialogues()
+ ledger_api_dialogues = LedgerApiDialogues(address)
request = LedgerApiMessage(
performative=LedgerApiMessage.Performative.GET_BALANCE,
dialogue_reference=ledger_api_dialogues.new_self_initiated_dialogue_reference(),
@@ -126,7 +108,10 @@ async def test_get_balance(
assert response is not None
assert type(response.message) == LedgerApiMessage
- response_msg = cast(LedgerApiMessage, response.message)
+ response_msg_orig = cast(LedgerApiMessage, response.message)
+ response_msg = copy.copy(response_msg_orig)
+ response_msg.is_incoming = True
+ response_msg.counterparty = response_msg_orig.sender
response_dialogue = ledger_api_dialogues.update(response_msg)
assert response_dialogue == ledger_api_dialogue
assert response_msg.performative == LedgerApiMessage.Performative.BALANCE
@@ -144,7 +129,7 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
crypto1 = make_crypto(ETHEREUM, private_key_path=ETHEREUM_PRIVATE_KEY_PATH)
crypto2 = make_crypto(ETHEREUM)
- ledger_api_dialogues = LedgerApiDialogues()
+ ledger_api_dialogues = LedgerApiDialogues(crypto1.address)
amount = 40000
fee = 30000
@@ -179,7 +164,10 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
assert response is not None
assert type(response.message) == LedgerApiMessage
- response_message = cast(LedgerApiMessage, response.message)
+ response_msg_orig = cast(LedgerApiMessage, response.message)
+ response_message = copy.copy(response_msg_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_msg_orig.sender
assert (
response_message.performative == LedgerApiMessage.Performative.RAW_TRANSACTION
)
@@ -188,18 +176,11 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
assert type(response_message.raw_transaction) == RawTransaction
assert response_message.raw_transaction.ledger_id == request.terms.ledger_id
- # raw_tx = api.get_transfer_transaction(
- # sender_address=crypto1.address,
- # destination_address=crypto2.address,
- # amount=amount,
- # tx_fee=fee,
- # tx_nonce="",
- # chain_id=3,
- # )
-
signed_transaction = crypto1.sign_transaction(response_message.raw_transaction.body)
request = LedgerApiMessage(
performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION,
+ message_id=response_message.message_id + 1,
+ target=response_message.message_id,
dialogue_reference=ledger_api_dialogue.dialogue_label.dialogue_reference,
signed_transaction=SignedTransaction(ETHEREUM, signed_transaction),
)
@@ -217,7 +198,10 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
assert response is not None
assert type(response.message) == LedgerApiMessage
- response_message = cast(LedgerApiMessage, response.message)
+ response_msg_orig = cast(LedgerApiMessage, response.message)
+ response_message = copy.copy(response_msg_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_msg_orig.sender
assert (
response_message.performative != LedgerApiMessage.Performative.ERROR
), f"Received error: {response_message.message}"
@@ -238,6 +222,8 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
request = LedgerApiMessage(
performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,
dialogue_reference=ledger_api_dialogue.dialogue_label.dialogue_reference,
+ message_id=response_message.message_id + 1,
+ target=response_message.message_id,
transaction_digest=response_message.transaction_digest,
)
request.counterparty = str(ledger_apis_connection.connection_id)
@@ -254,7 +240,10 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
assert response is not None
assert type(response.message) == LedgerApiMessage
- response_message = cast(LedgerApiMessage, response.message)
+ response_msg_orig = cast(LedgerApiMessage, response.message)
+ response_message = copy.copy(response_msg_orig)
+ response_message.is_incoming = True
+ response_message.counterparty = response_msg_orig.sender
assert (
response_message.performative
== LedgerApiMessage.Performative.TRANSACTION_RECEIPT
@@ -268,18 +257,10 @@ async def test_send_signed_transaction_ethereum(ledger_apis_connection: Connecti
response_message.transaction_receipt.ledger_id
== request.transaction_digest.ledger_id
)
-
- # # check that the transaction is settled (to update nonce!)
- # is_settled = False
- # attempts = 0
- # while not is_settled and attempts < 60:
- # attempts += 1
- # tx_receipt = api.get_transaction_receipt(
- # response_message.transaction_digest.body
- # )
- # is_settled = api.is_transaction_settled(tx_receipt)
- # await asyncio.sleep(4.0)
- # assert is_settled, "Transaction not settled."
+ assert LedgerApis.is_transaction_settled(
+ response_message.transaction_receipt.ledger_id,
+ response_message.transaction_receipt.receipt,
+ ), "Transaction not settled."
@pytest.mark.asyncio
@@ -307,17 +288,16 @@ async def test_new_message_wait_flag(ledger_apis_connection: LedgerConnection):
@pytest.mark.asyncio
async def test_no_balance():
"""Test no balance."""
- dispatcher = LedgerApiRequestDispatcher(ConnectionStatus())
+ dispatcher = LedgerApiRequestDispatcher(AsyncState())
mock_api = Mock()
- contract_api_dialogues = ContractApiDialogues()
message = LedgerApiMessage(
performative=LedgerApiMessage.Performative.GET_BALANCE,
- dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),
ledger_id=ETHEREUM,
address="test",
)
message.counterparty = "test"
- dialogue = contract_api_dialogues.update(message)
+ dialogue = dispatcher.dialogues.update(message)
mock_api.get_balance.return_value = None
msg = dispatcher.get_balance(mock_api, message, dialogue)
@@ -327,12 +307,11 @@ async def test_no_balance():
@pytest.mark.asyncio
async def test_no_raw_tx():
"""Test no raw tx returned."""
- dispatcher = LedgerApiRequestDispatcher(ConnectionStatus())
+ dispatcher = LedgerApiRequestDispatcher(AsyncState())
mock_api = Mock()
- contract_api_dialogues = ContractApiDialogues()
message = LedgerApiMessage(
performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION,
- dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),
terms=Terms(
ledger_id=ETHEREUM,
sender_address="1111",
@@ -346,7 +325,7 @@ async def test_no_raw_tx():
),
)
message.counterparty = "test"
- dialogue = contract_api_dialogues.update(message)
+ dialogue = dispatcher.dialogues.update(message)
mock_api.get_transfer_transaction.return_value = None
msg = dispatcher.get_raw_transaction(mock_api, message, dialogue)
@@ -356,17 +335,16 @@ async def test_no_raw_tx():
@pytest.mark.asyncio
async def test_attempts_get_transaction_receipt():
"""Test retry and sleep."""
- dispatcher = LedgerApiRequestDispatcher(ConnectionStatus())
- dispatcher.connection_status.is_connected = True
+ dispatcher = LedgerApiRequestDispatcher(AsyncState(ConnectionStates.connected))
mock_api = Mock()
- contract_api_dialogues = ContractApiDialogues()
message = LedgerApiMessage(
performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT,
- dialogue_reference=contract_api_dialogues.new_self_initiated_dialogue_reference(),
+ dialogue_reference=dispatcher.dialogues.new_self_initiated_dialogue_reference(),
transaction_digest=TransactionDigest("asdad", "sdfdsf"),
)
message.counterparty = "test"
- dialogue = contract_api_dialogues.update(message)
+ dialogue = dispatcher.dialogues.update(message)
+ assert dialogue is not None
mock_api.get_transaction.return_value = None
mock_api.is_transaction_settled.return_value = True
with patch.object(dispatcher, "MAX_ATTEMPTS", 2):
diff --git a/tests/test_packages/test_connections/test_local/test_search_services.py b/tests/test_packages/test_connections/test_local/test_search_services.py
index d288b21773..539a0ea8d2 100644
--- a/tests/test_packages/test_connections/test_local/test_search_services.py
+++ b/tests/test_packages/test_connections/test_local/test_search_services.py
@@ -17,7 +17,11 @@
#
# ------------------------------------------------------------------------------
"""This module contains the tests for the search feature of the local OEF node."""
+import asyncio
+import copy
import time
+import unittest.mock
+from typing import Optional, cast
import pytest
@@ -33,13 +37,74 @@
from aea.multiplexer import InBox, Multiplexer
from aea.protocols.default.message import DefaultMessage
-from packages.fetchai.connections.local.connection import LocalNode
+from packages.fetchai.connections.local.connection import LocalNode, OEFLocalConnection
+from packages.fetchai.protocols.fipa.dialogues import FipaDialogue, FipaDialogues
from packages.fetchai.protocols.fipa.message import FipaMessage
+from packages.fetchai.protocols.oef_search.dialogues import (
+ OefSearchDialogue,
+ OefSearchDialogues,
+)
from packages.fetchai.protocols.oef_search.message import OefSearchMessage
+from tests.common.mocks import AnyStringWith
from tests.conftest import MAX_FLAKY_RERUNS, _make_local_connection
-DEFAULT_OEF = "default_oef"
+
+class TestNoValidDialogue:
+ """Test that the search request returns an empty search result."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set up the test."""
+ cls.node = LocalNode()
+ cls.node.start()
+
+ cls.address_1 = "address_1"
+ cls.connection = _make_local_connection(cls.address_1, cls.node,)
+ cls.multiplexer = Multiplexer([cls.connection])
+
+ cls.multiplexer.connect()
+ cls.dialogues = OefSearchDialogues(cls.address_1)
+
+ @pytest.mark.asyncio
+ async def test_wrong_dialogue(self):
+ """Test that at the beginning, the search request returns an empty search result."""
+ query = Query(
+ constraints=[Constraint("foo", ConstraintType("==", 1))], model=None
+ )
+
+ # build and send the request
+ search_services_request = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ message_id=2,
+ target=1,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
+ query=query,
+ )
+ search_services_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], self.dialogues.update(search_services_request)
+ )
+ assert sending_dialogue is None
+ search_services_request.sender = self.address_1
+ envelope = Envelope(
+ to=search_services_request.counterparty,
+ sender=search_services_request.sender,
+ protocol_id=search_services_request.protocol_id,
+ message=search_services_request,
+ )
+ self.multiplexer.put(envelope)
+ with unittest.mock.patch.object(self.node.logger, "warning") as mock_logger:
+ await asyncio.sleep(0.1)
+ mock_logger.assert_any_call(
+ AnyStringWith("Could not create dialogue for message=")
+ )
+
+ @classmethod
+ def teardown_class(cls):
+ """Teardown the test."""
+ cls.multiplexer.disconnect()
+ cls.node.stop()
class TestEmptySearch:
@@ -57,22 +122,27 @@ def setup_class(cls):
)
cls.multiplexer.connect()
+ cls.dialogues = OefSearchDialogues(cls.address_1)
def test_empty_search_result(self):
"""Test that at the beginning, the search request returns an empty search result."""
- request_id = 1
query = Query(constraints=[], model=None)
# build and send the request
search_services_request = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=query,
)
+ search_services_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], self.dialogues.update(search_services_request)
+ )
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=search_services_request.counterparty,
+ sender=search_services_request.sender,
+ protocol_id=search_services_request.protocol_id,
message=search_services_request,
)
self.multiplexer.put(envelope)
@@ -80,9 +150,12 @@ def test_empty_search_result(self):
# check the result
response_envelope = self.multiplexer.get(block=True, timeout=2.0)
assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.to == self.address_1
- assert response_envelope.sender == DEFAULT_OEF
- search_result = response_envelope.message
+ search_result_orig = cast(OefSearchMessage, response_envelope.message)
+ search_result = copy.copy(search_result_orig)
+ search_result.is_incoming = True
+ search_result.counterparty = search_result_orig.sender
+ response_dialogue = self.dialogues.update(search_result)
+ assert response_dialogue == sending_dialogue
assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
assert search_result.agents == ()
@@ -110,7 +183,7 @@ def setup_class(cls):
cls.multiplexer.connect()
# register a service.
- request_id = 1
+ cls.dialogues = OefSearchDialogues(cls.address_1)
cls.data_model = DataModel(
"foobar",
attributes=[Attribute("foo", int, True), Attribute("bar", str, True)],
@@ -120,13 +193,18 @@ def setup_class(cls):
)
register_service_request = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=cls.dialogues.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ register_service_request.counterparty = str(OEFLocalConnection.connection_id)
+ cls.sending_dialogue = cast(
+ Optional[OefSearchDialogue], cls.dialogues.update(register_service_request)
+ )
+ assert cls.sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=cls.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=register_service_request.counterparty,
+ sender=register_service_request.sender,
+ protocol_id=register_service_request.protocol_id,
message=register_service_request,
)
cls.multiplexer.put(envelope)
@@ -136,19 +214,23 @@ def setup_class(cls):
) # TODO: check reasons!. quite unstable test
def test_not_empty_search_result(self):
"""Test that the search result contains one entry after a successful registration."""
- request_id = 1
query = Query(constraints=[], model=self.data_model)
# build and send the request
search_services_request = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=query,
)
+ search_services_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], self.dialogues.update(search_services_request)
+ )
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=search_services_request.counterparty,
+ sender=search_services_request.sender,
+ protocol_id=search_services_request.protocol_id,
message=search_services_request,
)
self.multiplexer.put(envelope)
@@ -156,9 +238,12 @@ def test_not_empty_search_result(self):
# check the result
response_envelope = self.multiplexer.get(block=True, timeout=2.0)
assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.to == self.address_1
- assert response_envelope.sender == DEFAULT_OEF
- search_result = response_envelope.message
+ search_result_orig = cast(OefSearchMessage, response_envelope.message)
+ search_result = copy.copy(search_result_orig)
+ search_result.is_incoming = True
+ search_result.counterparty = search_result_orig.sender
+ response_dialogue = self.dialogues.update(search_result)
+ assert response_dialogue == sending_dialogue
assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
assert search_result.agents == (self.address_1,)
@@ -188,6 +273,7 @@ def setup_class(cls):
)
cls.multiplexer1.connect()
cls.multiplexer2.connect()
+ cls.dialogues = OefSearchDialogues(cls.address_1)
def test_unregister_service_result(self):
"""Test that at the beginning, the search request returns an empty search result."""
@@ -200,13 +286,16 @@ def test_unregister_service_result(self):
)
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
@@ -214,19 +303,26 @@ def test_unregister_service_result(self):
# check the result
response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.sender == DEFAULT_OEF
- result = response_envelope.message
- assert result.performative == OefSearchMessage.Performative.OEF_ERROR
+ response_orig = cast(OefSearchMessage, response_envelope.message)
+ response = copy.copy(response_orig)
+ response.is_incoming = True
+ response.counterparty = response_orig.sender
+ response_dialogue = self.dialogues.update(response)
+ assert response_dialogue == sending_dialogue
+ assert response.performative == OefSearchMessage.Performative.OEF_ERROR
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
@@ -234,34 +330,43 @@ def test_unregister_service_result(self):
# Search for the registered service
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=Query([Constraint("foo", ConstraintType("==", 1))]),
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
# check the result
response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
- assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.sender == DEFAULT_OEF
- result = response_envelope.message
- assert result.performative == OefSearchMessage.Performative.SEARCH_RESULT
- assert len(result.agents) == 1
+ search_result_orig = cast(OefSearchMessage, response_envelope.message)
+ search_result = copy.copy(search_result_orig)
+ search_result.is_incoming = True
+ search_result.counterparty = search_result_orig.sender
+ response_dialogue = self.dialogues.update(search_result)
+ assert response_dialogue == sending_dialogue
+ assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
+ assert len(search_result.agents) == 1
# unregister the service
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
@@ -270,23 +375,29 @@ def test_unregister_service_result(self):
# Search for the register agent
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=Query([Constraint("foo", ConstraintType("==", 1))]),
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
# check the result
response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
- assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.sender == DEFAULT_OEF
- result = response_envelope.message
- assert result.performative == OefSearchMessage.Performative.SEARCH_RESULT
- assert result.agents == ()
+ search_result_orig = cast(OefSearchMessage, response_envelope.message)
+ search_result = copy.copy(search_result_orig)
+ search_result.is_incoming = True
+ search_result.counterparty = search_result_orig.sender
+ response_dialogue = self.dialogues.update(search_result)
+ assert response_dialogue == sending_dialogue
+ assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
+ assert search_result.agents == ()
@classmethod
def teardown_class(cls):
@@ -309,21 +420,23 @@ def setup_class(cls):
cls.multiplexer1 = Multiplexer(
[_make_local_connection(cls.address_1, cls.node,)]
)
+ cls.dialogues = FipaDialogues(cls.address_1)
@pytest.mark.asyncio
async def test_messages(self):
"""Test that at the beginning, the search request returns an empty search result."""
msg = FipaMessage(
performative=FipaMessage.Performative.CFP,
- dialogue_reference=(str(0), ""),
- message_id=1,
- target=0,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=Query([Constraint("something", ConstraintType(">", 1))]),
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[FipaDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=FipaMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
with pytest.raises(AEAConnectionError):
@@ -332,15 +445,16 @@ async def test_messages(self):
self.multiplexer1.connect()
msg = FipaMessage(
performative=FipaMessage.Performative.CFP,
- dialogue_reference=(str(0), str(1)),
- message_id=1,
- target=0,
+ dialogue_reference=self.dialogues.new_self_initiated_dialogue_reference(),
query=Query([Constraint("something", ConstraintType(">", 1))]),
)
+ msg.counterparty = "this_address_does_not_exist"
+ sending_dialogue = cast(Optional[FipaDialogue], self.dialogues.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to="this_address_does_not_exist",
- sender=self.address_1,
- protocol_id=FipaMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
self.multiplexer1.put(envelope)
@@ -348,7 +462,7 @@ async def test_messages(self):
# check the result
response_envelope = self.multiplexer1.get(block=True, timeout=5.0)
assert response_envelope.protocol_id == DefaultMessage.protocol_id
- assert response_envelope.sender == DEFAULT_OEF
+ assert response_envelope.sender == str(OEFLocalConnection.connection_id)
result = response_envelope.message
assert result.performative == DefaultMessage.Performative.ERROR
@@ -378,9 +492,10 @@ def setup_class(cls):
)
cls.multiplexer1.connect()
cls.multiplexer2.connect()
+ cls.dialogues1 = OefSearchDialogues(cls.address_1)
+ cls.dialogues2 = OefSearchDialogues(cls.address_2)
# register 'multiplexer1' as a service 'foobar'.
- request_id = 1
cls.data_model_foobar = DataModel(
"foobar",
attributes=[Attribute("foo", int, True), Attribute("bar", str, True)],
@@ -390,13 +505,18 @@ def setup_class(cls):
)
register_service_request = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=cls.dialogues1.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ register_service_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], cls.dialogues1.update(register_service_request)
+ )
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=cls.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=register_service_request.counterparty,
+ sender=register_service_request.sender,
+ protocol_id=register_service_request.protocol_id,
message=register_service_request,
)
cls.multiplexer1.put(envelope)
@@ -413,13 +533,18 @@ def setup_class(cls):
)
register_service_request = OefSearchMessage(
performative=OefSearchMessage.Performative.REGISTER_SERVICE,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=cls.dialogues1.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ register_service_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], cls.dialogues2.update(register_service_request)
+ )
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=cls.address_2,
- protocol_id=OefSearchMessage.protocol_id,
+ to=register_service_request.counterparty,
+ sender=register_service_request.sender,
+ protocol_id=register_service_request.protocol_id,
message=register_service_request,
)
cls.multiplexer2.put(envelope)
@@ -434,45 +559,52 @@ def setup_class(cls):
)
msg = OefSearchMessage(
performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
- dialogue_reference=(str(1), ""),
+ dialogue_reference=cls.dialogues1.new_self_initiated_dialogue_reference(),
service_description=service_description,
)
+ msg.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(Optional[OefSearchDialogue], cls.dialogues1.update(msg))
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=cls.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
cls.multiplexer1.put(envelope)
- @pytest.mark.flaky(
- reruns=MAX_FLAKY_RERUNS
- ) # TODO: check reasons!. quite unstable test
+ @pytest.mark.flaky(reruns=0) # TODO: check reasons!. quite unstable test
def test_filtered_search_result(self):
"""Test that the search result contains only the entries matching the query."""
- request_id = 1
query = Query(constraints=[], model=self.data_model_barfoo)
# build and send the request
search_services_request = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
- dialogue_reference=(str(request_id), ""),
+ dialogue_reference=self.dialogues1.new_self_initiated_dialogue_reference(),
query=query,
)
+ search_services_request.counterparty = str(OEFLocalConnection.connection_id)
+ sending_dialogue = cast(
+ Optional[OefSearchDialogue], self.dialogues1.update(search_services_request)
+ )
+ assert sending_dialogue is not None
envelope = Envelope(
- to=DEFAULT_OEF,
- sender=self.address_1,
- protocol_id=OefSearchMessage.protocol_id,
+ to=search_services_request.counterparty,
+ sender=search_services_request.sender,
+ protocol_id=search_services_request.protocol_id,
message=search_services_request,
)
self.multiplexer1.put(envelope)
# check the result
response_envelope = InBox(self.multiplexer1).get(block=True, timeout=5.0)
- assert response_envelope.protocol_id == OefSearchMessage.protocol_id
- assert response_envelope.to == self.address_1
- assert response_envelope.sender == DEFAULT_OEF
- search_result = response_envelope.message
+ search_result_orig = cast(OefSearchMessage, response_envelope.message)
+ search_result = copy.copy(search_result_orig)
+ search_result.is_incoming = True
+ search_result.counterparty = search_result_orig.sender
+ response_dialogue = self.dialogues1.update(search_result)
+ assert response_dialogue == sending_dialogue
assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
assert search_result.agents == (self.address_2,)
diff --git a/tests/test_packages/test_connections/test_oef/test_communication.py b/tests/test_packages/test_connections/test_oef/test_communication.py
index 715b4b3699..b016337ab0 100644
--- a/tests/test_packages/test_connections/test_oef/test_communication.py
+++ b/tests/test_packages/test_connections/test_oef/test_communication.py
@@ -21,6 +21,7 @@
"""This test module contains the tests for the OEF communication using an OEF."""
import asyncio
+import copy
import logging
import sys
import time
@@ -68,8 +69,6 @@
_make_oef_connection,
)
-DEFAULT_OEF = "default_oef"
-
logger = logging.getLogger(__name__)
@@ -179,11 +178,12 @@ def test_search_services_with_query_without_model(self):
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
query=search_query_empty_model,
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(self.connection.connection_id)
sending_dialogue = self.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
@@ -191,7 +191,10 @@ def test_search_services_with_query_without_model(self):
)
envelope = self.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -215,11 +218,12 @@ def test_search_services_with_query_with_model(self):
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
query=search_query,
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(self.connection.connection_id)
sending_dialogue = self.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
@@ -227,7 +231,10 @@ def test_search_services_with_query_with_model(self):
)
envelope = self.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -258,18 +265,22 @@ def test_search_services_with_distance_query(self):
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
query=search_query,
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(self.connection.connection_id)
sending_dialogue = self.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
)
)
envelope = self.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -308,14 +319,14 @@ def test_register_service(self):
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
service_description=desc,
)
- oef_search_registration.counterparty = DEFAULT_OEF
+ oef_search_registration.counterparty = str(self.connection.connection_id)
sending_dialogue_1 = self.oef_search_dialogues.update(
oef_search_registration
)
assert sending_dialogue_1 is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_registration,
@@ -330,18 +341,22 @@ def test_register_service(self):
[Constraint("bar", ConstraintType("==", 1))], model=foo_datamodel
),
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(self.connection.connection_id)
sending_dialogue_2 = self.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue_2 is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
)
)
envelope = self.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -385,14 +400,14 @@ def setup_class(cls):
dialogue_reference=cls.oef_search_dialogues.new_self_initiated_dialogue_reference(),
service_description=cls.desc,
)
- oef_search_registration.counterparty = DEFAULT_OEF
+ oef_search_registration.counterparty = str(cls.connection.connection_id)
sending_dialogue_1 = cls.oef_search_dialogues.update(
oef_search_registration
)
assert sending_dialogue_1 is not None
cls.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(cls.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_registration,
@@ -409,18 +424,22 @@ def setup_class(cls):
model=cls.foo_datamodel,
),
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(cls.connection.connection_id)
sending_dialogue_2 = cls.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue_2 is not None
cls.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(cls.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
)
)
envelope = cls.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = cls.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -444,14 +463,14 @@ def test_unregister_service(self):
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
service_description=self.desc,
)
- oef_search_deregistration.counterparty = DEFAULT_OEF
+ oef_search_deregistration.counterparty = str(self.connection.connection_id)
sending_dialogue_1 = self.oef_search_dialogues.update(
oef_search_deregistration
)
assert sending_dialogue_1 is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_deregistration,
@@ -468,11 +487,12 @@ def test_unregister_service(self):
model=self.foo_datamodel,
),
)
- oef_search_request.counterparty = DEFAULT_OEF
+ oef_search_request.counterparty = str(self.connection.connection_id)
sending_dialogue_2 = self.oef_search_dialogues.update(oef_search_request)
+ assert sending_dialogue_2 is not None
self.multiplexer.put(
Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=oef_search_request,
@@ -480,7 +500,10 @@ def test_unregister_service(self):
)
envelope = self.multiplexer.get(block=True, timeout=5.0)
- oef_search_response = envelope.message
+ oef_search_response_original = envelope.message
+ oef_search_response = copy.copy(oef_search_response_original)
+ oef_search_response.is_incoming = True
+ oef_search_response.counterparty = oef_search_response_original.sender
oef_search_dialogue = self.oef_search_dialogues.update(oef_search_response)
assert (
oef_search_response.performative
@@ -840,7 +863,7 @@ def test_on_oef_error(self):
def test_send(self):
"""Test the send method."""
envelope = Envelope(
- to=DEFAULT_OEF,
+ to=str(self.connection1.connection_id),
sender="me",
protocol_id=DefaultMessage.protocol_id,
message=b"Hello",
@@ -1009,7 +1032,7 @@ class TestSendWithOEF(UseOef):
"""Test other usecases with OEF."""
@pytest.mark.asyncio
- async def test_send_oef_message(self, pytestconfig):
+ async def test_send_oef_message(self, pytestconfig, caplog):
"""Test the send oef message."""
oef_connection = _make_oef_connection(
address=FETCHAI_ADDRESS_ONE, oef_addr="127.0.0.1", oef_port=10000,
@@ -1022,16 +1045,17 @@ async def test_send_oef_message(self, pytestconfig):
dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
oef_error_operation=OefSearchMessage.OefErrorOperation.SEARCH_SERVICES,
)
- msg.counterparty = DEFAULT_OEF
+ msg.counterparty = str(oef_connection.connection_id)
sending_dialogue = oef_search_dialogues.update(msg)
envelope = Envelope(
- to=DEFAULT_OEF,
+ to=str(oef_connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=msg,
)
- with pytest.raises(ValueError):
+ with caplog.at_level(logging.DEBUG, "aea.packages.fetchai.connections.oef"):
await oef_connection.send(envelope)
+ assert "Could not create dialogue for message=" in caplog.text
data_model = DataModel("foobar", attributes=[Attribute("foo", str, True)])
query = Query(
@@ -1044,17 +1068,20 @@ async def test_send_oef_message(self, pytestconfig):
dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
query=query,
)
- msg.counterparty = DEFAULT_OEF
+ msg.counterparty = str(oef_connection.connection_id)
sending_dialogue = oef_search_dialogues.update(msg)
envelope = Envelope(
- to=DEFAULT_OEF,
+ to=str(oef_connection.connection_id),
sender=FETCHAI_ADDRESS_ONE,
protocol_id=OefSearchMessage.protocol_id,
message=msg,
)
await oef_connection.send(envelope)
envelope = await oef_connection.receive()
- search_result = envelope.message
+ search_result_original = envelope.message
+ search_result = copy.copy(search_result_original)
+ search_result.counterparty = search_result_original.sender
+ search_result.is_incoming = True
response_dialogue = oef_search_dialogues.update(search_result)
assert search_result.performative == OefSearchMessage.Performative.SEARCH_RESULT
assert sending_dialogue == response_dialogue
@@ -1108,11 +1135,11 @@ async def test_connecting_twice_is_ok(self, pytestconfig):
)
oef_connection.loop = asyncio.get_event_loop()
- assert not oef_connection.connection_status.is_connected
+ assert not oef_connection.is_connected
await oef_connection.connect()
- assert oef_connection.connection_status.is_connected
+ assert oef_connection.is_connected
await oef_connection.connect()
- assert oef_connection.connection_status.is_connected
+ assert oef_connection.is_connected
await oef_connection.disconnect()
@@ -1121,7 +1148,7 @@ async def test_connecting_twice_is_ok(self, pytestconfig):
@pytest.mark.skipif(
sys.version_info < (3, 7), reason="Python version < 3.7 not supported by the OEF."
)
-async def test_cannot_connect_to_oef(caplog):
+async def test_cannot_connect_to_oef():
"""Test the case when we can't connect to the OEF."""
oef_connection = _make_oef_connection(
address=FETCHAI_ADDRESS_ONE,
@@ -1129,13 +1156,15 @@ async def test_cannot_connect_to_oef(caplog):
oef_port=61234, # use addr instead of hostname to avoid name resolution
)
- with caplog.at_level(logging.DEBUG, logger="aea.packages.fetchai.connections.oef"):
+ with mock.patch.object(oef_connection.logger, "warning") as mock_logger:
task = asyncio.ensure_future(
oef_connection.connect(), loop=asyncio.get_event_loop()
)
await asyncio.sleep(3.0)
- assert "Cannot connect to OEFChannel. Retrying in 5 seconds..." in caplog.text
+ mock_logger.assert_any_call(
+ "Cannot connect to OEFChannel. Retrying in 5 seconds..."
+ )
await cancel_and_wait(task)
await oef_connection.disconnect()
diff --git a/tests/test_packages/test_connections/test_p2p_client/test_p2p_client.py b/tests/test_packages/test_connections/test_p2p_client/test_p2p_client.py
index 1dbdb7dc73..5ef384bb40 100644
--- a/tests/test_packages/test_connections/test_p2p_client/test_p2p_client.py
+++ b/tests/test_packages/test_connections/test_p2p_client/test_p2p_client.py
@@ -82,7 +82,7 @@ async def test_disconnect(self):
return_value={"status": "OK"},
):
await self.p2p_client_connection.disconnect()
- assert self.p2p_client_connection.connection_status.is_connected is False
+ assert self.p2p_client_connection.is_connected is False
@pytest.mark.asyncio
@@ -117,7 +117,7 @@ async def test_p2p_receive():
return_value={"status": "OK"},
):
await p2p_connection.connect()
- assert p2p_connection.connection_status.is_connected is True
+ assert p2p_connection.is_connected is True
with mock.patch.object(
fetch.p2p.api.http_calls.HTTPCalls, "get_messages", return_value=messages
@@ -132,7 +132,7 @@ async def test_p2p_receive():
):
p2p_connection.channel._httpCall.get_messages = fake_get_messages_empty
await p2p_connection.disconnect()
- assert p2p_connection.connection_status.is_connected is False
+ assert p2p_connection.is_connected is False
@pytest.mark.asyncio
@@ -162,7 +162,7 @@ async def test_p2p_send():
return_value={"status": "OK"},
):
await p2p_client_connection.connect()
- assert p2p_client_connection.connection_status.is_connected is True
+ assert p2p_client_connection.is_connected is True
with mock.patch.object(
fetch.p2p.api.http_calls.HTTPCalls, "get_messages", return_value=[]
@@ -180,4 +180,4 @@ async def test_p2p_send():
fetch.p2p.api.http_calls.HTTPCalls, "unregister", return_value={"status": "OK"},
):
await p2p_client_connection.disconnect()
- assert p2p_client_connection.connection_status.is_connected is False
+ assert p2p_client_connection.is_connected is False
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p/test_aea_cli.py b/tests/test_packages/test_connections/test_p2p_libp2p/test_aea_cli.py
index 63ad027400..5a73b2a0ca 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p/test_aea_cli.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p/test_aea_cli.py
@@ -38,8 +38,8 @@ class TestP2PLibp2pConnectionAEARunningDefaultConfigNode(AEATestCaseEmpty):
@libp2p_log_on_failure
def test_agent(self):
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
# for logging
config_path = "vendor.fetchai.connections.p2p_libp2p.config"
@@ -68,7 +68,7 @@ def teardown_class(cls):
"""Tear down the test"""
cls.terminate_agents()
- AEATestCaseEmpty.teardown_class()
+ super(TestP2PLibp2pConnectionAEARunningDefaultConfigNode, cls).teardown_class()
@skip_test_windows
@@ -77,7 +77,7 @@ class TestP2PLibp2pConnectionAEARunningFullNode(AEATestCaseEmpty):
@libp2p_log_on_failure
def test_agent(self):
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
# setup a full node: with public uri, relay service, and delegate service
config_path = "vendor.fetchai.connections.p2p_libp2p.config"
@@ -118,5 +118,4 @@ def test_agent(self):
def teardown_class(cls):
"""Tear down the test"""
cls.terminate_agents()
-
- AEATestCaseEmpty.teardown_class()
+ super(TestP2PLibp2pConnectionAEARunningFullNode, cls).teardown_class()
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p/test_communication.py b/tests/test_packages/test_connections/test_p2p_libp2p/test_communication.py
index 376ef99293..8d78c93c97 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p/test_communication.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p/test_communication.py
@@ -58,16 +58,16 @@ def setup_class(cls):
@pytest.mark.asyncio
async def test_p2plibp2pconnection_connect_disconnect(self):
- assert self.connection.connection_status.is_connected is False
+ assert self.connection.is_connected is False
try:
await self.connection.connect()
- assert self.connection.connection_status.is_connected is True
+ assert self.connection.is_connected is True
except Exception as e:
await self.connection.disconnect()
raise e
await self.connection.disconnect()
- assert self.connection.connection_status.is_connected is False
+ assert self.connection.is_connected is False
@classmethod
def teardown_class(cls):
@@ -109,8 +109,8 @@ def setup_class(cls):
cls.multiplexer2.connect()
def test_connection_is_established(self):
- assert self.connection1.connection_status.is_connected is True
- assert self.connection2.connection_status.is_connected is True
+ assert self.connection1.is_connected is True
+ assert self.connection2.is_connected is True
def test_envelope_routed(self):
addr_1 = self.connection1.node.address
@@ -228,9 +228,9 @@ def setup_class(cls):
muxer.connect()
def test_connection_is_established(self):
- assert self.connection_genesis.connection_status.is_connected is True
+ assert self.connection_genesis.is_connected is True
for conn in self.connections:
- assert conn.connection_status.is_connected is True
+ assert conn.is_connected is True
def test_star_routing_connectivity(self):
addrs = [conn.node.address for conn in self.connections]
@@ -317,9 +317,9 @@ def setup_class(cls):
cls.multiplexer2.connect()
def test_connection_is_established(self):
- assert self.relay.connection_status.is_connected is True
- assert self.connection1.connection_status.is_connected is True
- assert self.connection2.connection_status.is_connected is True
+ assert self.relay.is_connected is True
+ assert self.connection1.is_connected is True
+ assert self.connection2.is_connected is True
def test_envelope_routed(self):
addr_1 = self.connection1.node.address
@@ -460,10 +460,10 @@ def setup_class(cls):
muxer.connect()
def test_connection_is_established(self):
- assert self.connection_relay_1.connection_status.is_connected is True
- assert self.connection_relay_2.connection_status.is_connected is True
+ assert self.connection_relay_1.is_connected is True
+ assert self.connection_relay_2.is_connected is True
for conn in self.connections:
- assert conn.connection_status.is_connected is True
+ assert conn.is_connected is True
def test_star_routing_connectivity(self):
addrs = [conn.node.address for conn in self.connections]
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p/test_errors.py b/tests/test_packages/test_connections/test_p2p_libp2p/test_errors.py
index ad774dc22a..53b8228fc3 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p/test_errors.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p/test_errors.py
@@ -113,9 +113,10 @@ def test_wrong_path(self):
def test_timeout(self):
self.connection.node._connection_timeout = 0
self.connection.node._connection_attempts = 2
+ muxer = Multiplexer([self.connection])
with pytest.raises(Exception):
- muxer = Multiplexer([self.connection])
muxer.connect()
+ muxer.disconnect()
@classmethod
def teardown_class(cls):
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p/test_public_dht.py b/tests/test_packages/test_connections/test_p2p_libp2p/test_public_dht.py
new file mode 100644
index 0000000000..ab1430bdba
--- /dev/null
+++ b/tests/test_packages/test_connections/test_p2p_libp2p/test_public_dht.py
@@ -0,0 +1,210 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 test module contains integration tests for P2PLibp2p connection."""
+
+import os
+import shutil
+import tempfile
+import time
+
+import pytest
+
+from aea.configurations.constants import DEFAULT_LEDGER
+from aea.crypto.registries import make_crypto
+from aea.mail.base import Envelope
+from aea.multiplexer import Multiplexer
+from aea.protocols.default.message import DefaultMessage
+from aea.protocols.default.serialization import DefaultSerializer
+
+from tests.conftest import (
+ PUBLIC_DHT_P2P_MADDR_1,
+ PUBLIC_DHT_P2P_MADDR_2,
+ _make_libp2p_connection,
+ libp2p_log_on_failure,
+ libp2p_log_on_failure_all,
+ skip_test_windows,
+)
+
+DEFAULT_PORT = 10234
+
+
+@skip_test_windows
+@pytest.mark.integration
+@libp2p_log_on_failure_all
+class TestLibp2pConnectionRelayPublicDHT:
+ """Test that public dht is working properly"""
+
+ @classmethod
+ def setup_class(cls):
+ """Set the test up"""
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ cls.log_files = []
+
+ def test_reachable(self):
+ public_nodes_maddrs = [PUBLIC_DHT_P2P_MADDR_1, PUBLIC_DHT_P2P_MADDR_2]
+ for maddr in public_nodes_maddrs:
+ connection = _make_libp2p_connection(
+ DEFAULT_PORT + 1, relay=False, entry_peers=[maddr]
+ )
+ multiplexer = Multiplexer([connection])
+ self.log_files.append(connection.node.log_file)
+ multiplexer.connect()
+
+ assert connection.is_connected is True
+ multiplexer.disconnect()
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear down the test"""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
+
+
+@skip_test_windows
+@libp2p_log_on_failure_all
+class TestLibp2pConnectionRelayNodeRestart:
+ """Test that connection will reliably route envelope to destination in case of relay node restart within timeout"""
+
+ @classmethod
+ @libp2p_log_on_failure
+ def setup_class(cls):
+ """Set the test up"""
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ cls.log_files = []
+
+ cls.genesis = _make_libp2p_connection(DEFAULT_PORT + 1)
+
+ cls.multiplexer_genesis = Multiplexer([cls.genesis])
+ cls.log_files.append(cls.genesis.node.log_file)
+ cls.multiplexer_genesis.connect()
+
+ genesis_peer = cls.genesis.node.multiaddrs[0]
+
+ with open("node_key", "wb") as f:
+ make_crypto(DEFAULT_LEDGER).dump(f)
+ cls.relay_key_path = "node_key"
+
+ cls.relay = _make_libp2p_connection(
+ port=DEFAULT_PORT + 2,
+ entry_peers=[genesis_peer],
+ node_key_file=cls.relay_key_path,
+ )
+ cls.multiplexer_relay = Multiplexer([cls.relay])
+ cls.log_files.append(cls.relay.node.log_file)
+ cls.multiplexer_relay.connect()
+
+ relay_peer = cls.relay.node.multiaddrs[0]
+
+ cls.connection = _make_libp2p_connection(
+ DEFAULT_PORT + 3, relay=False, entry_peers=[relay_peer]
+ )
+ cls.multiplexer = Multiplexer([cls.connection])
+ cls.log_files.append(cls.connection.node.log_file)
+ cls.multiplexer.connect()
+
+ def test_connection_is_established(self):
+ assert self.relay.is_connected is True
+ assert self.connection.is_connected is True
+
+ def test_envelope_routed_after_relay_restart(self):
+ addr_1 = self.connection.address
+ addr_2 = self.genesis.address
+
+ msg = DefaultMessage(
+ dialogue_reference=("", ""),
+ message_id=1,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"hello",
+ )
+ envelope = Envelope(
+ to=addr_2,
+ sender=addr_1,
+ protocol_id=DefaultMessage.protocol_id,
+ message=DefaultSerializer().encode(msg),
+ )
+
+ self.multiplexer.put(envelope)
+ delivered_envelope = self.multiplexer_genesis.get(block=True, timeout=20)
+
+ assert delivered_envelope is not None
+ assert delivered_envelope.to == envelope.to
+ assert delivered_envelope.sender == envelope.sender
+ assert delivered_envelope.protocol_id == envelope.protocol_id
+ assert delivered_envelope.message == envelope.message
+
+ self.multiplexer_relay.disconnect()
+
+ msg = DefaultMessage(
+ dialogue_reference=("", ""),
+ message_id=1,
+ target=0,
+ performative=DefaultMessage.Performative.BYTES,
+ content=b"helloAfterRestart",
+ )
+ envelope = Envelope(
+ to=addr_2,
+ sender=addr_1,
+ protocol_id=DefaultMessage.protocol_id,
+ message=DefaultSerializer().encode(msg),
+ )
+
+ self.multiplexer.put(envelope)
+ time.sleep(5)
+
+ TestLibp2pConnectionRelayNodeRestart.relay = _make_libp2p_connection(
+ port=DEFAULT_PORT + 2,
+ entry_peers=[self.genesis.node.multiaddrs[0]],
+ node_key_file=self.relay_key_path,
+ )
+ TestLibp2pConnectionRelayNodeRestart.multiplexer_relay = Multiplexer(
+ [self.relay]
+ )
+ self.multiplexer_relay.connect()
+
+ delivered_envelope = self.multiplexer_genesis.get(block=True, timeout=20)
+
+ assert delivered_envelope is not None
+ assert delivered_envelope.to == envelope.to
+ assert delivered_envelope.sender == envelope.sender
+ assert delivered_envelope.protocol_id == envelope.protocol_id
+ assert delivered_envelope.message == envelope.message
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear down the test"""
+ cls.multiplexer.disconnect()
+ cls.multiplexer_relay.disconnect()
+ cls.multiplexer_genesis.disconnect()
+
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_aea_cli.py b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_aea_cli.py
index 3703113ece..bb5bffe21d 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_aea_cli.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_aea_cli.py
@@ -46,7 +46,7 @@ class TestP2PLibp2pClientConnectionAEARunning(AEATestCaseEmpty):
@libp2p_log_on_failure
def setup_class(cls):
"""Set up the test class."""
- AEATestCaseEmpty.setup_class()
+ super(TestP2PLibp2pClientConnectionAEARunning, cls).setup_class()
cls.node_connection = _make_libp2p_connection(
delegate_host=DEFAULT_HOST,
@@ -59,10 +59,10 @@ def setup_class(cls):
cls.node_multiplexer.connect()
def test_node(self):
- assert self.node_connection.connection_status.is_connected is True
+ assert self.node_connection.is_connected is True
def test_connection(self):
- self.add_item("connection", "fetchai/p2p_libp2p_client:0.4.0")
+ self.add_item("connection", "fetchai/p2p_libp2p_client:0.5.0")
config_path = "vendor.fetchai.connections.p2p_libp2p_client.config"
self.force_set_config(
"{}.nodes".format(config_path),
@@ -91,6 +91,6 @@ def teardown_class(cls):
"""Tear down the test"""
cls.terminate_agents()
- AEATestCaseEmpty.teardown_class()
+ super(TestP2PLibp2pClientConnectionAEARunning, cls).teardown_class()
cls.node_multiplexer.disconnect()
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_communication.py b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_communication.py
index 4e2ec63b29..6c976faf3c 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_communication.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_communication.py
@@ -63,17 +63,17 @@ def setup_class(cls):
@pytest.mark.asyncio
async def test_libp2pclientconnection_connect_disconnect(self):
- assert self.connection.connection_status.is_connected is False
+ assert self.connection.is_connected is False
try:
await self.connection_node.connect()
await self.connection.connect()
- assert self.connection.connection_status.is_connected is True
+ assert self.connection.is_connected is True
except Exception as e:
await self.connection.disconnect()
raise e
await self.connection.disconnect()
- assert self.connection.connection_status.is_connected is False
+ assert self.connection.is_connected is False
await self.connection_node.disconnect()
@classmethod
@@ -115,8 +115,8 @@ def setup_class(cls):
cls.multiplexer_client_2.connect()
def test_connection_is_established(self):
- assert self.connection_client_1.connection_status.is_connected is True
- assert self.connection_client_2.connection_status.is_connected is True
+ assert self.connection_client_1.is_connected is True
+ assert self.connection_client_2.is_connected is True
def test_envelope_routed(self):
addr_1 = self.connection_client_1.address
@@ -276,10 +276,10 @@ def setup_class(cls):
cls.multiplexer_client_2.connect()
def test_connection_is_established(self):
- assert self.connection_node_1.connection_status.is_connected is True
- assert self.connection_node_2.connection_status.is_connected is True
- assert self.connection_client_1.connection_status.is_connected is True
- assert self.connection_client_2.connection_status.is_connected is True
+ assert self.connection_node_1.is_connected is True
+ assert self.connection_node_2.is_connected is True
+ assert self.connection_client_1.is_connected is True
+ assert self.connection_client_2.is_connected is True
def test_envelope_routed(self):
addr_1 = self.connection_client_1.address
@@ -447,7 +447,7 @@ def setup_class(cls):
def test_connection_is_established(self):
for conn in self.connections:
- assert conn.connection_status.is_connected is True
+ assert conn.is_connected is True
def test_star_routing_connectivity(self):
msg = DefaultMessage(
diff --git a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_errors.py b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_errors.py
index 6c881a73e0..a2e976eb84 100644
--- a/tests/test_packages/test_connections/test_p2p_libp2p_client/test_errors.py
+++ b/tests/test_packages/test_connections/test_p2p_libp2p_client/test_errors.py
@@ -127,7 +127,7 @@ def setup_class(cls):
cls.multiplexer_client.connect()
def test_node_disconnected(self):
- assert self.connection_client.connection_status.is_connected is True
+ assert self.connection_client.is_connected is True
self.multiplexer_node.disconnect()
self.multiplexer_client.disconnect()
diff --git a/tests/test_packages/test_connections/test_p2p_stub/test_p2p_stub.py b/tests/test_packages/test_connections/test_p2p_stub/test_p2p_stub.py
index a19e18dbdb..4d1a6820da 100644
--- a/tests/test_packages/test_connections/test_p2p_stub/test_p2p_stub.py
+++ b/tests/test_packages/test_connections/test_p2p_stub/test_p2p_stub.py
@@ -80,10 +80,10 @@ def setup(self):
async def test_send(self):
"""Test that the connection receives what has been enqueued in the input file."""
await self.connection1.connect()
- assert self.connection1.connection_status.is_connected
+ assert self.connection1.is_connected
await self.connection2.connect()
- assert self.connection2.connection_status.is_connected
+ assert self.connection2.is_connected
envelope = make_test_envelope(to_="con2")
await self.connection1.send(envelope)
diff --git a/tests/test_packages/test_connections/test_soef/test_soef.py b/tests/test_packages/test_connections/test_soef/test_soef.py
index 13a2918a20..8a5722c4ee 100644
--- a/tests/test_packages/test_connections/test_soef/test_soef.py
+++ b/tests/test_packages/test_connections/test_soef/test_soef.py
@@ -132,7 +132,7 @@ def setup(self):
api_key="TwiCIriSl0mLahw17pyqoA",
soef_addr="soef.fetch.ai",
soef_port=9002,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
)
self.connection = SOEFConnection(
@@ -214,19 +214,19 @@ async def test_remove_service_key(self):
def test_connected(self):
"""Test connected==True."""
- assert self.connection.connection_status.is_connected
+ assert self.connection.is_connected
@pytest.mark.asyncio
async def test_disconnected(self):
"""Test disconnect."""
- assert self.connection.connection_status.is_connected
+ assert self.connection.is_connected
with patch.object(
self.connection.channel,
"_request_text",
make_async("Goodbye!"),
):
await self.connection.disconnect()
- assert not self.connection.connection_status.is_connected
+ assert not self.connection.is_connected
@pytest.mark.asyncio
async def test_register_service(self):
@@ -302,9 +302,10 @@ async def test_bad_register_service(self):
expected_envelope.message.performative
== OefSearchMessage.Performative.OEF_ERROR
)
- message = copy.deepcopy(expected_envelope.message)
+ orig = expected_envelope.message
+ message = copy.copy(orig)
message.is_incoming = True # TODO: fix
- message.counterparty = SOEFConnection.connection_id.latest # TODO; fix
+ message.counterparty = orig.sender # TODO; fix
receiving_dialogue = self.oef_search_dialogues.update(message)
assert sending_dialogue == receiving_dialogue
@@ -406,11 +407,17 @@ async def test_bad_performative(self, caplog):
service_instance, data_model=models.AGENT_LOCATION_MODEL
)
message = OefSearchMessage(
- performative="oef_error", service_description=service_description,
+ performative="oef_error",
+ dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ service_description=service_description,
)
+ message.counterparty = SOEFConnection.connection_id.latest
+ sending_dialogue = self.oef_search_dialogues.update(message)
+ assert sending_dialogue is None
+ message.sender = self.crypto.address
envelope = Envelope(
- to="soef",
- sender=self.crypto.address,
+ to=message.counterparty,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -448,9 +455,10 @@ async def test_bad_search_query(self, caplog):
assert expected_envelope
message = expected_envelope.message
assert message.performative == OefSearchMessage.Performative.OEF_ERROR
- message = copy.deepcopy(expected_envelope.message)
+ orig = expected_envelope.message
+ message = copy.copy(orig)
message.is_incoming = True # TODO: fix
- message.counterparty = SOEFConnection.connection_id.latest # TODO; fix
+ message.counterparty = orig.sender # TODO; fix
receiving_dialogue = self.oef_search_dialogues.update(message)
assert sending_dialogue == receiving_dialogue
@@ -495,14 +503,17 @@ async def test_search(self):
make_async(self.search_success_response),
):
await self.connection.send(envelope)
+ expected_envelope = await asyncio.wait_for(
+ self.connection.receive(), timeout=1
+ )
- expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)
assert expected_envelope
message = expected_envelope.message
assert len(message.agents) >= 1
- message = copy.deepcopy(expected_envelope.message)
+ orig = expected_envelope.message
+ message = copy.copy(orig)
message.is_incoming = True # TODO: fix
- message.counterparty = SOEFConnection.connection_id.latest # TODO; fix
+ message.counterparty = orig.sender # TODO; fix
receiving_dialogue = self.oef_search_dialogues.update(message)
assert sending_dialogue == receiving_dialogue
@@ -526,14 +537,58 @@ async def test_find_around_me(self):
closeness_query = Query(
[close_to_my_service] + personality_filters + service_key_filters
)
- message = OefSearchMessage(
+
+ message_1 = OefSearchMessage(
performative=OefSearchMessage.Performative.SEARCH_SERVICES,
dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
query=closeness_query,
)
- message.counterparty = SOEFConnection.connection_id.latest
- sending_dialogue = self.oef_search_dialogues.update(message)
+ message_1.counterparty = SOEFConnection.connection_id.latest
+ sending_dialogue = self.oef_search_dialogues.update(message_1)
+ assert sending_dialogue is not None
+
+ internal_msg_1 = copy.copy(message_1)
+ internal_msg_1.is_incoming = True
+ internal_msg_1.counterparty = message_1.sender
+ internal_dialogue_1 = self.connection.channel.oef_search_dialogues.update(
+ internal_msg_1
+ )
+ assert internal_dialogue_1 is not None
+
+ message_2 = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ query=closeness_query,
+ )
+ message_2.counterparty = SOEFConnection.connection_id.latest
+ sending_dialogue = self.oef_search_dialogues.update(message_2)
+ assert sending_dialogue is not None
+
+ internal_msg_2 = copy.copy(message_2)
+ internal_msg_2.is_incoming = True
+ internal_msg_2.counterparty = message_2.sender
+ internal_dialogue_2 = self.connection.channel.oef_search_dialogues.update(
+ internal_msg_2
+ )
+ assert internal_dialogue_2 is not None
+
+ message_3 = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ query=closeness_query,
+ )
+ message_3.counterparty = SOEFConnection.connection_id.latest
+ sending_dialogue = self.oef_search_dialogues.update(message_3)
assert sending_dialogue is not None
+
+ internal_msg_3 = copy.copy(message_3)
+ internal_msg_3.is_incoming = True
+ internal_msg_3.counterparty = message_3.sender
+ internal_dialogue_3 = self.connection.channel.oef_search_dialogues.update(
+ internal_msg_3
+ )
+ assert internal_dialogue_3 is not None
+
with patch.object(
self.connection.channel,
"_request_text",
@@ -544,15 +599,15 @@ async def test_find_around_me(self):
wrap_future(self.search_fail_response),
],
):
- await self.connection.channel._find_around_me(
- message, sending_dialogue, 1, {}
+ await self.connection.channel._find_around_me_handle_requet(
+ internal_msg_1, internal_dialogue_1, 1, {}
)
- await self.connection.channel._find_around_me(
- message, sending_dialogue, 1, {}
+ await self.connection.channel._find_around_me_handle_requet(
+ internal_msg_2, internal_dialogue_2, 1, {}
)
with pytest.raises(SOEFException, match=r"`find_around_me` error: .*"):
- await self.connection.channel._find_around_me(
- message, sending_dialogue, 1, {}
+ await self.connection.channel._find_around_me_handle_requet(
+ internal_msg_3, internal_dialogue_3, 1, {}
)
@pytest.mark.asyncio
@@ -671,7 +726,7 @@ def test_chain_identifier_fail(self):
api_key="TwiCIriSl0mLahw17pyqoA",
soef_addr="soef.fetch.ai",
soef_port=9002,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
chain_identifier=chain_identifier,
)
@@ -689,7 +744,7 @@ def test_chain_identifier_ok(self):
api_key="TwiCIriSl0mLahw17pyqoA",
soef_addr="soef.fetch.ai",
soef_port=9002,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
chain_identifier=chain_identifier,
)
diff --git a/tests/test_packages/test_connections/test_soef/test_soef_integration.py b/tests/test_packages/test_connections/test_soef/test_soef_integration.py
index f5a310a005..06150dafe6 100644
--- a/tests/test_packages/test_connections/test_soef/test_soef_integration.py
+++ b/tests/test_packages/test_connections/test_soef/test_soef_integration.py
@@ -66,7 +66,7 @@ def test_soef():
api_key="TwiCIriSl0mLahw17pyqoA",
soef_addr="soef.fetch.ai",
soef_port=9002,
- restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
+ restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.4.0")},
connection_id=SOEFConnection.connection_id,
)
soef_connection = SOEFConnection(configuration=configuration, identity=identity,)
@@ -95,7 +95,7 @@ def test_soef():
assert sending_dialogue is not None
envelope = Envelope(
to=message.counterparty,
- sender=crypto.address,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -121,7 +121,7 @@ def test_soef():
assert sending_dialogue is not None
envelope = Envelope(
to=message.counterparty,
- sender=crypto.address,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -143,7 +143,7 @@ def test_soef():
assert sending_dialogue is not None
envelope = Envelope(
to=message.counterparty,
- sender=crypto.address,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -166,9 +166,9 @@ def test_soef():
message.counterparty = SOEFConnection.connection_id.latest
sending_dialogue = oef_search_dialogues.update(message)
assert sending_dialogue is not None
- envelope = Envelope(
+ search_envelope = Envelope(
to=message.counterparty,
- sender=crypto.address,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -177,20 +177,42 @@ def test_soef():
radius, agent_location.latitude, agent_location.longitude,
)
)
- multiplexer.put(envelope)
+ multiplexer.put(search_envelope)
wait_for_condition(lambda: not multiplexer.in_queue.empty(), timeout=20)
# check for search results
envelope = multiplexer.get()
- message = envelope.message
- assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT
- assert len(message.agents) >= 0
- message = copy.deepcopy(message)
+ orig_message = envelope.message
+ assert orig_message.performative == OefSearchMessage.Performative.SEARCH_RESULT
+ assert len(orig_message.agents) >= 0
+ message = copy.copy(orig_message)
message.is_incoming = True # TODO: fix
- message.counterparty = SOEFConnection.connection_id.latest # TODO; fix
+ message.counterparty = orig_message.sender # TODO; fix
receiving_dialogue = oef_search_dialogues.update(message)
assert sending_dialogue == receiving_dialogue
+ # double send to check issue with too many requests
+ message = OefSearchMessage(
+ performative=OefSearchMessage.Performative.SEARCH_SERVICES,
+ dialogue_reference=oef_search_dialogues.new_self_initiated_dialogue_reference(),
+ query=closeness_query,
+ )
+ message.counterparty = SOEFConnection.connection_id.latest
+ sending_dialogue = oef_search_dialogues.update(message)
+ assert sending_dialogue is not None
+ search_envelope = Envelope(
+ to=message.counterparty,
+ sender=message.sender,
+ protocol_id=message.protocol_id,
+ message=message,
+ )
+ multiplexer.put(search_envelope)
+ wait_for_condition(lambda: not multiplexer.in_queue.empty(), timeout=20)
+ # check for search results
+ envelope = multiplexer.get()
+ message = envelope.message
+ assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT
+
# find agents near me with filter
radius = 0.1
close_to_my_service = Constraint(
@@ -221,7 +243,7 @@ def test_soef():
assert sending_dialogue is not None
envelope = Envelope(
to=message.counterparty,
- sender=crypto.address,
+ sender=message.sender,
protocol_id=message.protocol_id,
message=message,
)
@@ -235,12 +257,12 @@ def test_soef():
wait_for_condition(lambda: not multiplexer.in_queue.empty(), timeout=20)
envelope = multiplexer.get()
- message = envelope.message
- assert message.performative == OefSearchMessage.Performative.SEARCH_RESULT
- assert len(message.agents) >= 0
- message = copy.deepcopy(message)
+ orig_message = envelope.message
+ assert orig_message.performative == OefSearchMessage.Performative.SEARCH_RESULT
+ assert len(orig_message.agents) >= 0
+ message = copy.copy(orig_message)
message.is_incoming = True # TODO: fix
- message.counterparty = SOEFConnection.connection_id.latest # TODO; fix
+ message.counterparty = orig_message.sender # TODO; fix
receiving_dialogue = oef_search_dialogues.update(message)
assert sending_dialogue == receiving_dialogue
diff --git a/tests/test_packages/test_connections/test_tcp/test_base.py b/tests/test_packages/test_connections/test_tcp/test_base.py
index abaa0bcd27..befe88aa87 100644
--- a/tests/test_packages/test_connections/test_tcp/test_base.py
+++ b/tests/test_packages/test_connections/test_tcp/test_base.py
@@ -20,7 +20,6 @@
"""This module contains the tests for the TCP base module."""
import asyncio
-import logging
import unittest.mock
from asyncio import CancelledError
@@ -37,7 +36,7 @@
@pytest.mark.asyncio
-async def test_connect_twice(caplog):
+async def test_connect_twice():
"""Test that connecting twice the tcp connection works correctly."""
port = get_unused_tcp_port()
tcp_connection = _make_tcp_server_connection("address", "127.0.0.1", port)
@@ -47,17 +46,15 @@ async def test_connect_twice(caplog):
await tcp_connection.connect()
await asyncio.sleep(0.1)
- with caplog.at_level(
- logging.WARNING, "aea.packages.fetchai.connections.tcp.tcp_server"
- ):
+ with unittest.mock.patch.object(tcp_connection.logger, "warning") as mock_logger:
await tcp_connection.connect()
- assert "Connection already set up." in caplog.text
+ mock_logger.assert_called_with("Connection already set up.")
await tcp_connection.disconnect()
@pytest.mark.asyncio
-async def test_connect_raises_exception(caplog):
+async def test_connect_raises_exception():
"""Test the case that a connection attempt raises an exception."""
port = get_unused_tcp_port()
tcp_connection = _make_tcp_server_connection("address", "127.0.0.1", port)
@@ -65,14 +62,12 @@ async def test_connect_raises_exception(caplog):
loop = asyncio.get_event_loop()
tcp_connection.loop = loop
- with caplog.at_level(
- logging.ERROR, "aea.packages.fetchai.connections.tcp.tcp_server"
- ):
+ with unittest.mock.patch.object(tcp_connection.logger, "error") as mock_logger:
with unittest.mock.patch.object(
tcp_connection, "setup", side_effect=Exception("error during setup")
):
await tcp_connection.connect()
- assert "error during setup" in caplog.text
+ mock_logger.assert_called_with("error during setup")
@pytest.mark.asyncio
@@ -81,15 +76,13 @@ async def test_disconnect_when_already_disconnected(caplog):
port = get_unused_tcp_port()
tcp_connection = _make_tcp_server_connection("address", "127.0.0.1", port)
- with caplog.at_level(
- logging.WARNING, "aea.packages.fetchai.connections.tcp.tcp_server"
- ):
+ with unittest.mock.patch.object(tcp_connection.logger, "warning") as mock_logger:
await tcp_connection.disconnect()
- assert "Connection already disconnected." in caplog.text
+ mock_logger.assert_called_with("Connection already disconnected.")
@pytest.mark.asyncio
-async def test_send_to_unknown_destination(caplog):
+async def test_send_to_unknown_destination():
"""Test that a message to an unknown destination logs an error."""
address = "address"
port = get_unused_tcp_port()
@@ -100,11 +93,11 @@ async def test_send_to_unknown_destination(caplog):
protocol_id=DefaultMessage.protocol_id,
message=b"",
)
- with caplog.at_level(
- logging.ERROR, "aea.packages.fetchai.connections.tcp.tcp_server"
- ):
+ with unittest.mock.patch.object(tcp_connection.logger, "error") as mock_logger:
await tcp_connection.send(envelope)
- assert "[{}]: Cannot send envelope {}".format(address, envelope) in caplog.text
+ mock_logger.assert_called_with(
+ "[{}]: Cannot send envelope {}".format(address, envelope)
+ )
@pytest.mark.asyncio
diff --git a/tests/test_packages/test_connections/test_tcp/test_communication.py b/tests/test_packages/test_connections/test_tcp/test_communication.py
index 1a4502a039..980f769e45 100644
--- a/tests/test_packages/test_connections/test_tcp/test_communication.py
+++ b/tests/test_packages/test_connections/test_tcp/test_communication.py
@@ -20,7 +20,6 @@
"""This module contains the tests for the TCP connection communication."""
import asyncio
-import logging
import struct
import unittest.mock
@@ -64,9 +63,9 @@ def setup_class(cls):
cls.client_1_multiplexer = Multiplexer([cls.client_conn_1])
cls.client_2_multiplexer = Multiplexer([cls.client_conn_2])
- assert not cls.server_conn.connection_status.is_connected
- assert not cls.client_conn_1.connection_status.is_connected
- assert not cls.client_conn_2.connection_status.is_connected
+ assert not cls.server_conn.is_connected
+ assert not cls.client_conn_1.is_connected
+ assert not cls.client_conn_2.is_connected
cls.server_multiplexer.connect()
cls.client_1_multiplexer.connect()
@@ -74,9 +73,9 @@ def setup_class(cls):
def test_is_connected(self):
"""Test that the connection status are connected."""
- assert self.server_conn.connection_status.is_connected
- assert self.client_conn_1.connection_status.is_connected
- assert self.client_conn_2.connection_status.is_connected
+ assert self.server_conn.is_connected
+ assert self.client_conn_1.is_connected
+ assert self.client_conn_2.is_connected
def test_communication_client_server(self):
"""Test that envelopes can be sent from a client to a server."""
@@ -156,7 +155,7 @@ class TestTCPClientConnection:
"""Test TCP Client code."""
@pytest.mark.asyncio
- async def test_receive_cancelled(self, caplog):
+ async def test_receive_cancelled(self):
"""Test that cancelling a receive task works correctly."""
port = get_unused_tcp_port()
tcp_server = _make_tcp_server_connection("address_server", "127.0.0.1", port,)
@@ -165,21 +164,21 @@ async def test_receive_cancelled(self, caplog):
await tcp_server.connect()
await tcp_client.connect()
- with caplog.at_level(
- logging.DEBUG, "aea.packages.fetchai.connections.tcp.tcp_client"
- ):
+ with unittest.mock.patch.object(tcp_client.logger, "debug") as mock_logger:
task = asyncio.ensure_future(tcp_client.receive())
await asyncio.sleep(0.1)
task.cancel()
await asyncio.sleep(0.1)
- assert "[{}] Read cancelled.".format("address_client") in caplog.text
+ mock_logger.assert_called_with(
+ "[{}] Read cancelled.".format("address_client")
+ )
assert task.result() is None
await tcp_client.disconnect()
await tcp_server.disconnect()
@pytest.mark.asyncio
- async def test_receive_raises_struct_error(self, caplog):
+ async def test_receive_raises_struct_error(self):
"""Test the case when a receive raises a struct error."""
port = get_unused_tcp_port()
tcp_server = _make_tcp_server_connection("address_server", "127.0.0.1", port,)
@@ -188,15 +187,13 @@ async def test_receive_raises_struct_error(self, caplog):
await tcp_server.connect()
await tcp_client.connect()
- with caplog.at_level(
- logging.DEBUG, "aea.packages.fetchai.connections.tcp.tcp_client"
- ):
+ with unittest.mock.patch.object(tcp_client.logger, "debug") as mock_logger:
with unittest.mock.patch.object(
tcp_client, "_recv", side_effect=struct.error
):
task = asyncio.ensure_future(tcp_client.receive())
await asyncio.sleep(0.1)
- assert "Struct error: " in caplog.text
+ mock_logger.assert_called_with("Struct error: ")
assert task.result() is None
await tcp_client.disconnect()
@@ -228,7 +225,7 @@ class TestTCPServerConnection:
"""Test TCP Server code."""
@pytest.mark.asyncio
- async def test_receive_raises_exception(self, caplog):
+ async def test_receive_raises_exception(self):
"""Test the case when a receive raises a generic exception."""
port = get_unused_tcp_port()
tcp_server = _make_tcp_server_connection("address_server", "127.0.0.1", port,)
@@ -237,15 +234,16 @@ async def test_receive_raises_exception(self, caplog):
await tcp_server.connect()
await tcp_client.connect()
await asyncio.sleep(0.1)
- with caplog.at_level(
- logging.DEBUG, "aea.packages.fetchai.connections.tcp.tcp_server"
- ):
+
+ with unittest.mock.patch.object(tcp_server.logger, "error") as mock_logger:
with unittest.mock.patch(
"asyncio.wait", side_effect=Exception("generic exception")
):
result = await tcp_server.receive()
assert result is None
- assert "Error in the receiving loop: generic exception" in caplog.text
+ mock_logger.assert_any_call(
+ "Error in the receiving loop: generic exception"
+ )
await tcp_client.disconnect()
await tcp_server.disconnect()
diff --git a/tests/test_packages/test_connections/test_webhook/test_webhook.py b/tests/test_packages/test_connections/test_webhook/test_webhook.py
index dd0da1537d..fa2a11fb38 100644
--- a/tests/test_packages/test_connections/test_webhook/test_webhook.py
+++ b/tests/test_packages/test_connections/test_webhook/test_webhook.py
@@ -19,10 +19,12 @@
"""Tests for the webhook connection and channel."""
import asyncio
+import copy
import json
import logging
from traceback import print_exc
from typing import cast
+from unittest.mock import patch
import aiohttp
from aiohttp.client_reqrep import ClientResponse
@@ -35,8 +37,10 @@
from packages.fetchai.connections.webhook.connection import WebhookConnection
+from packages.fetchai.protocols.http.dialogues import HttpDialogues
from packages.fetchai.protocols.http.message import HttpMessage
+from tests.common.mocks import RegexComparator
from tests.conftest import (
get_host,
get_unused_tcp_port,
@@ -67,6 +71,7 @@ def setup(self):
configuration=configuration, identity=self.identity,
)
self.webhook_connection.loop = self.loop
+ self.dialogues = HttpDialogues(self.identity.address)
async def test_initialization(self):
"""Test the initialisation of the class."""
@@ -76,16 +81,16 @@ async def test_initialization(self):
async def test_connection(self):
"""Test the connect functionality of the webhook connection."""
await self.webhook_connection.connect()
- assert self.webhook_connection.connection_status.is_connected is True
+ assert self.webhook_connection.is_connected is True
@pytest.mark.asyncio
async def test_disconnect(self):
"""Test the disconnect functionality of the webhook connection."""
await self.webhook_connection.connect()
- assert self.webhook_connection.connection_status.is_connected is True
+ assert self.webhook_connection.is_connected is True
await self.webhook_connection.disconnect()
- assert self.webhook_connection.connection_status.is_connected is False
+ assert self.webhook_connection.is_connected is False
def teardown(self):
"""Close connection after testing."""
@@ -99,14 +104,19 @@ def teardown(self):
async def test_receive_post_ok(self):
"""Test the connect functionality of the webhook connection."""
await self.webhook_connection.connect()
- assert self.webhook_connection.connection_status.is_connected is True
+ assert self.webhook_connection.is_connected is True
payload = {"hello": "world"}
call_task = self.loop.create_task(self.call_webhook("test_topic", json=payload))
envelope = await asyncio.wait_for(self.webhook_connection.receive(), timeout=10)
assert envelope
- message = cast(HttpMessage, envelope.message)
+ orig_message = cast(HttpMessage, envelope.message)
+ message = copy.copy(orig_message)
+ message.counterparty = orig_message.sender
+ message.is_incoming = True
+ dialogue = self.dialogues.update(message)
+ assert dialogue is not None
assert message.method.upper() == "POST"
assert message.bodyy.decode("utf-8") == json.dumps(payload)
await call_task
@@ -115,7 +125,7 @@ async def test_receive_post_ok(self):
async def test_send(self):
"""Test the connect functionality of the webhook connection."""
await self.webhook_connection.connect()
- assert self.webhook_connection.connection_status.is_connected is True
+ assert self.webhook_connection.is_connected is True
http_message = HttpMessage(
dialogue_reference=("", ""),
@@ -131,10 +141,17 @@ async def test_send(self):
envelope = Envelope(
to="addr",
sender="my_id",
- protocol_id=PublicId.from_str("fetchai/http:0.3.0"),
+ protocol_id=PublicId.from_str("fetchai/http:0.4.0"),
message=http_message,
)
- await self.webhook_connection.send(envelope)
+ with patch.object(self.webhook_connection.logger, "warning") as mock_logger:
+ await self.webhook_connection.send(envelope)
+ await asyncio.sleep(0.01)
+ mock_logger.assert_any_call(
+ RegexComparator(
+ "Dropping envelope=.* as sending via the webhook is not possible!"
+ )
+ )
async def call_webhook(self, topic: str, **kwargs) -> ClientResponse:
"""
diff --git a/tests/test_packages/test_protocols/test_fipa.py b/tests/test_packages/test_protocols/test_fipa.py
index b34d4862c8..1a8d5be733 100644
--- a/tests/test_packages/test_protocols/test_fipa.py
+++ b/tests/test_packages/test_protocols/test_fipa.py
@@ -369,7 +369,9 @@ def setup_class(cls):
def test_create_self_initiated(self):
"""Test the self initialisation of a dialogue."""
result = self.buyer_dialogues._create_self_initiated(
- dialogue_opponent_addr=self.seller_addr, role=FipaDialogue.Role.SELLER,
+ dialogue_opponent_addr=self.seller_addr,
+ dialogue_reference=(str(0), ""),
+ role=FipaDialogue.Role.SELLER,
)
assert isinstance(result, FipaDialogue)
assert result.role == FipaDialogue.Role.SELLER, "The role must be seller."
diff --git a/tests/test_packages/test_protocols/test_tac.py b/tests/test_packages/test_protocols/test_tac.py
index 16d4a347b2..71a71ebfe6 100644
--- a/tests/test_packages/test_protocols/test_tac.py
+++ b/tests/test_packages/test_protocols/test_tac.py
@@ -34,16 +34,16 @@ def test_tac_message_instantiation():
assert TacMessage(performative=TacMessage.Performative.UNREGISTER)
assert TacMessage(
performative=TacMessage.Performative.TRANSACTION,
- tx_id="some_id",
- tx_sender_addr="some_address",
- tx_counterparty_addr="some_other_address",
+ transaction_id="some_id",
+ ledger_id="some_ledger",
+ sender_address="some_address",
+ counterparty_address="some_other_address",
amount_by_currency_id={"FET": 10},
- tx_sender_fee=10,
- tx_counterparty_fee=10,
+ fee_by_currency_id={"FET": 1},
quantities_by_good_id={"123": 0, "1234": 10},
- tx_nonce=1,
- tx_sender_signature="some_signature",
- tx_counterparty_signature="some_other_signature",
+ nonce=1,
+ sender_signature="some_signature",
+ counterparty_signature="some_other_signature",
)
assert TacMessage(performative=TacMessage.Performative.CANCELLED)
assert TacMessage(
@@ -52,7 +52,7 @@ def test_tac_message_instantiation():
exchange_params_by_currency_id={"FET": 10.0},
quantities_by_good_id={"123": 20, "1234": 15},
utility_params_by_good_id={"123": 30.0, "1234": 50.0},
- tx_fee=20,
+ fee_by_currency_id={"FET": 1},
agent_addr_to_name={"agent_1": "Agent one", "agent_2": "Agent two"},
currency_id_to_name={"FET": "currency_name"},
good_id_to_name={"123": "First good", "1234": "Second good"},
@@ -60,7 +60,7 @@ def test_tac_message_instantiation():
)
assert TacMessage(
performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,
- tx_id="some_id",
+ transaction_id="some_id",
amount_by_currency_id={"FET": 10},
quantities_by_good_id={"123": 20, "1234": 15},
)
@@ -90,16 +90,16 @@ def test_tac_serialization():
msg = TacMessage(
performative=TacMessage.Performative.TRANSACTION,
- tx_id="some_id",
- tx_sender_addr="some_address",
- tx_counterparty_addr="some_other_address",
+ ledger_id="some_ledger",
+ transaction_id="some_id",
+ sender_address="some_address",
+ counterparty_address="some_other_address",
amount_by_currency_id={"FET": -10},
- tx_sender_fee=10,
- tx_counterparty_fee=10,
+ fee_by_currency_id={"FET": 1},
quantities_by_good_id={"123": 0, "1234": 10},
- tx_nonce=1,
- tx_sender_signature="some_signature",
- tx_counterparty_signature="some_other_signature",
+ nonce="1",
+ sender_signature="some_signature",
+ counterparty_signature="some_other_signature",
)
msg_bytes = TacMessage.serializer.encode(msg)
actual_msg = TacMessage.serializer.decode(msg_bytes)
@@ -118,7 +118,7 @@ def test_tac_serialization():
exchange_params_by_currency_id={"FET": 10.0},
quantities_by_good_id={"123": 20, "1234": 15},
utility_params_by_good_id={"123": 30.0, "1234": 50.0},
- tx_fee=20,
+ fee_by_currency_id={"FET": 1},
agent_addr_to_name={"agent_1": "Agent one", "agent_2": "Agent two"},
currency_id_to_name={"FET": "currency_name"},
good_id_to_name={"123": "First good", "1234": "Second good"},
@@ -131,7 +131,7 @@ def test_tac_serialization():
msg = TacMessage(
performative=TacMessage.Performative.TRANSACTION_CONFIRMATION,
- tx_id="some_id",
+ transaction_id="some_id",
amount_by_currency_id={"FET": 10},
quantities_by_good_id={"123": 20, "1234": 15},
)
diff --git a/tests/test_packages/test_skills/test_carpark.py b/tests/test_packages/test_skills/test_carpark.py
index 2ba59aaefb..9b6e4893ca 100644
--- a/tests/test_packages/test_skills/test_carpark.py
+++ b/tests/test_packages/test_skills/test_carpark.py
@@ -19,6 +19,8 @@
"""This test module contains the integration test for the weather skills."""
+from random import uniform
+
import pytest
from aea.test_tools.test_cases import AEATestCaseMany
@@ -26,7 +28,7 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -48,17 +50,23 @@ def test_carpark(self):
self.create_agents(carpark_aea_name, carpark_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# Setup agent one
self.set_agent_context(carpark_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/carpark_detection:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/carpark_detection:0.8.0")
setting_path = (
"vendor.fetchai.skills.carpark_detection.models.strategy.args.is_ledger_tx"
)
@@ -67,21 +75,30 @@ def test_carpark(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.carpark_detection.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
# Setup agent two
self.set_agent_context(carpark_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/carpark_client:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/carpark_client:0.8.0")
setting_path = (
"vendor.fetchai.skills.carpark_client.models.strategy.args.is_ledger_tx"
)
@@ -90,16 +107,24 @@ def test_carpark(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.carpark_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# Fire the sub-processes and the threads.
self.set_agent_context(carpark_aea_name)
carpark_aea_process = self.run_agent()
@@ -195,64 +220,93 @@ def test_carpark(self):
self.create_agents(carpark_aea_name, carpark_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# Setup agent one
self.set_agent_context(carpark_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/carpark_detection:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/carpark_detection:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/car_detector:0.8.0", carpark_aea_name
+ "fetchai/car_detector:0.9.0", carpark_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.carpark_detection.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
# Setup agent two
self.set_agent_context(carpark_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/carpark_client:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/carpark_client:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/car_data_buyer:0.8.0", carpark_client_aea_name
+ "fetchai/car_data_buyer:0.9.0", carpark_client_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+ # self.replace_private_key_in_file(
+ # FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ # )
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.carpark_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# Fire the sub-processes and the threads.
self.set_agent_context(carpark_aea_name)
carpark_aea_process = self.run_agent()
diff --git a/tests/test_packages/test_skills/test_echo.py b/tests/test_packages/test_skills/test_echo.py
index e4ad5f9014..f7afc6e01d 100644
--- a/tests/test_packages/test_skills/test_echo.py
+++ b/tests/test_packages/test_skills/test_echo.py
@@ -34,7 +34,7 @@ class TestEchoSkill(AEATestCaseEmpty):
@skip_test_windows
def test_echo(self):
"""Run the echo skill sequence."""
- self.add_item("skill", "fetchai/echo:0.3.0")
+ self.add_item("skill", "fetchai/echo:0.4.0")
process = self.run_agent()
is_running = self.is_running(process)
diff --git a/tests/test_packages/test_skills/test_erc1155.py b/tests/test_packages/test_skills/test_erc1155.py
index 733a69e995..90b9ca1624 100644
--- a/tests/test_packages/test_skills/test_erc1155.py
+++ b/tests/test_packages/test_skills/test_erc1155.py
@@ -18,20 +18,29 @@
# ------------------------------------------------------------------------------
"""This test module contains the integration test for the generic buyer and seller skills."""
+from random import uniform
+
import pytest
-from aea.test_tools.test_cases import AEATestCaseMany, UseOef
+from aea.test_tools.test_cases import AEATestCaseMany
from tests.conftest import (
+ COSMOS,
+ COSMOS_PRIVATE_KEY_FILE,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
ETHEREUM,
ETHEREUM_PRIVATE_KEY_FILE,
- FUNDED_ETH_PRIVATE_KEY_1,
FUNDED_ETH_PRIVATE_KEY_2,
+ FUNDED_ETH_PRIVATE_KEY_3,
MAX_FLAKY_RERUNS_ETH,
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1,
+ NON_GENESIS_CONFIG,
+ wait_for_localhost_ports_to_close,
)
-class TestERCSkillsEthereumLedger(AEATestCaseMany, UseOef):
+@pytest.mark.integration
+class TestERCSkillsEthereumLedger(AEATestCaseMany):
"""Test that erc1155 skills work."""
@pytest.mark.integration
@@ -46,22 +55,30 @@ def test_generic(self):
# add ethereum ledger in both configuration files
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/contract_api:0.1.0": "fetchai/ledger:0.2.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/contract_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# add packages for agent one
self.set_agent_context(deploy_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
self.set_config("agent.default_ledger", ETHEREUM)
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
- self.add_item("skill", "fetchai/erc1155_deploy:0.9.0")
+ self.add_item("skill", "fetchai/erc1155_deploy:0.10.0")
diff = self.difference_to_fetched_agent(
- "fetchai/erc1155_deployer:0.9.0", deploy_aea_name
+ "fetchai/erc1155_deployer:0.10.0", deploy_aea_name
)
assert (
diff == []
@@ -70,25 +87,43 @@ def test_generic(self):
self.generate_private_key(ETHEREUM)
self.add_private_key(ETHEREUM, ETHEREUM_PRIVATE_KEY_FILE)
self.replace_private_key_in_file(
- FUNDED_ETH_PRIVATE_KEY_1, ETHEREUM_PRIVATE_KEY_FILE
+ FUNDED_ETH_PRIVATE_KEY_3, ETHEREUM_PRIVATE_KEY_FILE
+ )
+ self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
+ self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+ self.replace_private_key_in_file(
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+ setting_path = "vendor.fetchai.connections.soef.config.chain_identifier"
+ self.set_config(setting_path, "ethereum")
# stdout = self.get_wealth(ETHEREUM)
# if int(stdout) < 100000000000000000:
# pytest.skip("The agent needs more funds for the test to pass.")
self.run_install()
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.erc1155_deploy.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# add packages for agent two
self.set_agent_context(client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
self.set_config("agent.default_ledger", ETHEREUM)
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
- self.add_item("skill", "fetchai/erc1155_client:0.8.0")
+ self.add_item("skill", "fetchai/erc1155_client:0.9.0")
diff = self.difference_to_fetched_agent(
- "fetchai/erc1155_client:0.9.0", client_aea_name
+ "fetchai/erc1155_client:0.10.0", client_aea_name
)
assert (
diff == []
@@ -99,15 +134,46 @@ def test_generic(self):
self.replace_private_key_in_file(
FUNDED_ETH_PRIVATE_KEY_2, ETHEREUM_PRIVATE_KEY_FILE
)
+ self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
+ self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
+ setting_path = "vendor.fetchai.connections.soef.config.chain_identifier"
+ self.set_config(setting_path, "ethereum")
+ setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
+ self.force_set_config(setting_path, NON_GENESIS_CONFIG)
# stdout = self.get_wealth(ETHEREUM)
# if int(stdout) < 100000000000000000:
# pytest.skip("The agent needs more funds for the test to pass.")
self.run_install()
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.erc1155_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run agents
self.set_agent_context(deploy_aea_name)
deploy_aea_process = self.run_agent()
+ check_strings = (
+ "Downloading golang dependencies. This may take a while...",
+ "Finished downloading golang dependencies.",
+ "Starting libp2p node...",
+ "Connecting to libp2p node...",
+ "Successfully connected to libp2p node!",
+ "My libp2p addresses:",
+ )
+ missing_strings = self.missing_from_output(
+ deploy_aea_process, check_strings, timeout=240, is_terminating=False
+ )
+ assert (
+ missing_strings == []
+ ), "Strings {} didn't appear in deploy_aea output.".format(missing_strings)
+
check_strings = (
"starting balance on ethereum ledger=",
"received raw transaction=",
@@ -117,8 +183,10 @@ def test_generic(self):
"transaction was successfully submitted. Transaction digest=",
"requesting transaction receipt.",
"transaction was successfully settled. Transaction receipt=",
- "Requesting create batch transaction...",
- "Requesting mint batch transaction...",
+ "requesting create batch transaction...",
+ "requesting mint batch transaction...",
+ "registering agent on SOEF.",
+ "registering service on SOEF.",
)
missing_strings = self.missing_from_output(
deploy_aea_process, check_strings, timeout=420, is_terminating=False
@@ -131,9 +199,25 @@ def test_generic(self):
client_aea_process = self.run_agent()
check_strings = (
- "Sending PROPOSE to agent=",
+ "Downloading golang dependencies. This may take a while...",
+ "Finished downloading golang dependencies.",
+ "Starting libp2p node...",
+ "Connecting to libp2p node...",
+ "Successfully connected to libp2p node!",
+ "My libp2p addresses:",
+ )
+ missing_strings = self.missing_from_output(
+ client_aea_process, check_strings, timeout=240, is_terminating=False
+ )
+ assert (
+ missing_strings == []
+ ), "Strings {} didn't appear in client_aea output.".format(missing_strings)
+
+ check_strings = (
+ "received CFP from sender=",
+ "sending PROPOSE to agent=",
"received ACCEPT_W_INFORM from sender=",
- "Requesting single atomic swap transaction...",
+ "requesting single atomic swap transaction...",
"received raw transaction=",
"proposing the transaction to the decision maker. Waiting for confirmation ...",
"transaction signing was successful.",
@@ -141,7 +225,7 @@ def test_generic(self):
"transaction was successfully submitted. Transaction digest=",
"requesting transaction receipt.",
"transaction was successfully settled. Transaction receipt=",
- "Demo finished!",
+ "demo finished!",
)
missing_strings = self.missing_from_output(
deploy_aea_process, check_strings, timeout=360, is_terminating=False
@@ -170,3 +254,4 @@ def test_generic(self):
assert (
self.is_successfully_terminated()
), "Agents weren't successfully terminated."
+ wait_for_localhost_ports_to_close([9000, 9001])
diff --git a/tests/test_packages/test_skills/test_generic.py b/tests/test_packages/test_skills/test_generic.py
index b5d6b33716..f44c07d10f 100644
--- a/tests/test_packages/test_skills/test_generic.py
+++ b/tests/test_packages/test_skills/test_generic.py
@@ -17,6 +17,9 @@
#
# ------------------------------------------------------------------------------
"""This test module contains the integration test for the generic buyer and seller skills."""
+
+from random import uniform
+
import pytest
from aea.test_tools.test_cases import AEATestCaseMany
@@ -24,7 +27,7 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -46,17 +49,23 @@ def test_generic(self, pytestconfig):
self.create_agents(seller_aea_name, buyer_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# prepare seller agent
self.set_agent_context(seller_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/generic_seller:0.8.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/generic_seller:0.9.0")
setting_path = (
"vendor.fetchai.skills.generic_seller.models.strategy.args.is_ledger_tx"
)
@@ -65,25 +74,34 @@ def test_generic(self, pytestconfig):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
# make runable:
setting_path = "vendor.fetchai.skills.generic_seller.is_abstract"
self.set_config(setting_path, False, "bool")
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.generic_seller.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# prepare buyer agent
self.set_agent_context(buyer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/generic_buyer:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/generic_buyer:0.8.0")
setting_path = (
"vendor.fetchai.skills.generic_buyer.models.strategy.args.is_ledger_tx"
)
@@ -92,13 +110,15 @@ def test_generic(self, pytestconfig):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
@@ -106,6 +126,12 @@ def test_generic(self, pytestconfig):
setting_path = "vendor.fetchai.skills.generic_buyer.is_abstract"
self.set_config(setting_path, False, "bool")
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.generic_buyer.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run AEAs
self.set_agent_context(seller_aea_name)
seller_aea_process = self.run_agent()
@@ -198,53 +224,68 @@ def test_generic(self, pytestconfig):
self.create_agents(seller_aea_name, buyer_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# prepare seller agent
self.set_agent_context(seller_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/generic_seller:0.8.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/generic_seller:0.9.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/generic_seller:0.5.0", seller_aea_name
+ "fetchai/generic_seller:0.6.0", seller_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
# make runable:
setting_path = "vendor.fetchai.skills.generic_seller.is_abstract"
self.set_config(setting_path, False, "bool")
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.generic_seller.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# prepare buyer agent
self.set_agent_context(buyer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/generic_buyer:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/generic_buyer:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/generic_buyer:0.5.0", buyer_aea_name
+ "fetchai/generic_buyer:0.6.0", buyer_aea_name
)
assert (
diff == []
@@ -253,16 +294,27 @@ def test_generic(self, pytestconfig):
setting_path = "vendor.fetchai.skills.generic_buyer.is_abstract"
self.set_config(setting_path, False, "bool")
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.generic_buyer.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run AEAs
self.set_agent_context(seller_aea_name)
seller_aea_process = self.run_agent()
diff --git a/tests/test_packages/test_skills/test_gym.py b/tests/test_packages/test_skills/test_gym.py
index 661a7261c1..f505cd4548 100644
--- a/tests/test_packages/test_skills/test_gym.py
+++ b/tests/test_packages/test_skills/test_gym.py
@@ -33,16 +33,16 @@ class TestGymSkill(AEATestCaseEmpty):
@skip_test_windows
def test_gym(self):
"""Run the gym skill sequence."""
- self.add_item("skill", "fetchai/gym:0.4.0")
- self.add_item("connection", "fetchai/gym:0.4.0")
+ self.add_item("skill", "fetchai/gym:0.5.0")
+ self.add_item("connection", "fetchai/gym:0.5.0")
self.run_install()
# change default connection
setting_path = "agent.default_connection"
- self.set_config(setting_path, "fetchai/gym:0.4.0")
+ self.set_config(setting_path, "fetchai/gym:0.5.0")
diff = self.difference_to_fetched_agent(
- "fetchai/gym_aea:0.6.0", self.agent_name
+ "fetchai/gym_aea:0.7.0", self.agent_name
)
assert (
diff == []
diff --git a/tests/test_packages/test_skills/test_http_echo.py b/tests/test_packages/test_skills/test_http_echo.py
index 4a0c8fdf14..0e8ef1d48a 100644
--- a/tests/test_packages/test_skills/test_http_echo.py
+++ b/tests/test_packages/test_skills/test_http_echo.py
@@ -36,9 +36,9 @@ class TestHttpEchoSkill(AEATestCaseEmpty):
@skip_test_windows
def test_echo(self):
"""Run the echo skill sequence."""
- self.add_item("connection", "fetchai/http_server:0.5.0")
- self.add_item("skill", "fetchai/http_echo:0.3.0")
- self.set_config("agent.default_connection", "fetchai/http_server:0.5.0")
+ self.add_item("connection", "fetchai/http_server:0.6.0")
+ self.add_item("skill", "fetchai/http_echo:0.4.0")
+ self.set_config("agent.default_connection", "fetchai/http_server:0.6.0")
self.set_config(
"vendor.fetchai.connections.http_server.config.api_spec_path", API_SPEC_PATH
)
diff --git a/tests/test_packages/test_skills/test_ml_skills.py b/tests/test_packages/test_skills/test_ml_skills.py
index 6c86801cca..f18d3f6149 100644
--- a/tests/test_packages/test_skills/test_ml_skills.py
+++ b/tests/test_packages/test_skills/test_ml_skills.py
@@ -20,6 +20,7 @@
"""This test module contains the integration test for the weather skills."""
import sys
+from random import uniform
import pytest
@@ -28,7 +29,7 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -36,6 +37,15 @@
)
+def _is_not_tensorflow_installed():
+ try:
+ import tensorflow # noqa
+
+ return False
+ except ImportError:
+ return True
+
+
@pytest.mark.integration
class TestMLSkills(AEATestCaseMany):
"""Test that ml skills work."""
@@ -44,8 +54,7 @@ class TestMLSkills(AEATestCaseMany):
reruns=MAX_FLAKY_RERUNS_INTEGRATION
) # cause possible network issues
@pytest.mark.skipif(
- sys.version_info >= (3, 8),
- reason="cannot run on 3.8 as tensorflow not installable",
+ _is_not_tensorflow_installed(), reason="This test requires Tensorflow.",
)
def test_ml_skills(self, pytestconfig):
"""Run the ml skills sequence."""
@@ -54,17 +63,23 @@ def test_ml_skills(self, pytestconfig):
self.create_agents(data_provider_aea_name, model_trainer_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# prepare data provider agent
self.set_agent_context(data_provider_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/ml_data_provider:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/ml_data_provider:0.8.0")
setting_path = (
"vendor.fetchai.skills.ml_data_provider.models.strategy.args.is_ledger_tx"
)
@@ -73,21 +88,30 @@ def test_ml_skills(self, pytestconfig):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.ml_data_provider.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
# prepare model trainer agent
self.set_agent_context(model_trainer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/ml_train:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/ml_train:0.8.0")
setting_path = (
"vendor.fetchai.skills.ml_train.models.strategy.args.is_ledger_tx"
)
@@ -96,16 +120,22 @@ def test_ml_skills(self, pytestconfig):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = "vendor.fetchai.skills.ml_train.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
self.set_agent_context(data_provider_aea_name)
data_provider_aea_process = self.run_agent()
@@ -205,64 +235,88 @@ def test_ml_skills(self, pytestconfig):
self.create_agents(data_provider_aea_name, model_trainer_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# prepare data provider agent
self.set_agent_context(data_provider_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/ml_data_provider:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/ml_data_provider:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/ml_data_provider:0.8.0", data_provider_aea_name
+ "fetchai/ml_data_provider:0.9.0", data_provider_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.ml_data_provider.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
# prepare model trainer agent
self.set_agent_context(model_trainer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/ml_train:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/ml_train:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/ml_model_trainer:0.8.0", model_trainer_aea_name
+ "fetchai/ml_model_trainer:0.9.0", model_trainer_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = "vendor.fetchai.skills.ml_train.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
self.set_agent_context(data_provider_aea_name)
data_provider_aea_process = self.run_agent()
diff --git a/tests/test_packages/test_skills/test_tac.py b/tests/test_packages/test_skills/test_tac.py
index fba245eda2..dbf5c299b5 100644
--- a/tests/test_packages/test_skills/test_tac.py
+++ b/tests/test_packages/test_skills/test_tac.py
@@ -53,14 +53,14 @@ def test_tac(self):
# prepare tac controller for test
self.set_agent_context(tac_controller_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("skill", "fetchai/tac_control:0.3.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("skill", "fetchai/tac_control:0.4.0")
self.set_config("agent.default_ledger", ETHEREUM)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/tac_controller:0.5.0", tac_controller_name
+ "fetchai/tac_controller:0.6.0", tac_controller_name
)
assert (
diff == []
@@ -69,14 +69,14 @@ def test_tac(self):
# prepare agents for test
for agent_name in (tac_aea_one, tac_aea_two):
self.set_agent_context(agent_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("skill", "fetchai/tac_participation:0.4.0")
- self.add_item("skill", "fetchai/tac_negotiation:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("skill", "fetchai/tac_participation:0.5.0")
+ self.add_item("skill", "fetchai/tac_negotiation:0.6.0")
self.set_config("agent.default_ledger", ETHEREUM)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/tac_participant:0.6.0", agent_name
+ "fetchai/tac_participant:0.7.0", agent_name
)
assert (
diff == []
@@ -95,18 +95,18 @@ def test_tac(self):
)
self.set_config(setting_path, start_time)
tac_controller_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
# run two agents (participants)
self.set_agent_context(tac_aea_one)
tac_aea_one_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
self.set_agent_context(tac_aea_two)
tac_aea_two_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
check_strings = (
@@ -179,9 +179,9 @@ def test_tac(self):
# prepare tac controller for test
self.set_agent_context(tac_controller_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("skill", "fetchai/tac_control_contract:0.4.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("skill", "fetchai/tac_control_contract:0.5.0")
self.set_config("agent.default_ledger", ETHEREUM)
# stdout = self.get_wealth(ETHEREUM)
# if int(stdout) < 100000000000000000:
@@ -189,7 +189,7 @@ def test_tac(self):
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/tac_controller_contract:0.6.0", tac_controller_name
+ "fetchai/tac_controller_contract:0.7.0", tac_controller_name
)
assert (
diff == []
@@ -207,10 +207,10 @@ def test_tac(self):
(FUNDED_ETH_PRIVATE_KEY_2, FUNDED_ETH_PRIVATE_KEY_3),
):
self.set_agent_context(agent_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("skill", "fetchai/tac_participation:0.4.0")
- self.add_item("skill", "fetchai/tac_negotiation:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("skill", "fetchai/tac_participation:0.5.0")
+ self.add_item("skill", "fetchai/tac_negotiation:0.6.0")
self.set_config("agent.default_ledger", ETHEREUM)
self.set_config(
"vendor.fetchai.skills.tac_participation.models.game.args.is_using_contract",
@@ -224,7 +224,7 @@ def test_tac(self):
)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/tac_participant:0.6.0", agent_name
+ "fetchai/tac_participant:0.7.0", agent_name
)
assert (
diff == []
@@ -244,7 +244,7 @@ def test_tac(self):
setting_path = "vendor.fetchai.skills.tac_control_contract.models.parameters.args.start_time"
self.set_config(setting_path, start_time)
tac_controller_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
check_strings = (
@@ -264,12 +264,12 @@ def test_tac(self):
# run two participants as well
self.set_agent_context(tac_aea_one)
tac_aea_one_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
self.set_agent_context(tac_aea_two)
tac_aea_two_process = self.run_agent(
- "--connections", "fetchai/p2p_libp2p:0.5.0"
+ "--connections", "fetchai/p2p_libp2p:0.6.0"
)
check_strings = (
diff --git a/tests/test_packages/test_skills/test_thermometer.py b/tests/test_packages/test_skills/test_thermometer.py
index 8ae7876803..d1d8923cde 100644
--- a/tests/test_packages/test_skills/test_thermometer.py
+++ b/tests/test_packages/test_skills/test_thermometer.py
@@ -17,6 +17,9 @@
#
# ------------------------------------------------------------------------------
"""This test module contains the integration test for the thermometer skills."""
+
+from random import uniform
+
import pytest
from aea.test_tools.test_cases import AEATestCaseMany
@@ -24,7 +27,7 @@
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -47,17 +50,23 @@ def test_thermometer(self):
self.create_agents(thermometer_aea_name, thermometer_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# add packages for agent one and run it
self.set_agent_context(thermometer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer:0.8.0")
setting_path = (
"vendor.fetchai.skills.thermometer.models.strategy.args.is_ledger_tx"
)
@@ -66,21 +75,28 @@ def test_thermometer(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
+ # replace location
+ setting_path = "vendor.fetchai.skills.thermometer.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
# add packages for agent two and run it
self.set_agent_context(thermometer_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer_client:0.6.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer_client:0.7.0")
setting_path = (
"vendor.fetchai.skills.thermometer_client.models.strategy.args.is_ledger_tx"
)
@@ -89,16 +105,24 @@ def test_thermometer(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.thermometer_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run AEAs
self.set_agent_context(thermometer_aea_name)
thermometer_aea_process = self.run_agent()
@@ -198,64 +222,88 @@ def test_thermometer(self):
self.create_agents(thermometer_aea_name, thermometer_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# add packages for agent one and run it
self.set_agent_context(thermometer_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/thermometer_aea:0.6.0", thermometer_aea_name
+ "fetchai/thermometer_aea:0.7.0", thermometer_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
+ # replace location
+ setting_path = "vendor.fetchai.skills.thermometer.models.strategy.args.location"
+ self.force_set_config(setting_path, location)
+
# add packages for agent two and run it
self.set_agent_context(thermometer_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/thermometer_client:0.6.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/thermometer_client:0.7.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/thermometer_client:0.6.0", thermometer_client_aea_name
+ "fetchai/thermometer_client:0.7.0", thermometer_client_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.thermometer_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run AEAs
self.set_agent_context(thermometer_aea_name)
thermometer_aea_process = self.run_agent()
diff --git a/tests/test_packages/test_skills/test_weather.py b/tests/test_packages/test_skills/test_weather.py
index b6d1a3b1f9..a0b8d2b06e 100644
--- a/tests/test_packages/test_skills/test_weather.py
+++ b/tests/test_packages/test_skills/test_weather.py
@@ -17,15 +17,17 @@
#
# ------------------------------------------------------------------------------
"""This test module contains the integration test for the weather skills."""
-import pytest
+from random import uniform
+
+import pytest
from aea.test_tools.test_cases import AEATestCaseMany
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_FILE,
- FUNDED_COSMOS_PRIVATE_KEY_1,
+ COSMOS_PRIVATE_KEY_FILE_CONNECTION,
MAX_FLAKY_RERUNS_INTEGRATION,
NON_FUNDED_COSMOS_PRIVATE_KEY_1,
NON_GENESIS_CONFIG,
@@ -47,18 +49,24 @@ def test_weather(self):
self.create_agents(weather_station_aea_name, weather_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# prepare agent one (weather station)
self.set_agent_context(weather_station_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/weather_station:0.7.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/weather_station:0.8.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
dotted_path = (
"vendor.fetchai.skills.weather_station.models.strategy.args.is_ledger_tx"
)
@@ -67,22 +75,31 @@ def test_weather(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.weather_station.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# prepare agent two (weather client)
self.set_agent_context(weather_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/weather_client:0.6.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/weather_client:0.7.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
dotted_path = (
"vendor.fetchai.skills.weather_client.models.strategy.args.is_ledger_tx"
)
@@ -91,16 +108,24 @@ def test_weather(self):
self.force_set_config(setting_path, default_routing)
self.run_install()
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.weather_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
# run agents
self.set_agent_context(weather_station_aea_name)
weather_station_process = self.run_agent()
@@ -192,64 +217,90 @@ def test_weather(self):
self.create_agents(weather_station_aea_name, weather_client_aea_name)
default_routing = {
- "fetchai/ledger_api:0.1.0": "fetchai/ledger:0.2.0",
- "fetchai/oef_search:0.3.0": "fetchai/soef:0.5.0",
+ "fetchai/ledger_api:0.2.0": "fetchai/ledger:0.3.0",
+ "fetchai/oef_search:0.4.0": "fetchai/soef:0.6.0",
+ }
+
+ # generate random location
+ location = {
+ "latitude": round(uniform(-90, 90), 2), # nosec
+ "longitude": round(uniform(-180, 180), 2), # nosec
}
# add packages for agent one
self.set_agent_context(weather_station_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/weather_station:0.7.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/weather_station:0.8.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/weather_station:0.8.0", weather_station_aea_name
+ "fetchai/weather_station:0.9.0", weather_station_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add non-funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
+ )
self.replace_private_key_in_file(
- NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ NON_FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE_CONNECTION
+ )
+
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.weather_station.models.strategy.args.location"
)
+ self.force_set_config(setting_path, location)
# add packages for agent two
self.set_agent_context(weather_client_aea_name)
- self.add_item("connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/soef:0.5.0")
- self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.5.0")
- self.add_item("connection", "fetchai/ledger:0.2.0")
- self.add_item("skill", "fetchai/weather_client:0.6.0")
+ self.add_item("connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/soef:0.6.0")
+ self.set_config("agent.default_connection", "fetchai/p2p_libp2p:0.6.0")
+ self.add_item("connection", "fetchai/ledger:0.3.0")
+ self.add_item("skill", "fetchai/weather_client:0.7.0")
setting_path = "agent.default_routing"
self.force_set_config(setting_path, default_routing)
self.run_install()
diff = self.difference_to_fetched_agent(
- "fetchai/weather_client:0.8.0", weather_client_aea_name
+ "fetchai/weather_client:0.9.0", weather_client_aea_name
)
assert (
diff == []
), "Difference between created and fetched project for files={}".format(diff)
- # add funded key
+ # add keys
self.generate_private_key(COSMOS)
+ self.generate_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION)
self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE)
- self.add_private_key(COSMOS, COSMOS_PRIVATE_KEY_FILE, connection=True)
- self.replace_private_key_in_file(
- FUNDED_COSMOS_PRIVATE_KEY_1, COSMOS_PRIVATE_KEY_FILE
+ self.add_private_key(
+ COSMOS, COSMOS_PRIVATE_KEY_FILE_CONNECTION, connection=True
)
+
+ # fund key
+ self.generate_wealth(COSMOS)
+
+ # set p2p configs
setting_path = "vendor.fetchai.connections.p2p_libp2p.config"
self.force_set_config(setting_path, NON_GENESIS_CONFIG)
+ # replace location
+ setting_path = (
+ "vendor.fetchai.skills.weather_client.models.strategy.args.location"
+ )
+ self.force_set_config(setting_path, location)
+
self.set_agent_context(weather_station_aea_name)
weather_station_process = self.run_agent()
diff --git a/tests/test_protocols/test_base.py b/tests/test_protocols/test_base.py
index 1f57cbb92d..e983a62cbb 100644
--- a/tests/test_protocols/test_base.py
+++ b/tests/test_protocols/test_base.py
@@ -32,6 +32,25 @@
from tests.conftest import UNKNOWN_PROTOCOL_PUBLIC_ID
+class TestMessageProperties:
+ """Test that the base serializations work."""
+
+ @classmethod
+ def setup_class(cls):
+ cls.body = {"body_1": "1", "body_2": "2"}
+ cls.kwarg = 1
+ cls.message = Message(cls.body, kwarg=cls.kwarg)
+
+ def test_message_properties(self):
+ for key, value in self.body.items():
+ assert self.message.get(key) == value
+ assert self.message.get("kwarg") == self.kwarg
+ assert not self.message.has_sender
+ assert not self.message.has_counterparty
+ assert not self.message.has_to
+ assert not self.message.is_incoming
+
+
class TestBaseSerializations:
"""Test that the base serializations work."""
diff --git a/tests/test_protocols/test_generator.py b/tests/test_protocols/test_generator.py
deleted file mode 100644
index ae8d6a3b33..0000000000
--- a/tests/test_protocols/test_generator.py
+++ /dev/null
@@ -1,571 +0,0 @@
-# -*- coding: utf-8 -*-
-# ------------------------------------------------------------------------------
-#
-# Copyright 2018-2019 Fetch.AI Limited
-#
-# 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 tests for the protocol generator."""
-
-import inspect
-import logging
-import os
-import shutil
-import tempfile
-import time
-from pathlib import Path
-from threading import Thread
-from typing import Optional
-from unittest import TestCase, mock
-
-import pytest
-
-from aea.aea_builder import AEABuilder
-from aea.configurations.base import (
- ComponentType,
- ProtocolId,
- ProtocolSpecificationParseError,
- PublicId,
- SkillConfig,
-)
-from aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE
-from aea.crypto.helpers import create_private_key
-from aea.mail.base import Envelope
-from aea.protocols.base import Message
-from aea.protocols.generator.base import (
- ProtocolGenerator,
- _union_sub_type_to_protobuf_variable_name,
-)
-from aea.protocols.generator.common import check_prerequisites
-from aea.protocols.generator.extract_specification import (
- _specification_type_to_python_type,
-)
-from aea.skills.base import Handler, Skill, SkillContext
-from aea.test_tools.test_cases import UseOef
-
-from tests.conftest import CliRunner, ROOT_DIR
-from tests.data.generator.t_protocol.message import ( # type: ignore
- TProtocolMessage,
-)
-
-
-logger = logging.getLogger("aea")
-logging.basicConfig(level=logging.INFO)
-
-CUR_PATH = os.path.dirname(inspect.getfile(inspect.currentframe())) # type: ignore
-HOST = "127.0.0.1"
-PORT = 10000
-
-
-class TestEndToEndGenerator(UseOef):
- """Test that the generating a protocol works correctly in correct preconditions."""
-
- @classmethod
- def setup_class(cls):
- """Set the test up."""
- cls.runner = CliRunner()
- cls.cwd = os.getcwd()
- cls.t = tempfile.mkdtemp()
- os.chdir(cls.t)
- cls.private_key_path_1 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + "_1")
- cls.private_key_path_2 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + "_2")
- create_private_key(DEFAULT_LEDGER, cls.private_key_path_1)
- create_private_key(DEFAULT_LEDGER, cls.private_key_path_2)
-
- def test_compare_latest_generator_output_with_test_protocol(self):
- """Test that the "t_protocol" test protocol matches with what the latest generator generates based on the specification."""
- # Skip if prerequisite applications are not installed
- try:
- check_prerequisites()
- except FileNotFoundError:
- pytest.skip(
- "Some prerequisite applications are not installed. Skipping this test."
- )
-
- # Specification
- # protocol_name = "t_protocol"
- path_to_specification = os.path.join(
- ROOT_DIR, "tests", "data", "sample_specification.yaml"
- )
- path_to_generated_protocol = self.t
- # path_to_original_protocol = os.path.join(
- # ROOT_DIR, "tests", "data", "generator", protocol_name
- # )
- path_to_package = "tests.data.generator."
-
- # Generate the protocol
- protocol_generator = ProtocolGenerator(
- path_to_specification,
- path_to_generated_protocol,
- path_to_protocol_package=path_to_package,
- )
- protocol_generator.generate()
-
- # # compare __init__.py
- # init_file_generated = Path(self.t, protocol_name, "__init__.py")
- # init_file_original = Path(path_to_original_protocol, "__init__.py",)
- # assert filecmp.cmp(init_file_generated, init_file_original)
-
- # # compare protocol.yaml
- # protocol_yaml_file_generated = Path(self.t, protocol_name, "protocol.yaml")
- # protocol_yaml_file_original = Path(path_to_original_protocol, "protocol.yaml",)
- # assert filecmp.cmp(protocol_yaml_file_generated, protocol_yaml_file_original)
-
- # # compare message.py
- # message_file_generated = Path(self.t, protocol_name, "message.py")
- # message_file_original = Path(path_to_original_protocol, "message.py",)
- # assert filecmp.cmp(message_file_generated, message_file_original)
-
- # # compare serialization.py
- # serialization_file_generated = Path(self.t, protocol_name, "serialization.py")
- # serialization_file_original = Path(
- # path_to_original_protocol, "serialization.py",
- # )
- # assert filecmp.cmp(serialization_file_generated, serialization_file_original)
-
- # # compare .proto
- # proto_file_generated = Path(
- # self.t, protocol_name, "{}.proto".format(protocol_name)
- # )
- # proto_file_original = Path(
- # path_to_original_protocol, "{}.proto".format(protocol_name),
- # )
- # assert filecmp.cmp(proto_file_generated, proto_file_original)
-
- # # compare _pb2.py
- # pb2_file_generated = Path(
- # self.t, protocol_name, "{}_pb2.py".format(protocol_name)
- # )
- # with open(ROOT_DIR + "/x_pb2.py", "w") as fp:
- # fp.write(pb2_file_generated.read_text())
- # pb2_file_original = Path(
- # path_to_original_protocol, "{}_pb2.py".format(protocol_name),
- # )
- # assert filecmp.cmp(pb2_file_generated, pb2_file_original)
- assert True
-
- def test_generated_protocol_serialisation_ct(self):
- """Test that a generated protocol's serialisation + deserialisation work correctly."""
- # create a message with pt content
- some_dict = {1: True, 2: False, 3: True, 4: False}
- data_model = TProtocolMessage.DataModel(
- bytes_field=b"some bytes",
- int_field=42,
- float_field=42.7,
- bool_field=True,
- str_field="some string",
- set_field={1, 2, 3, 4, 5},
- list_field=["some string 1", "some string 2"],
- dict_field=some_dict,
- )
- message = TProtocolMessage(
- message_id=1,
- dialogue_reference=(str(0), ""),
- target=0,
- performative=TProtocolMessage.Performative.PERFORMATIVE_CT,
- content_ct=data_model,
- )
-
- # serialise the message
- encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
-
- # deserialise the message
- decoded_message = TProtocolMessage.serializer.decode(encoded_message_in_bytes)
-
- # Compare the original message with the serialised+deserialised message
- assert decoded_message.message_id == message.message_id
- assert decoded_message.dialogue_reference == message.dialogue_reference
- assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
- assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
- assert decoded_message.target == message.target
- assert decoded_message.performative == message.performative
- assert decoded_message.content_ct == message.content_ct
-
- def test_generated_protocol_serialisation_pt(self):
- """Test that a generated protocol's serialisation + deserialisation work correctly."""
- # create a message with pt content
- message = TProtocolMessage(
- message_id=1,
- dialogue_reference=(str(0), ""),
- target=0,
- performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
- content_bytes=b"some bytes",
- content_int=42,
- content_float=42.7,
- content_bool=True,
- content_str="some string",
- )
-
- # serialise the message
- encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
-
- # deserialise the message
- decoded_message = TProtocolMessage.serializer.decode(encoded_message_in_bytes)
-
- # Compare the original message with the serialised+deserialised message
- assert decoded_message.message_id == message.message_id
- assert decoded_message.dialogue_reference == message.dialogue_reference
- assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
- assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
- assert decoded_message.target == message.target
- assert decoded_message.performative == message.performative
- assert decoded_message.content_bytes == message.content_bytes
- assert decoded_message.content_int == message.content_int
- # floats do not seem to lose some precision when serialised then deserialised using protobuf
- # assert decoded_message.content_float == message.content_float
- assert decoded_message.content_bool == message.content_bool
- assert decoded_message.content_str == message.content_str
-
- def test_generated_protocol_end_to_end(self):
- """Test that a generated protocol could be used in exchanging messages between two agents."""
- agent_name_1 = "my_aea_1"
- agent_name_2 = "my_aea_2"
- builder_1 = AEABuilder()
- builder_1.set_name(agent_name_1)
- builder_1.add_private_key(DEFAULT_LEDGER, self.private_key_path_1)
- builder_1.set_default_ledger(DEFAULT_LEDGER)
- builder_1.set_default_connection(PublicId.from_str("fetchai/oef:0.6.0"))
- builder_1.add_protocol(
- Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
- )
- builder_1.add_protocol(
- Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
- )
- builder_1.add_component(
- ComponentType.PROTOCOL,
- Path(ROOT_DIR, "tests", "data", "generator", "t_protocol"),
- skip_consistency_check=True,
- )
- builder_1.add_connection(
- Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
- )
-
- builder_2 = AEABuilder()
- builder_2.set_name(agent_name_2)
- builder_2.add_private_key(DEFAULT_LEDGER, self.private_key_path_2)
- builder_2.set_default_ledger(DEFAULT_LEDGER)
- builder_2.add_protocol(
- Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
- )
- builder_2.add_protocol(
- Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
- )
- builder_2.set_default_connection(PublicId.from_str("fetchai/oef:0.6.0"))
- builder_2.add_component(
- ComponentType.PROTOCOL,
- Path(ROOT_DIR, "tests", "data", "generator", "t_protocol"),
- skip_consistency_check=True,
- )
- builder_2.add_connection(
- Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
- )
-
- # create AEAs
- aea_1 = builder_1.build(connection_ids=[PublicId.from_str("fetchai/oef:0.6.0")])
- aea_2 = builder_2.build(connection_ids=[PublicId.from_str("fetchai/oef:0.6.0")])
-
- # message 1
- message = TProtocolMessage(
- message_id=1,
- dialogue_reference=(str(0), ""),
- target=0,
- performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
- content_bytes=b"some bytes",
- content_int=42,
- content_float=42.7,
- content_bool=True,
- content_str="some string",
- )
- message.counterparty = aea_2.identity.address
- envelope = Envelope(
- to=aea_2.identity.address,
- sender=aea_1.identity.address,
- protocol_id=TProtocolMessage.protocol_id,
- message=message,
- )
-
- # message 2
- message_2 = TProtocolMessage(
- message_id=2,
- dialogue_reference=(str(0), ""),
- target=1,
- performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
- content_bytes=b"some other bytes",
- content_int=43,
- content_float=43.7,
- content_bool=False,
- content_str="some other string",
- )
- message_2.counterparty = aea_1.identity.address
-
- # add handlers to AEA resources]
- skill_context_1 = SkillContext(aea_1.context)
- skill_1 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_1)
- skill_context_1._skill = skill_1
-
- agent_1_handler = Agent1Handler(
- skill_context=skill_context_1, name="fake_handler_1"
- )
- aea_1.resources._handler_registry.register(
- (
- PublicId.from_str("fetchai/fake_skill:0.1.0"),
- TProtocolMessage.protocol_id,
- ),
- agent_1_handler,
- )
- skill_context_2 = SkillContext(aea_2.context)
- skill_2 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_2)
- skill_context_2._skill = skill_2
-
- agent_2_handler = Agent2Handler(
- message=message_2, skill_context=skill_context_2, name="fake_handler_2",
- )
- aea_2.resources._handler_registry.register(
- (
- PublicId.from_str("fetchai/fake_skill:0.1.0"),
- TProtocolMessage.protocol_id,
- ),
- agent_2_handler,
- )
-
- # Start threads
- t_1 = Thread(target=aea_1.start)
- t_2 = Thread(target=aea_2.start)
- try:
- t_1.start()
- t_2.start()
- time.sleep(1.0)
- aea_1.outbox.put(envelope)
- time.sleep(5.0)
- assert (
- agent_2_handler.handled_message.message_id == message.message_id
- ), "Message from Agent 1 to 2: message ids do not match"
- assert (
- agent_2_handler.handled_message.dialogue_reference
- == message.dialogue_reference
- ), "Message from Agent 1 to 2: dialogue references do not match"
- assert (
- agent_2_handler.handled_message.dialogue_reference[0]
- == message.dialogue_reference[0]
- ), "Message from Agent 1 to 2: dialogue reference[0]s do not match"
- assert (
- agent_2_handler.handled_message.dialogue_reference[1]
- == message.dialogue_reference[1]
- ), "Message from Agent 1 to 2: dialogue reference[1]s do not match"
- assert (
- agent_2_handler.handled_message.target == message.target
- ), "Message from Agent 1 to 2: targets do not match"
- assert (
- agent_2_handler.handled_message.performative == message.performative
- ), "Message from Agent 1 to 2: performatives do not match"
- assert (
- agent_2_handler.handled_message.content_bytes == message.content_bytes
- ), "Message from Agent 1 to 2: content_bytes do not match"
- assert (
- agent_2_handler.handled_message.content_int == message.content_int
- ), "Message from Agent 1 to 2: content_int do not match"
- # floats do not seem to lose some precision when serialised then deserialised using protobuf
- # assert agent_2_handler.handled_message.content_float == message.content_float, "Message from Agent 1 to 2: content_float do not match"
- assert (
- agent_2_handler.handled_message.content_bool == message.content_bool
- ), "Message from Agent 1 to 2: content_bool do not match"
- assert (
- agent_2_handler.handled_message.content_str == message.content_str
- ), "Message from Agent 1 to 2: content_str do not match"
-
- assert (
- agent_1_handler.handled_message.message_id == message_2.message_id
- ), "Message from Agent 1 to 2: dialogue references do not match"
- assert (
- agent_1_handler.handled_message.dialogue_reference
- == message_2.dialogue_reference
- ), "Message from Agent 2 to 1: dialogue references do not match"
- assert (
- agent_1_handler.handled_message.dialogue_reference[0]
- == message_2.dialogue_reference[0]
- ), "Message from Agent 2 to 1: dialogue reference[0]s do not match"
- assert (
- agent_1_handler.handled_message.dialogue_reference[1]
- == message_2.dialogue_reference[1]
- ), "Message from Agent 2 to 1: dialogue reference[1]s do not match"
- assert (
- agent_1_handler.handled_message.target == message_2.target
- ), "Message from Agent 2 to 1: targets do not match"
- assert (
- agent_1_handler.handled_message.performative == message_2.performative
- ), "Message from Agent 2 to 1: performatives do not match"
- assert (
- agent_1_handler.handled_message.content_bytes == message_2.content_bytes
- ), "Message from Agent 2 to 1: content_bytes do not match"
- assert (
- agent_1_handler.handled_message.content_int == message_2.content_int
- ), "Message from Agent 2 to 1: content_int do not match"
- # floats do not seem to lose some precision when serialised then deserialised using protobuf
- # assert agent_1_handler.handled_message.content_float == message_2.content_float, "Message from Agent 2 to 1: content_float do not match"
- assert (
- agent_1_handler.handled_message.content_bool == message_2.content_bool
- ), "Message from Agent 2 to 1: content_bool do not match"
- assert (
- agent_1_handler.handled_message.content_str == message_2.content_str
- ), "Message from Agent 2 to 1: content_str do not match"
- time.sleep(2.0)
- finally:
- aea_1.stop()
- aea_2.stop()
- t_1.join()
- t_2.join()
-
- @classmethod
- def teardown_class(cls):
- """Tear the test down."""
- os.chdir(cls.cwd)
- try:
- shutil.rmtree(cls.t)
- except (OSError, IOError):
- pass
-
-
-class SpecificationTypeToPythonTypeTestCase(TestCase):
- """Test case for _specification_type_to_python_type method."""
-
- def test__specification_type_to_python_type_unsupported_type(self):
- """Test _specification_type_to_python_type method unsupported type."""
- with self.assertRaises(ProtocolSpecificationParseError):
- _specification_type_to_python_type("unsupported_type")
-
-
-@mock.patch(
- "aea.protocols.generator.common._get_sub_types_of_compositional_types",
- return_value=[1, 2],
-)
-class UnionSubTypeToProtobufVariableNameTestCase(TestCase):
- """Test case for _union_sub_type_to_protobuf_variable_name method."""
-
- def test__union_sub_type_to_protobuf_variable_name_tuple(self, mock):
- """Test _union_sub_type_to_protobuf_variable_name method tuple."""
- pytest.skip()
- _union_sub_type_to_protobuf_variable_name("content_name", "Tuple[str, ...]")
- mock.assert_called_once()
-
-
-class ProtocolGeneratorTestCase(TestCase):
- """Test case for ProtocolGenerator class."""
-
- def setUp(self):
- protocol_specification = mock.Mock()
- protocol_specification.name = "name"
-
- # @mock.patch(
- # "aea.protocols.generator.common._get_sub_types_of_compositional_types",
- # return_value=["some"],
- # )
- # def test__includes_custom_type_positive(self, *mocks):
- # """Test _includes_custom_type method positive result."""
- # content_type = "pt:union[pt:str]"
- # result = not _is_composition_type_with_custom_type(content_type)
- # self.assertTrue(result)
- #
- # content_type = "pt:optional[pt:str]"
- # result = not _is_composition_type_with_custom_type(content_type)
- # self.assertTrue(result)
-
- # @mock.patch("aea.protocols.generator._get_indent_str")
- # @mock.patch(
- # "aea.protocols.generator._get_sub_types_of_compositional_types",
- # return_value=["Tuple", "FrozenSet"],
- # )
- # def test__check_content_type_str_tuple(self, *mocks):
- # """Test _check_content_type_str method tuple."""
- # no_of_indents = 1
- # content_name = "name"
- # content_type = (
- # "Union[str, Dict[str, int], FrozenSet[DataModel, int], Dict[str, float]]"
- # )
- # self.protocol_generator._check_content_type_str(
- # no_of_indents, content_name, content_type
- # )
- # # TODO: finish this test
-
-
-class Agent1Handler(Handler):
- """The handler for agent 1."""
-
- SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id # type: Optional[ProtocolId]
-
- def __init__(self, **kwargs):
- """Initialize the handler."""
- super().__init__(**kwargs)
- self.kwargs = kwargs
- self.handled_message = None
-
- def setup(self) -> None:
- """Implement the setup for the handler."""
- pass
-
- def handle(self, message: Message) -> None:
- """
- Implement the reaction to a message.
-
- :param message: the message
- :return: None
- """
- self.handled_message = message
-
- def teardown(self) -> None:
- """
- Implement the handler teardown.
-
- :return: None
- """
-
-
-class Agent2Handler(Handler):
- """The handler for agent 2."""
-
- SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id # type: Optional[ProtocolId]
-
- def __init__(self, message, **kwargs):
- """Initialize the handler."""
- print("inside handler's initialisation method for agent 2")
- super().__init__(**kwargs)
- self.kwargs = kwargs
- self.handled_message = None
- self.message_2 = message
-
- def setup(self) -> None:
- """Implement the setup for the handler."""
- pass
-
- def handle(self, message: Message) -> None:
- """
- Implement the reaction to a message.
-
- :param message: the message
- :return: None
- """
- self.handled_message = message
- envelope = Envelope(
- to=message.counterparty,
- sender=self.context.agent_address,
- protocol_id=TProtocolMessage.protocol_id,
- message=self.message_2,
- )
- self.context.outbox.put(envelope)
-
- def teardown(self) -> None:
- """
- Implement the handler teardown.
-
- :return: None
- """
diff --git a/tests/test_protocols/test_generator/__init__.py b/tests/test_protocols/test_generator/__init__.py
new file mode 100644
index 0000000000..82e1017c65
--- /dev/null
+++ b/tests/test_protocols/test_generator/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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.
+#
+# ------------------------------------------------------------------------------
+
+"""The test generator module contains the tests of the AEA protocol generator."""
diff --git a/tests/test_protocols/test_generator/common.py b/tests/test_protocols/test_generator/common.py
new file mode 100644
index 0000000000..012c56c1e1
--- /dev/null
+++ b/tests/test_protocols/test_generator/common.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 utility code for the test_generator modules."""
+import os
+
+from tests.conftest import ROOT_DIR
+
+T_PROTOCOL_NAME = "t_protocol"
+PATH_TO_T_PROTOCOL_SPECIFICATION = os.path.join(
+ ROOT_DIR, "tests", "data", "sample_specification.yaml"
+)
+PATH_TO_T_PROTOCOL = os.path.join(
+ ROOT_DIR, "tests", "data", "generator", T_PROTOCOL_NAME
+)
+
+
+def black_is_not_installed(*args, **kwargs):
+ return not args[0] == "black"
diff --git a/tests/test_protocols/test_generator/test_common.py b/tests/test_protocols/test_generator/test_common.py
new file mode 100644
index 0000000000..73b28368fc
--- /dev/null
+++ b/tests/test_protocols/test_generator/test_common.py
@@ -0,0 +1,438 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 tests for generator/common.py module."""
+import logging
+import os
+import shutil
+import tempfile
+from pathlib import Path
+from subprocess import CalledProcessError # nosec
+from unittest import TestCase, mock
+
+from aea.protocols.generator.common import (
+ _camel_case_to_snake_case,
+ _create_protocol_file,
+ _get_sub_types_of_compositional_types,
+ _has_matched_brackets,
+ _includes_custom_type,
+ _match_brackets,
+ _python_pt_or_ct_type_to_proto_type,
+ _to_camel_case,
+ _union_sub_type_to_protobuf_variable_name,
+ check_prerequisites,
+ check_protobuf_using_protoc,
+ is_installed,
+ load_protocol_specification,
+ try_run_black_formatting,
+ try_run_protoc,
+)
+
+from tests.test_protocols.test_generator.common import (
+ PATH_TO_T_PROTOCOL_SPECIFICATION,
+ T_PROTOCOL_NAME,
+)
+
+logger = logging.getLogger("aea")
+logging.basicConfig(level=logging.INFO)
+
+
+def black_is_not_installed_side_effect(*args, **kwargs):
+ return not args[0] == "black"
+
+
+def protoc_is_not_installed_side_effect(*args, **kwargs):
+ return not args[0] == "protoc"
+
+
+class TestCommon(TestCase):
+ """Test for generator/common.py."""
+
+ @classmethod
+ def setup_class(cls):
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ def test_to_camel_case(self):
+ """Test the '_to_camel_case' method."""
+ input_text_1 = "this_is_a_snake_case_text"
+ expected_1 = "ThisIsASnakeCaseText"
+ output_1 = _to_camel_case(input_text_1)
+ assert output_1 == expected_1
+
+ input_text_2 = "This_is_a_Snake_Case_text"
+ expected_2 = "ThisIsASnakeCaseText"
+ output_2 = _to_camel_case(input_text_2)
+ assert output_2 == expected_2
+
+ def test_camel_case_to_snake_case(self):
+ """Test the '_camel_case_to_snake_case' method."""
+ input_text_1 = "ThisIsASnakeCaseText"
+ expected_1 = "this_is_a_snake_case_text"
+ output_1 = _camel_case_to_snake_case(input_text_1)
+ assert output_1 == expected_1
+
+ def test_match_brackets(self,):
+ """Positive test the '_match_brackets' method."""
+ text_1 = "[so[met[hi]]ng]"
+ assert _match_brackets(text_1, 0) == 14
+ assert _match_brackets(text_1, 3) == 11
+ assert _match_brackets(text_1, 7) == 10
+
+ text_2 = "[]]som[]et[hi[ng][sf]"
+ index_2 = 4
+ with self.assertRaises(SyntaxError) as cm:
+ _match_brackets(text_2, index_2)
+ self.assertEqual(
+ str(cm.exception),
+ "Index {} in 'text' is not an open bracket '['. It is {}".format(
+ index_2, text_2[index_2],
+ ),
+ )
+
+ index_3 = 2
+ with self.assertRaises(SyntaxError) as cm:
+ _match_brackets(text_2, index_3)
+ self.assertEqual(
+ str(cm.exception),
+ "Index {} in 'text' is not an open bracket '['. It is {}".format(
+ index_3, text_2[index_3],
+ ),
+ )
+
+ index_4 = 10
+ with self.assertRaises(SyntaxError) as cm:
+ _match_brackets(text_2, index_4)
+ self.assertEqual(
+ str(cm.exception),
+ "No matching closing bracket ']' for the opening bracket '[' at {} "
+ + str(index_4),
+ )
+
+ def test_has_matched_brackets(self,):
+ """Positive test the '_has_matched_brackets' method."""
+ valid_text_1 = "[so[met[hi]]ng]"
+ assert _has_matched_brackets(valid_text_1) is True
+
+ valid_text_2 = "[[][[]]]"
+ assert _has_matched_brackets(valid_text_2) is True
+
+ valid_text_3 = "[[[[[[[]]]]]]]"
+ assert _has_matched_brackets(valid_text_3) is True
+
+ invalid_text_1 = "[]]som[]et[hi[ng][sf]"
+ assert _has_matched_brackets(invalid_text_1) is False
+
+ invalid_text_2 = "[]][][[][]"
+ assert _has_matched_brackets(invalid_text_2) is False
+
+ invalid_text_3 = "[]]"
+ assert _has_matched_brackets(invalid_text_3) is False
+
+ invalid_text_4 = "[[]"
+ assert _has_matched_brackets(invalid_text_4) is False
+
+ def test_get_sub_types_of_compositional_types_positive(self,):
+ """Positive test the '_get_sub_types_of_compositional_types' method."""
+ composition_type_1 = "pt:set[pt:int, integer, bool]"
+ expected_1 = ("pt:int", "integer", "bool")
+ assert _get_sub_types_of_compositional_types(composition_type_1) == expected_1
+
+ composition_type_2 = "FrozenSet[something, anotherthing]"
+ expected_2 = ("something", "anotherthing")
+ assert _get_sub_types_of_compositional_types(composition_type_2) == expected_2
+
+ composition_type_3 = "pt:list[pt:str]"
+ expected_3 = ("pt:str",)
+ assert _get_sub_types_of_compositional_types(composition_type_3) == expected_3
+
+ composition_type_4 = "Tuple[bytes, ...]"
+ expected_4 = ("bytes",)
+ assert _get_sub_types_of_compositional_types(composition_type_4) == expected_4
+
+ composition_type_5 = "pt:dict[pt:int, pt:int]"
+ expected_5 = ("pt:int", "pt:int")
+ assert _get_sub_types_of_compositional_types(composition_type_5) == expected_5
+
+ composition_type_6 = "Dict[bool, float]"
+ expected_6 = ("bool", "float")
+ assert _get_sub_types_of_compositional_types(composition_type_6) == expected_6
+
+ composition_type_7 = "pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]"
+ expected_7 = (
+ "ct:DataModel",
+ "pt:bytes",
+ "pt:int",
+ "pt:bool",
+ "pt:float",
+ "pt:str",
+ "pt:set[pt:int]",
+ "pt:list[pt:bool]",
+ "pt:dict[pt:str,pt:str]",
+ )
+ assert _get_sub_types_of_compositional_types(composition_type_7) == expected_7
+
+ composition_type_8 = "Union[int, Tuple[bool, ...]]"
+ expected_8 = ("int", "Tuple[bool, ...]")
+ assert _get_sub_types_of_compositional_types(composition_type_8) == expected_8
+
+ composition_type_9 = (
+ "Union[DataModel, FrozenSet[int], Tuple[bool, ...], bytes, Dict[bool,float], int, "
+ "FrozenSet[bool], Dict[int, str], Tuple[str, ...], bool, float, str, Dict[str, str]]"
+ )
+ expected_9 = (
+ "DataModel",
+ "FrozenSet[int]",
+ "Tuple[bool, ...]",
+ "bytes",
+ "Dict[bool,float]",
+ "int",
+ "FrozenSet[bool]",
+ "Dict[int, str]",
+ "Tuple[str, ...]",
+ "bool",
+ "float",
+ "str",
+ "Dict[str, str]",
+ )
+ assert _get_sub_types_of_compositional_types(composition_type_9) == expected_9
+
+ composition_type_10 = "pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]]"
+ expected_10 = (
+ "pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]",
+ )
+ assert _get_sub_types_of_compositional_types(composition_type_10) == expected_10
+
+ composition_type_11 = "Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str,str]]]"
+ expected_11 = (
+ "Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str,str]]",
+ )
+ assert _get_sub_types_of_compositional_types(composition_type_11) == expected_11
+
+ def test_get_sub_types_of_compositional_types_negative(self,):
+ """Negative test the '_get_sub_types_of_compositional_types' method"""
+ composition_type_1 = "pt:int"
+ with self.assertRaises(SyntaxError) as cm:
+ _get_sub_types_of_compositional_types(composition_type_1)
+ self.assertEqual(
+ str(cm.exception),
+ "{} is not a valid compositional type.".format(composition_type_1),
+ )
+
+ composition_type_2 = "pt:int[pt:DataModel]"
+ with self.assertRaises(SyntaxError) as cm:
+ _get_sub_types_of_compositional_types(composition_type_2)
+ self.assertEqual(
+ str(cm.exception),
+ "{} is not a valid compositional type.".format(composition_type_2),
+ )
+
+ composition_type_3 = "pt:dict[pt:set[int, pt:list[pt:bool]]"
+ with self.assertRaises(SyntaxError) as cm:
+ _get_sub_types_of_compositional_types(composition_type_3)
+ self.assertEqual(
+ str(cm.exception),
+ "Bad formatting. No matching close bracket ']' for the open bracket at pt:set[",
+ )
+
+ def test_union_sub_type_to_protobuf_variable_name(self,):
+ """Test the '_union_sub_type_to_protobuf_variable_name' method"""
+ content_name = "proposal"
+
+ content_type_1 = "FrozenSet[int]"
+ assert (
+ _union_sub_type_to_protobuf_variable_name(content_name, content_type_1)
+ == "proposal_type_set_of_int"
+ )
+
+ content_type_2 = "Tuple[str, ...]"
+ assert (
+ _union_sub_type_to_protobuf_variable_name(content_name, content_type_2)
+ == "proposal_type_list_of_str"
+ )
+
+ content_type_3 = "Dict[bool, float]"
+ assert (
+ _union_sub_type_to_protobuf_variable_name(content_name, content_type_3)
+ == "proposal_type_dict_of_bool_float"
+ )
+
+ content_type_4 = "int"
+ assert (
+ _union_sub_type_to_protobuf_variable_name(content_name, content_type_4)
+ == "proposal_type_int"
+ )
+
+ content_type_5 = "DataModel"
+ assert (
+ _union_sub_type_to_protobuf_variable_name(content_name, content_type_5)
+ == "proposal_type_DataModel"
+ )
+
+ def test_python_pt_or_ct_type_to_proto_type(self,):
+ """Test the '_python_pt_or_ct_type_to_proto_type' method"""
+ content_type_bytes = "bytes"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_bytes) == "bytes"
+
+ content_type_int = "int"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_int) == "int32"
+
+ content_type_float = "float"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_float) == "float"
+
+ content_type_bool = "bool"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_bool) == "bool"
+
+ content_type_str = "str"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_str) == "string"
+
+ content_type_ct = "Query"
+ assert _python_pt_or_ct_type_to_proto_type(content_type_ct) == "Query"
+
+ def test_includes_custom_type(self,):
+ """Test the '_includes_custom_type' method"""
+ content_type_includes_1 = "Optional[DataModel]"
+ assert _includes_custom_type(content_type_includes_1) is True
+
+ content_type_includes_2 = "Union[int, DataModel]"
+ assert _includes_custom_type(content_type_includes_2) is True
+
+ content_type_includes_3 = "Optional[Union[int, float, DataModel, Query, float]]"
+ assert _includes_custom_type(content_type_includes_3) is True
+
+ content_type_not_includes_1 = "Optional[int]"
+ assert _includes_custom_type(content_type_not_includes_1) is False
+
+ content_type_not_includes_2 = "Union[int, float, str]"
+ assert _includes_custom_type(content_type_not_includes_2) is False
+
+ content_type_not_includes_3 = (
+ "Optional[Union[int, float, FrozenSet[int], Tuple[bool, ...], float]]"
+ )
+ assert _includes_custom_type(content_type_not_includes_3) is False
+
+ @mock.patch("shutil.which", return_value="some string")
+ def test_is_installed_positive(self, mocked_shutil_which):
+ """Positive test for the 'is_installed' method"""
+ assert is_installed("some_programme") is True
+
+ @mock.patch("shutil.which", return_value=None)
+ def test_is_installed_negative(self, mocked_shutil_which):
+ """Negative test for the 'is_installed' method: programme is not installed"""
+ assert is_installed("some_programme") is False
+
+ @mock.patch("aea.protocols.generator.common.is_installed", return_value=True)
+ def test_check_prerequisites_positive(self, mocked_is_installed):
+ """Positive test for the 'check_prerequisites' method"""
+ try:
+ check_prerequisites()
+ except FileNotFoundError:
+ self.assertTrue(False)
+
+ @mock.patch(
+ "aea.protocols.generator.common.is_installed",
+ side_effect=black_is_not_installed_side_effect,
+ )
+ def test_check_prerequisites_negative_black_is_not_installed(
+ self, mocked_is_installed
+ ):
+ """Negative test for the 'check_prerequisites' method: black isn't installed"""
+ with self.assertRaises(FileNotFoundError):
+ check_prerequisites()
+
+ @mock.patch(
+ "aea.protocols.generator.common.is_installed",
+ side_effect=protoc_is_not_installed_side_effect,
+ )
+ def test_check_prerequisites_negative_protoc_is_not_installed(
+ self, mocked_is_installed
+ ):
+ """Negative test for the 'check_prerequisites' method: protoc isn't installed"""
+ with self.assertRaises(FileNotFoundError):
+ check_prerequisites()
+
+ def test_load_protocol_specification(self,):
+ """Test the 'load_protocol_specification' method"""
+ spec = load_protocol_specification(PATH_TO_T_PROTOCOL_SPECIFICATION)
+ assert spec.name == T_PROTOCOL_NAME
+ assert spec.version == "0.1.0"
+ assert spec.author == "fetchai"
+ assert spec.license == "Apache-2.0"
+ assert spec.aea_version == ">=0.5.0, <0.6.0"
+ assert spec.description == "A protocol for testing purposes."
+ assert spec.speech_acts is not None
+ assert spec.protobuf_snippets is not None and spec.protobuf_snippets != ""
+
+ def test_create_protocol_file(self,):
+ """Test the '_create_protocol_file' method"""
+ file_name = "temp_file"
+ file_content = "this is a temporary file"
+
+ _create_protocol_file(self.t, file_name, file_content)
+ path_to_the_file = os.path.join(self.t, file_name)
+
+ assert Path(path_to_the_file).exists()
+ assert Path(path_to_the_file).read_text() == file_content
+
+ @mock.patch("subprocess.run")
+ def test_try_run_black_formatting(self, mocked_subprocess):
+ """Test the 'try_run_black_formatting' method"""
+ try_run_black_formatting("some_path")
+ mocked_subprocess.assert_called_once()
+
+ @mock.patch("subprocess.run")
+ def test_try_run_protoc(self, mocked_subprocess):
+ """Test the 'try_run_protoc' method"""
+ try_run_protoc("some_path", "some_name")
+ mocked_subprocess.assert_called_once()
+
+ @mock.patch("aea.protocols.generator.common.try_run_protoc")
+ def test_check_protobuf_using_protoc_positive(self, mocked_try_run_protoc):
+ """Positive test for the 'check_protobuf_using_protoc' method"""
+ protocol_name = "protocol_name"
+ file_name = protocol_name + "_pb2.py"
+
+ new_file = open(os.path.join(self.t, file_name), "w+")
+ new_file.close()
+ result, msg = check_protobuf_using_protoc(self.t, protocol_name)
+
+ assert not Path(self.t, file_name).exists()
+ assert result is True
+ assert msg == "protobuf file is valid"
+
+ @mock.patch(
+ "subprocess.run",
+ side_effect=CalledProcessError(
+ 1, "some_command", stderr="name.proto:12:45: some_protoc_error\n"
+ ),
+ )
+ def test_check_protobuf_using_protoc_nagative(self, mocked_subprocess):
+ """Negative test for the 'check_protobuf_using_protoc' method: protoc has some errors"""
+ result, msg = check_protobuf_using_protoc("some_path", "name")
+ assert result is False
+ assert msg == "some_protoc_error"
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
diff --git a/tests/test_protocols/test_generator/test_end_to_end.py b/tests/test_protocols/test_generator/test_end_to_end.py
new file mode 100644
index 0000000000..3f78f5f33f
--- /dev/null
+++ b/tests/test_protocols/test_generator/test_end_to_end.py
@@ -0,0 +1,372 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 end to end tests for the protocol generator."""
+import logging
+import os
+import shutil
+import tempfile
+import time
+from pathlib import Path
+from threading import Thread
+from typing import Optional
+
+from aea.aea_builder import AEABuilder
+from aea.configurations.base import (
+ ComponentType,
+ ProtocolId,
+ PublicId,
+ SkillConfig,
+)
+from aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE
+from aea.crypto.helpers import create_private_key
+from aea.helpers.dialogue.base import DialogueLabel
+from aea.protocols.base import Message
+from aea.skills.base import Handler, Skill, SkillContext
+from aea.test_tools.test_cases import UseOef
+
+from tests.conftest import ROOT_DIR
+from tests.data.generator.t_protocol.dialogues import TProtocolDialogue
+from tests.data.generator.t_protocol.message import ( # type: ignore
+ TProtocolMessage,
+)
+from tests.test_protocols.test_generator.common import PATH_TO_T_PROTOCOL
+
+logger = logging.getLogger("aea")
+logging.basicConfig(level=logging.INFO)
+
+
+class TestEndToEndGenerator(UseOef):
+ """
+ Test that the generating a protocol works correctly in correct preconditions.
+
+ Note: Types involving Floats seem to lose some precision when serialised then deserialised using protobuf.
+ So tests for these types are commented out throughout for now.
+ """
+
+ @classmethod
+ def setup_class(cls):
+ """Set the test up."""
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+ cls.private_key_path_1 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + "_1")
+ cls.private_key_path_2 = os.path.join(cls.t, DEFAULT_PRIVATE_KEY_FILE + "_2")
+ create_private_key(DEFAULT_LEDGER, cls.private_key_path_1)
+ create_private_key(DEFAULT_LEDGER, cls.private_key_path_2)
+
+ def test_generated_protocol_end_to_end(self):
+ """Test that a generated protocol could be used in exchanging messages between two agents."""
+ agent_name_1 = "my_aea_1"
+ agent_name_2 = "my_aea_2"
+ builder_1 = AEABuilder()
+ builder_1.set_name(agent_name_1)
+ builder_1.add_private_key(DEFAULT_LEDGER, self.private_key_path_1)
+ builder_1.set_default_ledger(DEFAULT_LEDGER)
+ builder_1.set_default_connection(PublicId.from_str("fetchai/oef:0.7.0"))
+ builder_1.add_protocol(
+ Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
+ )
+ builder_1.add_protocol(
+ Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
+ )
+ builder_1.add_component(
+ ComponentType.PROTOCOL,
+ Path(PATH_TO_T_PROTOCOL),
+ skip_consistency_check=True,
+ )
+ builder_1.add_connection(
+ Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
+ )
+
+ builder_2 = AEABuilder()
+ builder_2.set_name(agent_name_2)
+ builder_2.add_private_key(DEFAULT_LEDGER, self.private_key_path_2)
+ builder_2.set_default_ledger(DEFAULT_LEDGER)
+ builder_2.add_protocol(
+ Path(ROOT_DIR, "packages", "fetchai", "protocols", "fipa")
+ )
+ builder_2.add_protocol(
+ Path(ROOT_DIR, "packages", "fetchai", "protocols", "oef_search")
+ )
+ builder_2.set_default_connection(PublicId.from_str("fetchai/oef:0.7.0"))
+ builder_2.add_component(
+ ComponentType.PROTOCOL,
+ Path(PATH_TO_T_PROTOCOL),
+ skip_consistency_check=True,
+ )
+ builder_2.add_connection(
+ Path(ROOT_DIR, "packages", "fetchai", "connections", "oef")
+ )
+
+ # create AEAs
+ aea_1 = builder_1.build(connection_ids=[PublicId.from_str("fetchai/oef:0.7.0")])
+ aea_2 = builder_2.build(connection_ids=[PublicId.from_str("fetchai/oef:0.7.0")])
+
+ # dialogues
+ dialogue_label_1 = DialogueLabel(
+ (str(1), ""), aea_2.identity.address, aea_1.identity.address
+ )
+ aea_1_dialogue = TProtocolDialogue(
+ dialogue_label_1, aea_1.identity.address, TProtocolDialogue.Role.ROLE_1
+ )
+ dialogue_label_2 = DialogueLabel(
+ (str(1), str(1)), aea_1.identity.address, aea_1.identity.address
+ )
+ aea_2_dialogue = TProtocolDialogue(
+ dialogue_label_2, aea_2.identity.address, TProtocolDialogue.Role.ROLE_2
+ )
+
+ # message 1
+ message_1 = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(1), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
+ content_bytes=b"some bytes",
+ content_int=42,
+ content_float=42.7,
+ content_bool=True,
+ content_str="some string",
+ )
+ message_1.counterparty = aea_2.identity.address
+ message_1.is_incoming = False
+
+ # message 2
+ message_2 = TProtocolMessage(
+ message_id=2,
+ dialogue_reference=(str(1), str(1)),
+ target=1,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
+ content_bytes=b"some other bytes",
+ content_int=43,
+ content_float=43.7,
+ content_bool=False,
+ content_str="some other string",
+ )
+ message_2.counterparty = aea_1.identity.address
+ message_2.is_incoming = False
+
+ # add handlers to AEA resources
+ skill_context_1 = SkillContext(aea_1.context)
+ skill_1 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_1)
+ skill_context_1._skill = skill_1
+
+ agent_1_handler = Agent1Handler(
+ skill_context=skill_context_1,
+ name="fake_handler_1",
+ dialogue=aea_1_dialogue,
+ )
+ aea_1.resources._handler_registry.register(
+ (
+ PublicId.from_str("fetchai/fake_skill:0.1.0"),
+ TProtocolMessage.protocol_id,
+ ),
+ agent_1_handler,
+ )
+ skill_context_2 = SkillContext(aea_2.context)
+ skill_2 = Skill(SkillConfig("fake_skill", "fetchai", "0.1.0"), skill_context_2)
+ skill_context_2._skill = skill_2
+
+ agent_2_handler = Agent2Handler(
+ message=message_2,
+ dialogue=aea_2_dialogue,
+ skill_context=skill_context_2,
+ name="fake_handler_2",
+ )
+ aea_2.resources._handler_registry.register(
+ (
+ PublicId.from_str("fetchai/fake_skill:0.1.0"),
+ TProtocolMessage.protocol_id,
+ ),
+ agent_2_handler,
+ )
+
+ # Start threads
+ t_1 = Thread(target=aea_1.start)
+ t_2 = Thread(target=aea_2.start)
+ try:
+ t_1.start()
+ t_2.start()
+ time.sleep(1.0)
+ aea_1_dialogue.update(message_1)
+ aea_1.outbox.put_message(message_1)
+ time.sleep(5.0)
+ assert (
+ agent_2_handler.handled_message.message_id == message_1.message_id
+ ), "Message from Agent 1 to 2: message ids do not match"
+ assert (
+ agent_2_handler.handled_message.dialogue_reference
+ == message_1.dialogue_reference
+ ), "Message from Agent 1 to 2: dialogue references do not match"
+ assert (
+ agent_2_handler.handled_message.dialogue_reference[0]
+ == message_1.dialogue_reference[0]
+ ), "Message from Agent 1 to 2: dialogue reference[0]s do not match"
+ assert (
+ agent_2_handler.handled_message.dialogue_reference[1]
+ == message_1.dialogue_reference[1]
+ ), "Message from Agent 1 to 2: dialogue reference[1]s do not match"
+ assert (
+ agent_2_handler.handled_message.target == message_1.target
+ ), "Message from Agent 1 to 2: targets do not match"
+ assert (
+ agent_2_handler.handled_message.performative == message_1.performative
+ ), "Message from Agent 1 to 2: performatives do not match"
+ assert (
+ agent_2_handler.handled_message.content_bytes == message_1.content_bytes
+ ), "Message from Agent 1 to 2: content_bytes do not match"
+ assert (
+ agent_2_handler.handled_message.content_int == message_1.content_int
+ ), "Message from Agent 1 to 2: content_int do not match"
+ # assert (
+ # agent_2_handler.handled_message.content_float == message_1.content_float
+ # ), "Message from Agent 1 to 2: content_float do not match"
+ assert (
+ agent_2_handler.handled_message.content_bool == message_1.content_bool
+ ), "Message from Agent 1 to 2: content_bool do not match"
+ assert (
+ agent_2_handler.handled_message.content_str == message_1.content_str
+ ), "Message from Agent 1 to 2: content_str do not match"
+
+ assert (
+ agent_1_handler.handled_message.message_id == message_2.message_id
+ ), "Message from Agent 1 to 2: dialogue references do not match"
+ assert (
+ agent_1_handler.handled_message.dialogue_reference
+ == message_2.dialogue_reference
+ ), "Message from Agent 2 to 1: dialogue references do not match"
+ assert (
+ agent_1_handler.handled_message.dialogue_reference[0]
+ == message_2.dialogue_reference[0]
+ ), "Message from Agent 2 to 1: dialogue reference[0]s do not match"
+ assert (
+ agent_1_handler.handled_message.dialogue_reference[1]
+ == message_2.dialogue_reference[1]
+ ), "Message from Agent 2 to 1: dialogue reference[1]s do not match"
+ assert (
+ agent_1_handler.handled_message.target == message_2.target
+ ), "Message from Agent 2 to 1: targets do not match"
+ assert (
+ agent_1_handler.handled_message.performative == message_2.performative
+ ), "Message from Agent 2 to 1: performatives do not match"
+ assert (
+ agent_1_handler.handled_message.content_bytes == message_2.content_bytes
+ ), "Message from Agent 2 to 1: content_bytes do not match"
+ assert (
+ agent_1_handler.handled_message.content_int == message_2.content_int
+ ), "Message from Agent 2 to 1: content_int do not match"
+ # assert (
+ # agent_1_handler.handled_message.content_float == message_2.content_float
+ # ), "Message from Agent 2 to 1: content_float do not match"
+ assert (
+ agent_1_handler.handled_message.content_bool == message_2.content_bool
+ ), "Message from Agent 2 to 1: content_bool do not match"
+ assert (
+ agent_1_handler.handled_message.content_str == message_2.content_str
+ ), "Message from Agent 2 to 1: content_str do not match"
+ time.sleep(2.0)
+ finally:
+ aea_1.stop()
+ aea_2.stop()
+ t_1.join()
+ t_2.join()
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
+
+
+class Agent1Handler(Handler):
+ """The handler for agent 1."""
+
+ SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id # type: Optional[ProtocolId]
+
+ def __init__(self, dialogue: TProtocolDialogue, **kwargs):
+ """Initialize the handler."""
+ super().__init__(**kwargs)
+ self.kwargs = kwargs
+ self.handled_message = None # type: Optional[Message]
+ self.dialogue = dialogue
+
+ def setup(self) -> None:
+ """Implement the setup for the handler."""
+ pass
+
+ def handle(self, message: Message) -> None:
+ """
+ Implement the reaction to a message.
+
+ :param message: the message
+ :return: None
+ """
+ self.dialogue.update(message)
+ self.handled_message = message
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
+
+
+class Agent2Handler(Handler):
+ """The handler for agent 2."""
+
+ SUPPORTED_PROTOCOL = TProtocolMessage.protocol_id # type: Optional[ProtocolId]
+
+ def __init__(
+ self, message: TProtocolMessage, dialogue: TProtocolDialogue, **kwargs
+ ):
+ """Initialize the handler."""
+ print("inside handler's initialisation method for agent 2")
+ super().__init__(**kwargs)
+ self.kwargs = kwargs
+ self.handled_message = None # type: Optional[Message]
+ self.message_2 = message
+ self.dialogue = dialogue
+
+ def setup(self) -> None:
+ """Implement the setup for the handler."""
+ pass
+
+ def handle(self, message: Message) -> None:
+ """
+ Implement the reaction to a message.
+
+ :param message: the message
+ :return: None
+ """
+ self.dialogue.update(message)
+ self.handled_message = message
+ message.counterparty = self.dialogue.dialogue_label.dialogue_opponent_addr
+ self.dialogue.update(self.message_2)
+ self.context.outbox.put_message(self.message_2)
+
+ def teardown(self) -> None:
+ """
+ Implement the handler teardown.
+
+ :return: None
+ """
diff --git a/tests/test_protocols/test_generator/test_extract_specification.py b/tests/test_protocols/test_generator/test_extract_specification.py
new file mode 100644
index 0000000000..6687057b40
--- /dev/null
+++ b/tests/test_protocols/test_generator/test_extract_specification.py
@@ -0,0 +1,530 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 tests for generator/extract_specification.py module."""
+import logging
+import os
+import shutil
+import tempfile
+from unittest import TestCase, mock
+
+from aea.configurations.base import ProtocolSpecificationParseError
+from aea.protocols.generator.common import load_protocol_specification
+from aea.protocols.generator.extract_specification import (
+ PythonicProtocolSpecification,
+ _ct_specification_type_to_python_type,
+ _mt_specification_type_to_python_type,
+ _optional_specification_type_to_python_type,
+ _pct_specification_type_to_python_type,
+ _pmt_specification_type_to_python_type,
+ _pt_specification_type_to_python_type,
+ _specification_type_to_python_type,
+ extract,
+)
+
+from tests.test_protocols.test_generator.common import PATH_TO_T_PROTOCOL_SPECIFICATION
+
+logger = logging.getLogger("aea")
+logging.basicConfig(level=logging.INFO)
+
+
+class TestExtractSpecification(TestCase):
+ """Test for generator/extract_specification.py."""
+
+ @classmethod
+ def setup_class(cls):
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ def test_ct_specification_type_to_python_type(self):
+ """Test the '_ct_specification_type_to_python_type' method."""
+ specification_type_1 = "ct:DataModel"
+ expected_1 = "DataModel"
+ assert _ct_specification_type_to_python_type(specification_type_1) == expected_1
+
+ specification_type_2 = "ct:Query"
+ expected_2 = "Query"
+ assert _ct_specification_type_to_python_type(specification_type_2) == expected_2
+
+ def test_pt_specification_type_to_python_type(self):
+ """Test the '_pt_specification_type_to_python_type' method."""
+ specification_type_1 = "pt:bytes"
+ expected_1 = "bytes"
+ assert _pt_specification_type_to_python_type(specification_type_1) == expected_1
+
+ specification_type_2 = "pt:int"
+ expected_2 = "int"
+ assert _pt_specification_type_to_python_type(specification_type_2) == expected_2
+
+ specification_type_3 = "pt:float"
+ expected_3 = "float"
+ assert _pt_specification_type_to_python_type(specification_type_3) == expected_3
+
+ specification_type_4 = "pt:bool"
+ expected_4 = "bool"
+ assert _pt_specification_type_to_python_type(specification_type_4) == expected_4
+
+ specification_type_5 = "pt:str"
+ expected_5 = "str"
+ assert _pt_specification_type_to_python_type(specification_type_5) == expected_5
+
+ def test_pct_specification_type_to_python_type(self):
+ """Test the '_pct_specification_type_to_python_type' method."""
+ specification_type_1 = "pt:set[pt:bytes]"
+ expected_1 = "FrozenSet[bytes]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_1) == expected_1
+ )
+
+ specification_type_2 = "pt:set[pt:int]"
+ expected_2 = "FrozenSet[int]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_2) == expected_2
+ )
+
+ specification_type_3 = "pt:set[pt:float]"
+ expected_3 = "FrozenSet[float]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_3) == expected_3
+ )
+
+ specification_type_4 = "pt:set[pt:bool]"
+ expected_4 = "FrozenSet[bool]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_4) == expected_4
+ )
+
+ specification_type_5 = "pt:set[pt:str]"
+ expected_5 = "FrozenSet[str]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_5) == expected_5
+ )
+
+ specification_type_6 = "pt:list[pt:bytes]"
+ expected_6 = "Tuple[bytes, ...]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_6) == expected_6
+ )
+
+ specification_type_7 = "pt:list[pt:int]"
+ expected_7 = "Tuple[int, ...]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_7) == expected_7
+ )
+
+ specification_type_8 = "pt:list[pt:float]"
+ expected_8 = "Tuple[float, ...]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_8) == expected_8
+ )
+
+ specification_type_9 = "pt:list[pt:bool]"
+ expected_9 = "Tuple[bool, ...]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_9) == expected_9
+ )
+
+ specification_type_10 = "pt:list[pt:str]"
+ expected_10 = "Tuple[str, ...]"
+ assert (
+ _pct_specification_type_to_python_type(specification_type_10) == expected_10
+ )
+
+ def test_pmt_specification_type_to_python_type(self):
+ """Test the '_pmt_specification_type_to_python_type' method."""
+ specification_type_1 = "pt:dict[pt:int, pt:bytes]"
+ expected_1 = "Dict[int, bytes]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_1) == expected_1
+ )
+
+ specification_type_2 = "pt:dict[pt:int, pt:int]"
+ expected_2 = "Dict[int, int]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_2) == expected_2
+ )
+
+ specification_type_3 = "pt:dict[pt:int, pt:float]"
+ expected_3 = "Dict[int, float]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_3) == expected_3
+ )
+
+ specification_type_4 = "pt:dict[pt:int, pt:bool]"
+ expected_4 = "Dict[int, bool]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_4) == expected_4
+ )
+
+ specification_type_5 = "pt:dict[pt:int, pt:str]"
+ expected_5 = "Dict[int, str]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_5) == expected_5
+ )
+
+ specification_type_6 = "pt:dict[pt:bool, pt:bytes]"
+ expected_6 = "Dict[bool, bytes]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_6) == expected_6
+ )
+
+ specification_type_7 = "pt:dict[pt:bool, pt:int]"
+ expected_7 = "Dict[bool, int]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_7) == expected_7
+ )
+
+ specification_type_8 = "pt:dict[pt:bool, pt:float]"
+ expected_8 = "Dict[bool, float]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_8) == expected_8
+ )
+
+ specification_type_9 = "pt:dict[pt:bool, pt:bool]"
+ expected_9 = "Dict[bool, bool]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_9) == expected_9
+ )
+
+ specification_type_10 = "pt:dict[pt:bool, pt:str]"
+ expected_10 = "Dict[bool, str]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_10) == expected_10
+ )
+
+ specification_type_11 = "pt:dict[pt:str, pt:bytes]"
+ expected_11 = "Dict[str, bytes]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_11) == expected_11
+ )
+
+ specification_type_12 = "pt:dict[pt:str, pt:int]"
+ expected_12 = "Dict[str, int]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_12) == expected_12
+ )
+
+ specification_type_13 = "pt:dict[pt:str, pt:float]"
+ expected_13 = "Dict[str, float]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_13) == expected_13
+ )
+
+ specification_type_14 = "pt:dict[pt:str, pt:bool]"
+ expected_14 = "Dict[str, bool]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_14) == expected_14
+ )
+
+ specification_type_15 = "pt:dict[pt:str, pt:str]"
+ expected_15 = "Dict[str, str]"
+ assert (
+ _pmt_specification_type_to_python_type(specification_type_15) == expected_15
+ )
+
+ def test_mt_specification_type_to_python_type(self):
+ """Test the '_mt_specification_type_to_python_type' method."""
+ specification_type_1 = "pt:union[pt:int, pt:bytes]"
+ expected_1 = "Union[int, bytes]"
+ assert _mt_specification_type_to_python_type(specification_type_1) == expected_1
+
+ specification_type_2 = "pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], pt:list[pt:bool], pt:dict[pt:str,pt:str]]"
+ expected_2 = "Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]"
+ assert _mt_specification_type_to_python_type(specification_type_2) == expected_2
+
+ specification_type_3 = (
+ "pt:union[ct:DataModel, pt:set[pt:int], pt:list[pt:bool], pt:bytes, pt:dict[pt:bool,pt:float], pt:int, "
+ "pt:set[pt:bool], pt:dict[pt:int, pt:str], pt:list[pt:str], pt:bool, pt:float, pt:str, pt:dict[pt:str, pt:str]]"
+ )
+ expected_3 = (
+ "Union[DataModel, FrozenSet[int], Tuple[bool, ...], bytes, Dict[bool, float], int, "
+ "FrozenSet[bool], Dict[int, str], Tuple[str, ...], bool, float, str, Dict[str, str]]"
+ )
+ assert _mt_specification_type_to_python_type(specification_type_3) == expected_3
+
+ def test_optional_specification_type_to_python_type(self):
+ """Test the '_optional_specification_type_to_python_type' method."""
+ specification_type_1 = (
+ "pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], "
+ "pt:list[pt:bool], pt:dict[pt:str, pt:str]]]"
+ )
+ expected_1 = "Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]"
+ assert (
+ _optional_specification_type_to_python_type(specification_type_1)
+ == expected_1
+ )
+
+ specification_type_2 = (
+ "pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], "
+ "pt:list[pt:bool], pt:dict[pt:str,pt:str]]]"
+ )
+ expected_2 = "Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]"
+ assert (
+ _optional_specification_type_to_python_type(specification_type_2)
+ == expected_2
+ )
+
+ specification_type_3 = "pt:optional[ct:DataModel]"
+ expected_3 = "Optional[DataModel]"
+ assert (
+ _optional_specification_type_to_python_type(specification_type_3)
+ == expected_3
+ )
+
+ def test_specification_type_to_python_type(self):
+ """Test the '_specification_type_to_python_type' method."""
+ specification_type_1 = "ct:DataModel"
+ expected_1 = "DataModel"
+ assert _specification_type_to_python_type(specification_type_1) == expected_1
+
+ specification_type_2 = "pt:bytes"
+ expected_2 = "bytes"
+ assert _specification_type_to_python_type(specification_type_2) == expected_2
+
+ specification_type_3 = "pt:set[pt:int]"
+ expected_3 = "FrozenSet[int]"
+ assert _specification_type_to_python_type(specification_type_3) == expected_3
+
+ specification_type_4 = "pt:list[pt:float]"
+ expected_4 = "Tuple[float, ...]"
+ assert _specification_type_to_python_type(specification_type_4) == expected_4
+
+ specification_type_5 = "pt:dict[pt:bool, pt:str]"
+ expected_5 = "Dict[bool, str]"
+ assert _specification_type_to_python_type(specification_type_5) == expected_5
+
+ specification_type_6 = "pt:union[pt:int, pt:bytes]"
+ expected_6 = "Union[int, bytes]"
+ assert _specification_type_to_python_type(specification_type_6) == expected_6
+
+ specification_type_7 = (
+ "pt:optional[pt:union[ct:DataModel, pt:bytes, pt:int, pt:bool, pt:float, pt:str, pt:set[pt:int], "
+ "pt:list[pt:bool], pt:dict[pt:str,pt:str]]]"
+ )
+ expected_7 = "Optional[Union[DataModel, bytes, int, bool, float, str, FrozenSet[int], Tuple[bool, ...], Dict[str, str]]]"
+ assert _specification_type_to_python_type(specification_type_7) == expected_7
+
+ specification_type_8 = "wrong_type"
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ _specification_type_to_python_type(specification_type_8)
+ self.assertEqual(
+ str(cm.exception), "Unsupported type: '{}'".format(specification_type_8)
+ )
+
+ specification_type_9 = "pt:integer"
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ _specification_type_to_python_type(specification_type_9)
+ self.assertEqual(
+ str(cm.exception), "Unsupported type: '{}'".format(specification_type_9)
+ )
+
+ specification_type_10 = "pt: list"
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ _specification_type_to_python_type(specification_type_10)
+ self.assertEqual(
+ str(cm.exception), "Unsupported type: '{}'".format(specification_type_10)
+ )
+
+ specification_type_11 = "pt:list[wrong_sub_type]"
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ _specification_type_to_python_type(specification_type_11)
+ self.assertEqual(str(cm.exception), "Unsupported type: 'wrong_sub_type'")
+
+ def test_pythonic_protocol_specification_class(self):
+ """Test the 'PythonicProtocolSpecification' class."""
+ spec = PythonicProtocolSpecification()
+ assert spec.speech_acts == dict()
+ assert spec.all_performatives == list()
+ assert spec.all_unique_contents == dict()
+ assert spec.all_custom_types == list()
+ assert spec.custom_custom_types == dict()
+ assert spec.initial_performatives == list()
+ assert spec.reply == dict()
+ assert spec.terminal_performatives == list()
+ assert spec.roles == list()
+ assert spec.end_states == list()
+ assert spec.typing_imports == {
+ "Set": True,
+ "Tuple": True,
+ "cast": True,
+ "FrozenSet": False,
+ "Dict": False,
+ "Union": False,
+ "Optional": False,
+ }
+
+ def test_extract_positive(self):
+ """Positive test the 'extract' method."""
+ protocol_specification = load_protocol_specification(
+ PATH_TO_T_PROTOCOL_SPECIFICATION
+ )
+ spec = extract(protocol_specification)
+
+ assert spec.speech_acts == {
+ "performative_ct": {"content_ct": "DataModel"},
+ "performative_pt": {
+ "content_bytes": "bytes",
+ "content_int": "int",
+ "content_float": "float",
+ "content_bool": "bool",
+ "content_str": "str",
+ },
+ "performative_pct": {
+ "content_set_bytes": "FrozenSet[bytes]",
+ "content_set_int": "FrozenSet[int]",
+ "content_set_float": "FrozenSet[float]",
+ "content_set_bool": "FrozenSet[bool]",
+ "content_set_str": "FrozenSet[str]",
+ "content_list_bytes": "Tuple[bytes, ...]",
+ "content_list_int": "Tuple[int, ...]",
+ "content_list_float": "Tuple[float, ...]",
+ "content_list_bool": "Tuple[bool, ...]",
+ "content_list_str": "Tuple[str, ...]",
+ },
+ "performative_pmt": {
+ "content_dict_int_bytes": "Dict[int, bytes]",
+ "content_dict_int_int": "Dict[int, int]",
+ "content_dict_int_float": "Dict[int, float]",
+ "content_dict_int_bool": "Dict[int, bool]",
+ "content_dict_int_str": "Dict[int, str]",
+ "content_dict_bool_bytes": "Dict[bool, bytes]",
+ "content_dict_bool_int": "Dict[bool, int]",
+ "content_dict_bool_float": "Dict[bool, float]",
+ "content_dict_bool_bool": "Dict[bool, bool]",
+ "content_dict_bool_str": "Dict[bool, str]",
+ "content_dict_str_bytes": "Dict[str, bytes]",
+ "content_dict_str_int": "Dict[str, int]",
+ "content_dict_str_float": "Dict[str, float]",
+ "content_dict_str_bool": "Dict[str, bool]",
+ "content_dict_str_str": "Dict[str, str]",
+ },
+ "performative_mt": {
+ "content_union_1": "Union[DataModel, bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]]",
+ "content_union_2": "Union[FrozenSet[bytes], FrozenSet[int], FrozenSet[str], Tuple[float, ...], Tuple[bool, ...], Tuple[bytes, ...], Dict[str, int], Dict[int, float], Dict[bool, bytes]]",
+ },
+ "performative_o": {
+ "content_o_ct": "Optional[DataModel]",
+ "content_o_bool": "Optional[bool]",
+ "content_o_set_int": "Optional[FrozenSet[int]]",
+ "content_o_list_bytes": "Optional[Tuple[bytes, ...]]",
+ "content_o_dict_str_int": "Optional[Dict[str, int]]",
+ },
+ "performative_empty_contents": {},
+ }
+ assert spec.all_performatives == [
+ "performative_ct",
+ "performative_empty_contents",
+ "performative_mt",
+ "performative_o",
+ "performative_pct",
+ "performative_pmt",
+ "performative_pt",
+ ]
+ assert spec.all_unique_contents == {
+ "content_ct": "DataModel",
+ "content_bytes": "bytes",
+ "content_int": "int",
+ "content_float": "float",
+ "content_bool": "bool",
+ "content_str": "str",
+ "content_set_bytes": "FrozenSet[bytes]",
+ "content_set_int": "FrozenSet[int]",
+ "content_set_float": "FrozenSet[float]",
+ "content_set_bool": "FrozenSet[bool]",
+ "content_set_str": "FrozenSet[str]",
+ "content_list_bytes": "Tuple[bytes, ...]",
+ "content_list_int": "Tuple[int, ...]",
+ "content_list_float": "Tuple[float, ...]",
+ "content_list_bool": "Tuple[bool, ...]",
+ "content_list_str": "Tuple[str, ...]",
+ "content_dict_int_bytes": "Dict[int, bytes]",
+ "content_dict_int_int": "Dict[int, int]",
+ "content_dict_int_float": "Dict[int, float]",
+ "content_dict_int_bool": "Dict[int, bool]",
+ "content_dict_int_str": "Dict[int, str]",
+ "content_dict_bool_bytes": "Dict[bool, bytes]",
+ "content_dict_bool_int": "Dict[bool, int]",
+ "content_dict_bool_float": "Dict[bool, float]",
+ "content_dict_bool_bool": "Dict[bool, bool]",
+ "content_dict_bool_str": "Dict[bool, str]",
+ "content_dict_str_bytes": "Dict[str, bytes]",
+ "content_dict_str_int": "Dict[str, int]",
+ "content_dict_str_float": "Dict[str, float]",
+ "content_dict_str_bool": "Dict[str, bool]",
+ "content_dict_str_str": "Dict[str, str]",
+ "content_union_1": "Union[DataModel, bytes, int, float, bool, str, FrozenSet[int], Tuple[bool, ...], Dict[str, int]]",
+ "content_union_2": "Union[FrozenSet[bytes], FrozenSet[int], FrozenSet[str], Tuple[float, ...], Tuple[bool, ...], Tuple[bytes, ...], Dict[str, int], Dict[int, float], Dict[bool, bytes]]",
+ "content_o_ct": "Optional[DataModel]",
+ "content_o_bool": "Optional[bool]",
+ "content_o_set_int": "Optional[FrozenSet[int]]",
+ "content_o_list_bytes": "Optional[Tuple[bytes, ...]]",
+ "content_o_dict_str_int": "Optional[Dict[str, int]]",
+ }
+ assert spec.all_custom_types == ["DataModel"]
+ assert spec.custom_custom_types == {"DataModel": "CustomDataModel"}
+ assert spec.initial_performatives == ["PERFORMATIVE_CT", "PERFORMATIVE_PT"]
+ assert spec.reply == {
+ "performative_ct": ["performative_pct"],
+ "performative_pt": ["performative_pmt"],
+ "performative_pct": ["performative_mt", "performative_o"],
+ "performative_pmt": ["performative_mt", "performative_o"],
+ "performative_mt": [],
+ "performative_o": [],
+ "performative_empty_contents": ["performative_empty_contents"],
+ }
+ assert spec.terminal_performatives == [
+ "PERFORMATIVE_MT",
+ "PERFORMATIVE_O",
+ "PERFORMATIVE_EMPTY_CONTENTS",
+ ]
+ assert spec.roles == ["role_1", "role_2"]
+ assert spec.end_states == ["end_state_1", "end_state_2", "end_state_3"]
+ assert spec.typing_imports == {
+ "Set": True,
+ "Tuple": True,
+ "cast": True,
+ "FrozenSet": True,
+ "Dict": True,
+ "Union": True,
+ "Optional": True,
+ }
+
+ @mock.patch(
+ "aea.protocols.generator.extract_specification.validate",
+ return_value=(False, "Some error!"),
+ )
+ def test_extract_negative_invalid_specification(self, mocked_validate):
+ """Negative test the 'extract' method: invalid protocol specification"""
+ protocol_specification = load_protocol_specification(
+ PATH_TO_T_PROTOCOL_SPECIFICATION
+ )
+
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ extract(protocol_specification)
+ expected_msg = "Some error!"
+ assert str(cm.exception) == expected_msg
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
diff --git a/tests/test_protocols/test_generator/test_generator.py b/tests/test_protocols/test_generator/test_generator.py
new file mode 100644
index 0000000000..7cf30dba19
--- /dev/null
+++ b/tests/test_protocols/test_generator/test_generator.py
@@ -0,0 +1,1273 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 miscellaneous tests for the protocol generator."""
+import filecmp
+import logging
+import os
+import shutil
+import tempfile
+from pathlib import Path
+from typing import cast
+from unittest import TestCase, mock
+
+import pytest
+
+from aea.configurations.base import (
+ ProtocolSpecification,
+ ProtocolSpecificationParseError,
+)
+from aea.protocols.generator.base import ProtocolGenerator
+
+from tests.conftest import ROOT_DIR, skip_test_windows
+from tests.data.generator.t_protocol.message import ( # type: ignore
+ TProtocolMessage,
+)
+from tests.test_protocols.test_generator.common import (
+ PATH_TO_T_PROTOCOL,
+ PATH_TO_T_PROTOCOL_SPECIFICATION,
+ T_PROTOCOL_NAME,
+)
+
+
+logger = logging.getLogger("aea")
+logging.basicConfig(level=logging.INFO)
+
+
+@skip_test_windows
+class TestCompareLatestGeneratorOutputWithTestProtocol:
+ """Test that the "t_protocol" test protocol matches with the latest generator output based on its specification."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set the test up."""
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+ filecmp.clear_cache()
+
+ def test_compare_latest_generator_output_with_test_protocol(self):
+ """
+ Test that the "t_protocol" test protocol matches with the latest generator output based on its specification.
+
+ Note:
+ - custom_types.py files are not compared as the generated one is only a template.
+ - protocol.yaml files are consequently not compared either because the different
+ custom_types.py files makes their IPFS hashes different.
+ """
+ path_to_generated_protocol = self.t
+ dotted_path_to_package_for_imports = "tests.data.generator."
+
+ # Generate the protocol
+ try:
+ protocol_generator = ProtocolGenerator(
+ path_to_protocol_specification=PATH_TO_T_PROTOCOL_SPECIFICATION,
+ output_path=path_to_generated_protocol,
+ dotted_path_to_protocol_package=dotted_path_to_package_for_imports,
+ )
+ protocol_generator.generate()
+ except Exception as e:
+ pytest.skip(
+ "Something went wrong when generating the protocol. The exception:"
+ + str(e)
+ )
+
+ # compare __init__.py
+ init_file_generated = Path(self.t, T_PROTOCOL_NAME, "__init__.py")
+ init_file_original = Path(PATH_TO_T_PROTOCOL, "__init__.py",)
+ assert filecmp.cmp(init_file_generated, init_file_original)
+
+ # compare message.py
+ message_file_generated = Path(self.t, T_PROTOCOL_NAME, "message.py")
+ message_file_original = Path(PATH_TO_T_PROTOCOL, "message.py",)
+ assert filecmp.cmp(message_file_generated, message_file_original)
+
+ # compare serialization.py
+ serialization_file_generated = Path(self.t, T_PROTOCOL_NAME, "serialization.py")
+ serialization_file_original = Path(PATH_TO_T_PROTOCOL, "serialization.py",)
+ assert filecmp.cmp(serialization_file_generated, serialization_file_original)
+
+ # compare dialogues.py
+ dialogue_file_generated = Path(self.t, T_PROTOCOL_NAME, "dialogues.py")
+ dialogue_file_original = Path(PATH_TO_T_PROTOCOL, "dialogues.py",)
+ assert filecmp.cmp(dialogue_file_generated, dialogue_file_original)
+
+ # compare .proto
+ proto_file_generated = Path(
+ self.t, T_PROTOCOL_NAME, "{}.proto".format(T_PROTOCOL_NAME)
+ )
+ proto_file_original = Path(
+ PATH_TO_T_PROTOCOL, "{}.proto".format(T_PROTOCOL_NAME),
+ )
+ assert filecmp.cmp(proto_file_generated, proto_file_original, shallow=False)
+
+ # compare _pb2.py
+ # ToDo Fails in CI. Investigate!
+ # pb2_file_generated = Path(
+ # self.t, T_PROTOCOL_NAME, "{}_pb2.py".format(T_PROTOCOL_NAME)
+ # )
+ # pb2_file_original = Path(
+ # PATH_TO_T_PROTOCOL, "{}_pb2.py".format(T_PROTOCOL_NAME),
+ # )
+ # assert filecmp.cmp(pb2_file_generated, pb2_file_original)
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
+
+
+@skip_test_windows
+class TestCompareLatestGeneratorOutputWithTestProtocolWithNoCustomTypes:
+ """Test that the "t_protocol" test protocol matches with the latest generator output based on its specification."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set the test up."""
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+ filecmp.clear_cache()
+
+ def test_compare_latest_generator_output_with_test_protocol(self):
+ """
+ Test that the "t_protocol" test protocol matches with the latest generator output based on its specification.
+
+ Note:
+ - custom_types.py files are not compared as the generated one is only a template.
+ - protocol.yaml files are consequently not compared either because the different
+ custom_types.py files makes their IPFS hashes different.
+ """
+
+ protocol_name = "t_protocol_no_ct"
+ path_to_protocol_specification_with_no_custom_types = os.path.join(
+ ROOT_DIR, "tests", "data", "sample_specification_no_custom_types.yaml"
+ )
+ path_to_generated_protocol = self.t
+ dotted_path_to_package_for_imports = "tests.data.generator."
+ path_to_protocol = os.path.join(
+ ROOT_DIR, "tests", "data", "generator", protocol_name
+ )
+
+ # Generate the protocol
+ try:
+ protocol_generator = ProtocolGenerator(
+ path_to_protocol_specification=path_to_protocol_specification_with_no_custom_types,
+ output_path=path_to_generated_protocol,
+ dotted_path_to_protocol_package=dotted_path_to_package_for_imports,
+ )
+ protocol_generator.generate()
+ except Exception as e:
+ pytest.skip(
+ "Something went wrong when generating the protocol. The exception:"
+ + str(e)
+ )
+
+ # compare __init__.py
+ init_file_generated = Path(self.t, protocol_name, "__init__.py")
+ init_file_original = Path(path_to_protocol, "__init__.py",)
+ assert filecmp.cmp(init_file_generated, init_file_original)
+
+ # compare message.py
+ message_file_generated = Path(self.t, protocol_name, "message.py")
+ message_file_original = Path(path_to_protocol, "message.py",)
+ assert filecmp.cmp(message_file_generated, message_file_original)
+
+ # compare serialization.py
+ serialization_file_generated = Path(self.t, protocol_name, "serialization.py")
+ serialization_file_original = Path(path_to_protocol, "serialization.py",)
+ assert filecmp.cmp(serialization_file_generated, serialization_file_original)
+
+ # compare dialogues.py
+ dialogue_file_generated = Path(self.t, protocol_name, "dialogues.py")
+ dialogue_file_original = Path(path_to_protocol, "dialogues.py",)
+ assert filecmp.cmp(dialogue_file_generated, dialogue_file_original)
+
+ # compare .proto
+ proto_file_generated = Path(
+ self.t, protocol_name, "{}.proto".format(protocol_name)
+ )
+ proto_file_original = Path(path_to_protocol, "{}.proto".format(protocol_name),)
+ assert filecmp.cmp(proto_file_generated, proto_file_original)
+
+ # compare _pb2.py
+ # ToDo Fails in CI. Investigate!
+ # pb2_file_generated = Path(
+ # self.t, protocol_name, "{}_pb2.py".format(protocol_name)
+ # )
+ # pb2_file_original = Path(
+ # path_to_protocol, "{}_pb2.py".format(protocol_name),
+ # )
+ # assert filecmp.cmp(pb2_file_generated, pb2_file_original)
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
+
+
+class TestSerialisations:
+ """
+ Test that the generating a protocol works correctly in correct preconditions.
+
+ Note: Types involving Floats seem to lose some precision when serialised then deserialised using protobuf.
+ So tests for these types are commented out throughout for now.
+ """
+
+ def test_generated_protocol_serialisation_ct(self):
+ """Test serialisation and deserialisation of a message involving a ct type."""
+ some_dict = {1: True, 2: False, 3: True, 4: False}
+ data_model = TProtocolMessage.DataModel(
+ bytes_field=b"some bytes",
+ int_field=42,
+ float_field=42.7,
+ bool_field=True,
+ str_field="some string",
+ set_field={1, 2, 3, 4, 5},
+ list_field=["some string 1", "some string 2"],
+ dict_field=some_dict,
+ )
+ message = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_CT,
+ content_ct=data_model,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message.message_id
+ assert decoded_message.dialogue_reference == message.dialogue_reference
+ assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
+ assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
+ assert decoded_message.target == message.target
+ assert decoded_message.performative == message.performative
+ assert decoded_message.content_ct == message.content_ct
+
+ def test_generated_protocol_serialisation_pt(self):
+ """Test serialisation and deserialisation of a message involving a pt type."""
+ message = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_PT,
+ content_bytes=b"some bytes",
+ content_int=42,
+ content_float=42.7,
+ content_bool=True,
+ content_str="some string",
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message.message_id
+ assert decoded_message.dialogue_reference == message.dialogue_reference
+ assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
+ assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
+ assert decoded_message.target == message.target
+ assert decoded_message.performative == message.performative
+ assert decoded_message.content_bytes == message.content_bytes
+ assert decoded_message.content_int == message.content_int
+ # assert decoded_message.content_float == message.content_float
+ assert decoded_message.content_bool == message.content_bool
+ assert decoded_message.content_str == message.content_str
+
+ def test_generated_protocol_serialisation_pct(self):
+ """Test serialisation and deserialisation of a message involving a pct type."""
+ message = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_PCT,
+ content_set_bytes=frozenset([b"byte 1", b"byte 2", b"byte 3"]),
+ content_set_int=frozenset([1, 2, 3]),
+ content_set_float=frozenset([1.2, 2.3, 3.4]),
+ content_set_bool=frozenset([True, False, False, True]),
+ content_set_str=frozenset(["string1", "string2", "string3"]),
+ content_list_bytes=(b"byte 4", b"byte 5", b"byte 6"),
+ content_list_int=(4, 5, 6),
+ content_list_float=(4.5, 5.6, 6.7),
+ content_list_bool=(False, True, False, False),
+ content_list_str=("string4", "string5", "string6"),
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message.message_id
+ assert decoded_message.dialogue_reference == message.dialogue_reference
+ assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
+ assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
+ assert decoded_message.target == message.target
+ assert decoded_message.performative == message.performative
+ assert decoded_message.content_set_bytes == message.content_set_bytes
+ assert decoded_message.content_set_int == message.content_set_int
+ # assert decoded_message.content_set_float == message.content_set_float
+ assert decoded_message.content_set_bool == message.content_set_bool
+ assert decoded_message.content_set_str == message.content_set_str
+ assert decoded_message.content_list_bytes == message.content_list_bytes
+ assert decoded_message.content_list_int == message.content_list_int
+ # assert decoded_message.content_list_float == message.content_list_float
+ assert decoded_message.content_list_bool == message.content_list_bool
+ assert decoded_message.content_list_str == message.content_list_str
+
+ def test_generated_protocol_serialisation_pmt(self):
+ """Test serialisation and deserialisation of a message involving a pmt type."""
+ message = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_PMT,
+ content_dict_int_bytes={1: b"bytes1", 2: b"bytes2", 3: b"bytes3"},
+ content_dict_int_int={1: 2, 2: 3, 3: 4},
+ content_dict_int_float={1: 3.4, 2: 4.7, 3: 4.6},
+ content_dict_int_bool={1: True, 2: True, 3: False},
+ content_dict_int_str={1: "string1", 2: "string2", 3: "string3"},
+ content_dict_bool_bytes={True: b"bytes1", False: b"bytes2"},
+ content_dict_bool_int={True: 5, False: 7},
+ content_dict_bool_float={True: 5.4, False: 4.6},
+ content_dict_bool_bool={True: False, False: False},
+ content_dict_bool_str={True: "string1", False: "string2"},
+ content_dict_str_bytes={
+ "string1": b"bytes1",
+ "string2": b"bytes2",
+ "string3": b"bytes3",
+ },
+ content_dict_str_int={"string1": 2, "string2": 3, "string3": 4},
+ content_dict_str_float={"string1": 3.4, "string2": 4.7, "string3": 4.6},
+ content_dict_str_bool={"string1": True, "string2": True, "string3": False},
+ content_dict_str_str={
+ "string1": "string4",
+ "string2": "string5",
+ "string3": "string6",
+ },
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message.message_id
+ assert decoded_message.dialogue_reference == message.dialogue_reference
+ assert decoded_message.dialogue_reference[0] == message.dialogue_reference[0]
+ assert decoded_message.dialogue_reference[1] == message.dialogue_reference[1]
+ assert decoded_message.target == message.target
+ assert decoded_message.performative == message.performative
+ assert decoded_message.content_dict_int_bytes == message.content_dict_int_bytes
+ assert decoded_message.content_dict_int_int == message.content_dict_int_int
+ # assert decoded_message.content_dict_int_float == message.content_dict_int_float
+ assert decoded_message.content_dict_int_bool == message.content_dict_int_bool
+ assert decoded_message.content_dict_int_str == message.content_dict_int_str
+ assert (
+ decoded_message.content_dict_bool_bytes == message.content_dict_bool_bytes
+ )
+ assert decoded_message.content_dict_bool_int == message.content_dict_bool_int
+ # assert decoded_message.content_dict_bool_float == message.content_dict_bool_float
+ assert decoded_message.content_dict_bool_bool == message.content_dict_bool_bool
+ assert decoded_message.content_dict_bool_str == message.content_dict_bool_str
+ assert decoded_message.content_dict_str_bytes == message.content_dict_str_bytes
+ assert decoded_message.content_dict_str_int == message.content_dict_str_int
+ # assert decoded_message.content_dict_str_float == message.content_dict_str_float
+ assert decoded_message.content_dict_str_bool == message.content_dict_str_bool
+ assert decoded_message.content_dict_str_str == message.content_dict_str_str
+
+ def test_generated_protocol_serialisation_mt(self):
+ """Test serialisation and deserialisation of a message involving an mt type."""
+ pytest.skip(
+ "Currently, union type is not properly implemented in the generator."
+ )
+ some_dict = {1: True, 2: False, 3: True, 4: False}
+ data_model = TProtocolMessage.DataModel(
+ bytes_field=b"some bytes",
+ int_field=42,
+ float_field=42.7,
+ bool_field=True,
+ str_field="some string",
+ set_field={1, 2, 3, 4, 5},
+ list_field=["some string 1", "some string 2"],
+ dict_field=some_dict,
+ )
+ message_ct = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=data_model,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_ct)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_ct.message_id
+ assert decoded_message.dialogue_reference == message_ct.dialogue_reference
+ assert decoded_message.dialogue_reference[0] == message_ct.dialogue_reference[0]
+ assert decoded_message.dialogue_reference[1] == message_ct.dialogue_reference[1]
+ assert decoded_message.target == message_ct.target
+ assert decoded_message.performative == message_ct.performative
+ assert decoded_message.content_union_1 == message_ct.content_union_1
+
+ #####################
+
+ message_pt_bytes = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=b"some bytes",
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_bytes)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_pt_bytes.message_id
+ assert decoded_message.dialogue_reference == message_pt_bytes.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_pt_bytes.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_pt_bytes.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_pt_bytes.target
+ assert decoded_message.performative == message_pt_bytes.performative
+ assert decoded_message.content_union_1 == message_pt_bytes.content_union_1
+
+ #####################
+
+ message_pt_int = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=3453,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_int)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_pt_int.message_id
+ assert decoded_message.dialogue_reference == message_pt_int.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_pt_int.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_pt_int.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_pt_int.target
+ assert decoded_message.performative == message_pt_int.performative
+ assert decoded_message.content_union_1 == message_pt_int.content_union_1
+
+ #####################
+
+ message_pt_float = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=34.64,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_float)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_pt_float.message_id
+ assert decoded_message.dialogue_reference == message_pt_float.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_pt_float.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_pt_float.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_pt_float.target
+ assert decoded_message.performative == message_pt_float.performative
+ assert decoded_message.content_union_1 == message_pt_float.content_union_1
+
+ #####################
+
+ message_pt_bool = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=True,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_bool)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_pt_bool.message_id
+ assert decoded_message.dialogue_reference == message_pt_bool.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_pt_bool.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_pt_bool.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_pt_bool.target
+ assert decoded_message.performative == message_pt_bool.performative
+ assert decoded_message.content_union_1 == message_pt_bool.content_union_1
+
+ #####################
+
+ message_pt_str = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1="some string",
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_pt_str)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_pt_str.message_id
+ assert decoded_message.dialogue_reference == message_pt_str.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_pt_str.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_pt_str.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_pt_str.target
+ assert decoded_message.performative == message_pt_str.performative
+ assert decoded_message.content_union_1 == message_pt_str.content_union_1
+
+ #####################
+
+ message_set_int = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=frozenset([1, 2, 3]),
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_set_int)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_set_int.message_id
+ assert decoded_message.dialogue_reference == message_set_int.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_set_int.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_set_int.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_set_int.target
+ assert decoded_message.performative == message_set_int.performative
+ assert decoded_message.content_union_1 == message_set_int.content_union_1
+
+ #####################
+
+ message_list_bool = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1=(True, False, False, True, True),
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_list_bool)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_list_bool.message_id
+ assert (
+ decoded_message.dialogue_reference == message_list_bool.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_list_bool.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_list_bool.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_list_bool.target
+ assert decoded_message.performative == message_list_bool.performative
+ assert decoded_message.content_union_1 == message_list_bool.content_union_1
+
+ #####################
+
+ message_dict_str_int = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_MT,
+ content_union_1={"string1": 2, "string2": 3, "string3": 4},
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_dict_str_int
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_dict_str_int.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_dict_str_int.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_dict_str_int.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_dict_str_int.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_dict_str_int.target
+ assert decoded_message.performative == message_dict_str_int.performative
+ assert decoded_message.content_union_1 == message_dict_str_int.content_union_1
+
+ def test_generated_protocol_serialisation_o(self):
+ """Test serialisation and deserialisation of a message involving an optional type."""
+ some_dict = {1: True, 2: False, 3: True, 4: False}
+ data_model = TProtocolMessage.DataModel(
+ bytes_field=b"some bytes",
+ int_field=42,
+ float_field=42.7,
+ bool_field=True,
+ str_field="some string",
+ set_field={1, 2, 3, 4, 5},
+ list_field=["some string 1", "some string 2"],
+ dict_field=some_dict,
+ )
+ message_o_ct_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ content_o_ct=data_model,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(message_o_ct_set)
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_ct_set.message_id
+ assert decoded_message.dialogue_reference == message_o_ct_set.dialogue_reference
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_ct_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_ct_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_ct_set.target
+ assert decoded_message.performative == message_o_ct_set.performative
+ assert decoded_message.content_o_ct == message_o_ct_set.content_o_ct
+
+ #####################
+
+ message_o_ct_not_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_ct_not_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_ct_not_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_ct_not_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_ct_not_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_ct_not_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_ct_not_set.target
+ assert decoded_message.performative == message_o_ct_not_set.performative
+ assert decoded_message.content_o_ct == message_o_ct_not_set.content_o_ct
+
+ #####################
+
+ message_o_bool_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ content_o_bool=True,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_bool_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_bool_set.message_id
+ assert (
+ decoded_message.dialogue_reference == message_o_bool_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_bool_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_bool_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_bool_set.target
+ assert decoded_message.performative == message_o_bool_set.performative
+ assert decoded_message.content_o_ct == message_o_bool_set.content_o_ct
+
+ #####################
+
+ message_o_bool_not_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_bool_not_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_bool_not_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_bool_not_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_bool_not_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_bool_not_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_bool_not_set.target
+ assert decoded_message.performative == message_o_bool_not_set.performative
+ assert decoded_message.content_o_bool == message_o_bool_not_set.content_o_bool
+
+ #####################
+
+ message_o_set_int_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ content_o_set_int=frozenset([1, 2, 3]),
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_set_int_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_set_int_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_set_int_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_set_int_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_set_int_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_set_int_set.target
+ assert decoded_message.performative == message_o_set_int_set.performative
+ assert (
+ decoded_message.content_o_set_int == message_o_set_int_set.content_o_set_int
+ )
+
+ #####################
+
+ message_o_set_int_not_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_set_int_not_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_set_int_not_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_set_int_not_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_set_int_not_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_set_int_not_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_set_int_not_set.target
+ assert decoded_message.performative == message_o_set_int_not_set.performative
+ assert (
+ decoded_message.content_o_set_int
+ == message_o_set_int_not_set.content_o_set_int
+ )
+
+ #####################
+
+ message_o_list_bytes_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ content_o_list_bytes=(b"bytes1", b"bytes2", b"bytes3"),
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_list_bytes_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_list_bytes_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_list_bytes_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_list_bytes_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_list_bytes_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_list_bytes_set.target
+ assert decoded_message.performative == message_o_list_bytes_set.performative
+ assert (
+ decoded_message.content_o_list_bytes
+ == message_o_list_bytes_set.content_o_list_bytes
+ )
+
+ #####################
+
+ message_o_list_bytes_not_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_list_bytes_not_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_list_bytes_not_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_list_bytes_not_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_list_bytes_not_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_list_bytes_not_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_list_bytes_not_set.target
+ assert decoded_message.performative == message_o_list_bytes_not_set.performative
+ assert (
+ decoded_message.content_o_list_bytes
+ == message_o_list_bytes_not_set.content_o_list_bytes
+ )
+
+ #####################
+
+ message_o_dict_str_int_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ content_o_dict_str_int={"string1": 2, "string2": 3, "string3": 4},
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_dict_str_int_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_dict_str_int_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_dict_str_int_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_dict_str_int_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_dict_str_int_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_dict_str_int_set.target
+ assert decoded_message.performative == message_o_dict_str_int_set.performative
+ assert (
+ decoded_message.content_o_list_bytes
+ == message_o_dict_str_int_set.content_o_list_bytes
+ )
+
+ #####################
+
+ message_o_dict_str_int_not_set = TProtocolMessage(
+ message_id=1,
+ dialogue_reference=(str(0), ""),
+ target=0,
+ performative=TProtocolMessage.Performative.PERFORMATIVE_O,
+ )
+
+ encoded_message_in_bytes = TProtocolMessage.serializer.encode(
+ message_o_dict_str_int_not_set
+ )
+ decoded_message = cast(
+ TProtocolMessage,
+ TProtocolMessage.serializer.decode(encoded_message_in_bytes),
+ )
+
+ assert decoded_message.message_id == message_o_dict_str_int_not_set.message_id
+ assert (
+ decoded_message.dialogue_reference
+ == message_o_dict_str_int_not_set.dialogue_reference
+ )
+ assert (
+ decoded_message.dialogue_reference[0]
+ == message_o_dict_str_int_not_set.dialogue_reference[0]
+ )
+ assert (
+ decoded_message.dialogue_reference[1]
+ == message_o_dict_str_int_not_set.dialogue_reference[1]
+ )
+ assert decoded_message.target == message_o_dict_str_int_not_set.target
+ assert (
+ decoded_message.performative == message_o_dict_str_int_not_set.performative
+ )
+ assert (
+ decoded_message.content_o_list_bytes
+ == message_o_dict_str_int_not_set.content_o_list_bytes
+ )
+
+
+class ProtocolGeneratorTestCase(TestCase):
+ """Test for generator/base.py."""
+
+ @classmethod
+ def setup_class(cls):
+ cls.cwd = os.getcwd()
+ cls.t = tempfile.mkdtemp()
+ os.chdir(cls.t)
+
+ @mock.patch(
+ "aea.protocols.generator.base.check_prerequisites",
+ side_effect=FileNotFoundError("Some error!"),
+ )
+ def test_init_negative_no_prerequisits(self, mocked_check_prerequisites):
+ """Negative test for the '__init__' method: check_prerequisites fails."""
+ with self.assertRaises(FileNotFoundError) as cm:
+ ProtocolGenerator(PATH_TO_T_PROTOCOL, self.t)
+ expected_msg = "Some error!"
+ assert str(cm.exception) == expected_msg
+
+ @mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ side_effect=ValueError("Some error!"),
+ )
+ def test_init_negative_loading_specification_fails(self, mocked_load):
+ """Negative test for the '__init__' method: loading the specification fails."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ with self.assertRaises(ValueError) as cm:
+ ProtocolGenerator(PATH_TO_T_PROTOCOL, self.t)
+ expected_msg = "Some error!"
+ assert str(cm.exception) == expected_msg
+
+ @mock.patch(
+ "aea.protocols.generator.base.extract",
+ side_effect=ProtocolSpecificationParseError("Some error!"),
+ )
+ def test_init_negative_extracting_specification_fails(self, mocked_extract):
+ """Negative test for the '__init__' method: extracting the specification fails."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ p_spec_mock = mock.MagicMock(ProtocolSpecification)
+ p_spec_mock.name = "some_name"
+ p_spec_mock.author = "some_author"
+ with mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ return_value=p_spec_mock,
+ ):
+ with self.assertRaises(ProtocolSpecificationParseError) as cm:
+ ProtocolGenerator(
+ "some_path_to_protocol_specification", "some_path_to_output"
+ )
+ expected_msg = "Some error!"
+ assert str(cm.exception) == expected_msg
+
+ def test_change_indent_negative_set_indent_to_negative_value(self):
+ """Negative test for the '_change_indent' method: setting indent level to negative value."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ p_spec_mock = mock.MagicMock(ProtocolSpecification)
+ p_spec_mock.name = "some_name"
+ p_spec_mock.author = "some_author"
+ with mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ return_value=p_spec_mock,
+ ):
+ with mock.patch("aea.protocols.generator.base.extract"):
+ protocol_generator = ProtocolGenerator(
+ "some_path_to_protocol_specification", "some_path_to_output"
+ )
+ with self.assertRaises(ValueError) as cm:
+ protocol_generator._change_indent(-1, "s")
+ expected_msg = "Error: setting indent to be a negative number."
+ assert str(cm.exception) == expected_msg
+
+ def test_change_indent_negative_decreasing_more_spaces_than_available(self):
+ """Negative test for the '_change_indent' method: decreasing more spaces than available."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ p_spec_mock = mock.MagicMock(ProtocolSpecification)
+ p_spec_mock.name = "some_name"
+ p_spec_mock.author = "some_author"
+ with mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ return_value=p_spec_mock,
+ ):
+ with mock.patch("aea.protocols.generator.base.extract"):
+ protocol_generator = ProtocolGenerator(
+ "some_path_to_protocol_specification", "some_path_to_output"
+ )
+ protocol_generator.indent = " "
+ with self.assertRaises(ValueError) as cm:
+ protocol_generator._change_indent(-2)
+ expected_msg = (
+ "Not enough spaces in the 'indent' variable to remove."
+ )
+ assert str(cm.exception) == expected_msg
+
+ def test_import_from_custom_types_module_no_custom_types(self):
+ """Test the '_import_from_custom_types_module' method: no custom types."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ p_spec_mock = mock.MagicMock(ProtocolSpecification)
+ p_spec_mock.name = "some_name"
+ p_spec_mock.author = "some_author"
+ with mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ return_value=p_spec_mock,
+ ):
+ with mock.patch("aea.protocols.generator.base.extract"):
+ protocol_generator = ProtocolGenerator(
+ "some_path_to_protocol_specification", "some_path_to_output"
+ )
+ protocol_generator.spec.all_custom_types = []
+ assert protocol_generator._import_from_custom_types_module() == ""
+
+ def test_protocol_buffer_schema_str(self):
+ """Negative test for the '_protocol_buffer_schema_str' method: 1 line protobuf snippet."""
+ with mock.patch("aea.protocols.generator.base.check_prerequisites"):
+ p_spec_mock = mock.MagicMock(ProtocolSpecification)
+ p_spec_mock.name = "some_name"
+ p_spec_mock.author = "some_author"
+ with mock.patch(
+ "aea.protocols.generator.base.load_protocol_specification",
+ return_value=p_spec_mock,
+ ):
+ with mock.patch("aea.protocols.generator.base.extract"):
+ protocol_generator = ProtocolGenerator(
+ "some_path_to_protocol_specification", "some_path_to_output"
+ )
+ protocol_generator.spec.all_custom_types = ["SomeCustomType"]
+ protocol_generator.protocol_specification.protobuf_snippets = {
+ "ct:SomeCustomType": "bytes description = 1;"
+ }
+ proto_buff_schema_str = (
+ protocol_generator._protocol_buffer_schema_str()
+ )
+ print(proto_buff_schema_str)
+ expected = (
+ 'syntax = "proto3";\n\n'
+ "package fetch.aea.SomeName;\n\n"
+ "message SomeNameMessage{\n\n"
+ " // Custom Types\n"
+ " message SomeCustomType{\n"
+ " bytes description = 1; }\n\n\n"
+ " // Performatives and contents\n\n"
+ " // Standard SomeNameMessage fields\n"
+ " int32 message_id = 1;\n"
+ " string dialogue_starter_reference = 2;\n"
+ " string dialogue_responder_reference = 3;\n"
+ " int32 target = 4;\n"
+ " oneof performative{\n"
+ " }\n"
+ "}\n"
+ )
+ assert proto_buff_schema_str == expected
+
+ def test_generate_protobuf_only_mode_positive(self):
+ """Positive test for the 'generate_protobuf_only_mode' method."""
+ protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)
+ protocol_generator.generate_protobuf_only_mode()
+ path_to_protobuf_file = os.path.join(
+ self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + ".proto"
+ )
+ assert Path(path_to_protobuf_file).exists()
+
+ @mock.patch(
+ "aea.protocols.generator.base.check_protobuf_using_protoc",
+ return_value=(False, "Some error!"),
+ )
+ def test_generate_protobuf_only_mode_negative(self, mocked_check_protobuf):
+ """Negative test for the 'generate_protobuf_only_mode' method: protobuf schema file is invalid"""
+ protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)
+ with self.assertRaises(SyntaxError) as cm:
+ protocol_generator.generate_protobuf_only_mode()
+ expected_msg = "Error in the protocol buffer schema code:\n" + "Some error!"
+ assert str(cm.exception) == expected_msg
+
+ path_to_protobuf_file = os.path.join(
+ self.t, T_PROTOCOL_NAME, T_PROTOCOL_NAME + ".proto"
+ )
+ assert not Path(path_to_protobuf_file).exists()
+
+ @mock.patch(
+ "aea.protocols.generator.base.ProtocolGenerator.generate_protobuf_only_mode"
+ )
+ @mock.patch("aea.protocols.generator.base.ProtocolGenerator.generate_full_mode")
+ def test_generate_1(self, mocked_full_mode, mocked_protobuf_mode):
+ """Test the 'generate' method: protobuf_only mode"""
+ protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)
+ protocol_generator.generate(protobuf_only=True)
+ mocked_protobuf_mode.assert_called_once()
+ mocked_full_mode.assert_not_called()
+
+ @mock.patch(
+ "aea.protocols.generator.base.ProtocolGenerator.generate_protobuf_only_mode"
+ )
+ @mock.patch("aea.protocols.generator.base.ProtocolGenerator.generate_full_mode")
+ def test_generate_2(self, mocked_full_mode, mocked_protobuf_mode):
+ """Test the 'generate' method: full mode"""
+ protocol_generator = ProtocolGenerator(PATH_TO_T_PROTOCOL_SPECIFICATION, self.t)
+ protocol_generator.generate(protobuf_only=False)
+ mocked_protobuf_mode.assert_not_called()
+ mocked_full_mode.assert_called_once()
+
+ @classmethod
+ def teardown_class(cls):
+ """Tear the test down."""
+ os.chdir(cls.cwd)
+ try:
+ shutil.rmtree(cls.t)
+ except (OSError, IOError):
+ pass
diff --git a/tests/test_protocols/test_generator/test_validate.py b/tests/test_protocols/test_generator/test_validate.py
new file mode 100644
index 0000000000..eeeda771f3
--- /dev/null
+++ b/tests/test_protocols/test_generator/test_validate.py
@@ -0,0 +1,1595 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 tests for generator/validate.py module."""
+import logging
+from unittest import TestCase, mock
+
+from aea.configurations.base import CRUDCollection, SpeechActContentConfig
+from aea.protocols.generator.validate import (
+ CONTENT_NAME_REGEX_PATTERN,
+ END_STATE_REGEX_PATTERN,
+ PERFORMATIVE_REGEX_PATTERN,
+ ROLE_REGEX_PATTERN,
+ _has_brackets,
+ _is_reserved_name,
+ _is_valid_content_type_format,
+ _is_valid_ct,
+ _is_valid_dict,
+ _is_valid_list,
+ _is_valid_optional,
+ _is_valid_pt,
+ _is_valid_regex,
+ _is_valid_set,
+ _is_valid_union,
+ _validate_content_name,
+ _validate_content_type,
+ _validate_dialogue_section,
+ _validate_end_states,
+ _validate_initiation,
+ _validate_performatives,
+ _validate_protocol_buffer_schema_code_snippets,
+ _validate_reply,
+ _validate_roles,
+ _validate_speech_acts_section,
+ _validate_termination,
+ validate,
+)
+
+logger = logging.getLogger("aea")
+logging.basicConfig(level=logging.INFO)
+
+
+class TestValidate(TestCase):
+ """Test for generator/validate.py."""
+
+ def test_is_reserved_name(self):
+ """Test for the '_is_reserved_name' method."""
+ invalid_content_name_1 = "body"
+ assert _is_reserved_name(invalid_content_name_1) is True
+
+ invalid_content_name_2 = "message_id"
+ assert _is_reserved_name(invalid_content_name_2) is True
+
+ invalid_content_name_3 = "dialogue_reference"
+ assert _is_reserved_name(invalid_content_name_3) is True
+
+ invalid_content_name_4 = "target"
+ assert _is_reserved_name(invalid_content_name_4) is True
+
+ invalid_content_name_5 = "performative"
+ assert _is_reserved_name(invalid_content_name_5) is True
+
+ valid_content_nam_1 = "content_name"
+ assert _is_reserved_name(valid_content_nam_1) is False
+
+ valid_content_name_2 = "query"
+ assert _is_reserved_name(valid_content_name_2) is False
+
+ valid_content_name_3 = "ThiSiSAConTEnT234"
+ assert _is_reserved_name(valid_content_name_3) is False
+
+ def test_is_valid_regex(self):
+ """Test for the '_is_valid_regex' method."""
+ regex_1 = "^[0-9][a-zA-Z0-9]*[A-Z]$"
+
+ valid_text_1 = "53453hKb35nDkG"
+ assert _is_valid_regex(regex_1, valid_text_1) is True
+
+ invalid_text_1 = "hKbnDkG"
+ assert _is_valid_regex(regex_1, invalid_text_1) is False
+
+ invalid_text_2 = "4f nkG"
+ assert _is_valid_regex(regex_1, invalid_text_2) is False
+
+ def test_has_brackets(self):
+ """Test for the '_has_brackets' method."""
+ valid_content_type_1 = "pt:set[pt:int]"
+ assert _has_brackets(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:union[hskdjf-8768&^${]hsdkjhfk]"
+ assert _has_brackets(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:optional[[]]"
+ assert _has_brackets(valid_content_type_3) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "ct:set[pt:int]"
+ with self.assertRaises(SyntaxError) as cm:
+ _has_brackets(invalid_content_type_1)
+ self.assertEqual(
+ str(cm.exception), "Content type must be a compositional type!"
+ )
+
+ invalid_content_type_2 = "pt:tuple[pt:float]"
+ with self.assertRaises(SyntaxError) as cm:
+ _has_brackets(invalid_content_type_2)
+ self.assertEqual(
+ str(cm.exception), "Content type must be a compositional type!"
+ )
+
+ invalid_content_type_3 = "pt:optinal[pt:bool]"
+ with self.assertRaises(SyntaxError) as cm:
+ _has_brackets(invalid_content_type_3)
+ self.assertEqual(
+ str(cm.exception), "Content type must be a compositional type!"
+ )
+
+ ###################################################
+
+ invalid_content_type_4 = "pt:optional{}"
+ assert _has_brackets(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:set[]7657"
+ assert _has_brackets(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:union [pt:int, pt:bool]"
+ assert _has_brackets(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:dict[pt:int, pt:bool] "
+ assert _has_brackets(invalid_content_type_7) is False
+
+ def test_is_valid_ct(self):
+ """Test for the '_is_valid_ct' method."""
+ valid_content_type_1 = "ct:DataModel"
+ assert _is_valid_ct(valid_content_type_1) is True
+
+ valid_content_type_2 = "ct:ThisIsACustomContent"
+ assert _is_valid_ct(valid_content_type_2) is True
+
+ valid_content_type_3 = "ct:Query"
+ assert _is_valid_ct(valid_content_type_3) is True
+
+ valid_content_type_4 = " ct:Proposal "
+ assert _is_valid_ct(valid_content_type_4) is True
+
+ valid_content_type_5 = "ct:DSA"
+ assert _is_valid_ct(valid_content_type_5) is True
+
+ valid_content_type_6 = "ct:DataF"
+ assert _is_valid_ct(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "ct:data"
+ assert _is_valid_ct(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "Model"
+ assert _is_valid_ct(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "ct: DataModel"
+ assert _is_valid_ct(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "ct:E3"
+ assert _is_valid_ct(invalid_content_type_4) is False
+
+ def test_is_valid_pt(self):
+ """Test for the '_is_valid_pt' method."""
+ valid_content_type_1 = "pt:bytes"
+ assert _is_valid_pt(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:int"
+ assert _is_valid_pt(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:float"
+ assert _is_valid_pt(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:bool"
+ assert _is_valid_pt(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:str"
+ assert _is_valid_pt(valid_content_type_5) is True
+
+ valid_content_type_6 = " pt:int "
+ assert _is_valid_pt(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:integer"
+ assert _is_valid_pt(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "bool"
+ assert _is_valid_pt(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: str"
+ assert _is_valid_pt(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt;float"
+ assert _is_valid_pt(invalid_content_type_4) is False
+
+ def test_is_valid_set(self):
+ """Test for the '_is_valid_set' method."""
+ valid_content_type_1 = "pt:set[pt:bytes]"
+ assert _is_valid_set(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:set[pt:int]"
+ assert _is_valid_set(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:set[pt:float]"
+ assert _is_valid_set(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:set[pt:bool]"
+ assert _is_valid_set(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:set[pt:str]"
+ assert _is_valid_set(valid_content_type_5) is True
+
+ valid_content_type_6 = " pt:set[ pt:int ] "
+ assert _is_valid_set(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:frozenset[pt:int]"
+ assert _is_valid_set(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "set[pt:int]"
+ assert _is_valid_set(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: set[pt:int]"
+ assert _is_valid_set(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:set[integer]"
+ assert _is_valid_set(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:set[int]"
+ assert _is_valid_set(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:set{int]"
+ assert _is_valid_set(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:set[pt:int, pt:str]"
+ assert _is_valid_set(invalid_content_type_7) is False
+
+ invalid_content_type_8 = "pt:set[]"
+ assert _is_valid_set(invalid_content_type_8) is False
+
+ invalid_content_type_9 = "pt:set[pt:list[pt:int, pt:list[pt:bool]]"
+ assert _is_valid_set(invalid_content_type_9) is False
+
+ invalid_content_type_10 = "pt:set"
+ assert _is_valid_set(invalid_content_type_10) is False
+
+ def test_is_valid_list(self):
+ """Test for the '_is_valid_list' method."""
+ valid_content_type_1 = "pt:list[pt:bytes]"
+ assert _is_valid_list(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:list[pt:int]"
+ assert _is_valid_list(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:list[pt:float]"
+ assert _is_valid_list(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:list[pt:bool]"
+ assert _is_valid_list(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:list[pt:str]"
+ assert _is_valid_list(valid_content_type_5) is True
+
+ valid_content_type_6 = " pt:list[ pt:bool ] "
+ assert _is_valid_list(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:tuple[pt:bytes]"
+ assert _is_valid_list(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "list[pt:bool]"
+ assert _is_valid_list(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: list[pt:float]"
+ assert _is_valid_list(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:list[string]"
+ assert _is_valid_list(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:list[bool]"
+ assert _is_valid_list(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:list[bytes"
+ assert _is_valid_list(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:list[pt:float, pt:bool]"
+ assert _is_valid_list(invalid_content_type_7) is False
+
+ invalid_content_type_8 = "pt:list[]"
+ assert _is_valid_list(invalid_content_type_8) is False
+
+ invalid_content_type_9 = "pt:list[pt:set[pt:bool, pt:set[pt:str]]"
+ assert _is_valid_list(invalid_content_type_9) is False
+
+ invalid_content_type_10 = "pt:list"
+ assert _is_valid_list(invalid_content_type_10) is False
+
+ def test_is_valid_dict(self):
+ """Test for the '_is_valid_dict' method."""
+ valid_content_type_1 = "pt:dict[pt:bytes, pt:int]"
+ assert _is_valid_dict(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:dict[pt:int, pt:int]"
+ assert _is_valid_dict(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:dict[pt:float, pt:str]"
+ assert _is_valid_dict(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:dict[pt:bool, pt:str]"
+ assert _is_valid_dict(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:dict[pt:bool,pt:float]"
+ assert _is_valid_dict(valid_content_type_5) is True
+
+ valid_content_type_6 = " pt:dict[ pt:bytes , pt:int ] "
+ assert _is_valid_dict(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:map[pt:bool, pt:str]"
+ assert _is_valid_dict(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "dict[pt:int, pt:float]"
+ assert _is_valid_dict(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: dict[pt:bytes, pt:bool]"
+ assert _is_valid_dict(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:dict[float, pt:str]"
+ assert _is_valid_dict(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:dict[pt:bool, pt:integer]"
+ assert _is_valid_dict(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:dict(pt:boolean, pt:int"
+ assert _is_valid_dict(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:dict[pt:boolean]"
+ assert _is_valid_dict(invalid_content_type_7) is False
+
+ invalid_content_type_8 = "pt:dict[]"
+ assert _is_valid_dict(invalid_content_type_8) is False
+
+ invalid_content_type_9 = "pt:dict[pt:str, pt:float, pt:int, pt:bytes]"
+ assert _is_valid_dict(invalid_content_type_9) is False
+
+ invalid_content_type_10 = "pt:dict[pt:set[pt:bool, pt:str]"
+ assert _is_valid_dict(invalid_content_type_10) is False
+
+ invalid_content_type_11 = "pt:dict"
+ assert _is_valid_dict(invalid_content_type_11) is False
+
+ def test_is_valid_union(self):
+ """Test for the '_is_valid_union' method."""
+ valid_content_type_1 = (
+ "pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:bytes], "
+ "pt:set[pt:int], pt:set[pt:float], pt:set[pt:bool], pt:set[pt:str], "
+ "pt:list[pt:bytes], pt:list[pt:int], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:str], "
+ "pt:dict[pt:bytes, pt:bytes], pt:dict[ pt:bytes , pt:int ] , pt:dict[pt:bytes, pt:float], pt:dict[pt:bytes, pt:bool], pt:dict[pt:bytes, pt:str], "
+ "pt:dict[pt:int, pt:bytes], pt:dict[pt:int, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:int, pt:bool], pt:dict[pt:int, pt:str], "
+ "pt:dict[pt:float, pt:bytes], pt:dict[pt:float, pt:int], pt:dict[pt:float, pt:float], pt:dict[pt:float, pt:bool], pt:dict[pt:float, pt:str], "
+ "pt:dict[pt:bool, pt:bytes], pt:dict[pt:bool, pt:int], pt:dict[pt:bool,pt:float], pt:dict[pt:bool, pt:bool], pt:dict[pt:bool, pt:str], "
+ "pt:dict[pt:str, pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:str,pt:float], pt:dict[pt:str, pt:bool], pt:dict[pt:str, pt:str]]"
+ )
+ assert _is_valid_union(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:union[pt:bytes, pt:set[pt:int]]"
+ assert _is_valid_union(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:union[pt:float, pt:bool]"
+ assert _is_valid_union(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:union[pt:set[pt:int], pt:set[pt:float]]"
+ assert _is_valid_union(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:union[pt:bool,pt:bytes]"
+ assert _is_valid_union(valid_content_type_5) is True
+
+ valid_content_type_6 = " pt:union[ pt:bytes , pt:set[ pt:int ] ] "
+ assert _is_valid_union(valid_content_type_6) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:onion[pt:bool, pt:str]"
+ assert _is_valid_union(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "union[pt:int, pt:float]"
+ assert _is_valid_union(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: union[pt:set[pt:int], pt:bool]"
+ assert _is_valid_union(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:union[float, pt:str"
+ assert _is_valid_union(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:union[pt:int, pt:dict[pt:str, pt:bool]"
+ assert _is_valid_union(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:union{pt:boolean, pt:int]"
+ assert _is_valid_union(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:union[pt:boolean]"
+ assert _is_valid_union(invalid_content_type_7) is False
+
+ invalid_content_type_8 = "pt:union[]"
+ assert _is_valid_union(invalid_content_type_8) is False
+
+ invalid_content_type_9 = "pt:union[pt:str, pt:int, pt:str]"
+ assert _is_valid_union(invalid_content_type_9) is False
+
+ invalid_content_type_10 = "pt:union[pt:set[pt:integer], pt:float]"
+ assert _is_valid_union(invalid_content_type_10) is False
+
+ invalid_content_type_11 = (
+ "pt:union[pt:dict[pt:set[pt:bool]], pt:list[pt:set[pt:str]]]"
+ )
+ assert _is_valid_union(invalid_content_type_11) is False
+
+ invalid_content_type_12 = "pt:union"
+ assert _is_valid_union(invalid_content_type_12) is False
+
+ def test_is_valid_optional(self):
+ """Test for the '_is_valid_optional' method."""
+ valid_content_type_1 = (
+ "pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:bytes], "
+ "pt:set[pt:int], pt:set[pt:float], pt:set[pt:bool], pt:set[pt:str], "
+ "pt:list[pt:bytes], pt:list[pt:int], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:str], "
+ "pt:dict[pt:bytes, pt:bytes], pt:dict[ pt:bytes , pt:int ] , pt:dict[pt:bytes, pt:float], pt:dict[pt:bytes, pt:bool], pt:dict[pt:bytes, pt:str], "
+ "pt:dict[pt:int, pt:bytes], pt:dict[pt:int, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:int, pt:bool], pt:dict[pt:int, pt:str], "
+ "pt:dict[pt:float, pt:bytes], pt:dict[pt:float, pt:int], pt:dict[pt:float, pt:float], pt:dict[pt:float, pt:bool], pt:dict[pt:float, pt:str], "
+ "pt:dict[pt:bool, pt:bytes], pt:dict[pt:bool, pt:int], pt:dict[pt:bool,pt:float], pt:dict[pt:bool, pt:bool], pt:dict[pt:bool, pt:str], "
+ "pt:dict[pt:str, pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:str,pt:float], pt:dict[pt:str, pt:bool], pt:dict[pt:str, pt:str]]]"
+ )
+ assert _is_valid_optional(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:optional[pt:union[pt:bytes, pt:set[pt:int]]]"
+ assert _is_valid_optional(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:optional[pt:bytes]"
+ assert _is_valid_optional(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:optional[pt:int]"
+ assert _is_valid_optional(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:optional[pt:float]"
+ assert _is_valid_optional(valid_content_type_5) is True
+
+ valid_content_type_6 = "pt:optional[pt:bool]"
+ assert _is_valid_optional(valid_content_type_6) is True
+
+ valid_content_type_7 = "pt:optional[pt:str]"
+ assert _is_valid_optional(valid_content_type_7) is True
+
+ valid_content_type_8 = "pt:optional[pt:set[pt:bytes]]"
+ assert _is_valid_optional(valid_content_type_8) is True
+
+ valid_content_type_9 = "pt:optional[pt:list[pt:int]]"
+ assert _is_valid_optional(valid_content_type_9) is True
+
+ valid_content_type_10 = (
+ " pt:optional[ pt:dict[ pt:float , pt:bool ] ] "
+ )
+ assert _is_valid_optional(valid_content_type_10) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "pt:optinal[pt:bytes]"
+ assert _is_valid_optional(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "optional[pt:int]"
+ assert _is_valid_optional(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: optional[pt:float]"
+ assert _is_valid_optional(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:optional[bool]"
+ assert _is_valid_optional(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:optional[pt:str"
+ assert _is_valid_optional(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:optional{pt:set[pt:int]]"
+ assert _is_valid_optional(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:optional[pt:string]"
+ assert _is_valid_optional(invalid_content_type_7) is False
+
+ invalid_content_type_8 = "pt:optional[]"
+ assert _is_valid_optional(invalid_content_type_8) is False
+
+ invalid_content_type_9 = "pt:optional[pt:str, pt:int, pt:list[pt:bool]]"
+ assert _is_valid_optional(invalid_content_type_9) is False
+
+ invalid_content_type_10 = "pt:optional[pt:list[pt:boolean]]"
+ assert _is_valid_optional(invalid_content_type_10) is False
+
+ invalid_content_type_11 = "pt:optional[pt:dict[pt:set[pt:int]]]"
+ assert _is_valid_optional(invalid_content_type_11) is False
+
+ invalid_content_type_12 = "pt:optional"
+ assert _is_valid_optional(invalid_content_type_12) is False
+
+ def test_is_valid_content_type_format(self):
+ """Test for the '_is_valid_content_type_format' method."""
+ valid_content_type_1 = "ct:DataModel"
+ assert _is_valid_content_type_format(valid_content_type_1) is True
+
+ valid_content_type_2 = "pt:int"
+ assert _is_valid_content_type_format(valid_content_type_2) is True
+
+ valid_content_type_3 = "pt:set[pt:float]"
+ assert _is_valid_content_type_format(valid_content_type_3) is True
+
+ valid_content_type_4 = "pt:list[pt:bool]"
+ assert _is_valid_content_type_format(valid_content_type_4) is True
+
+ valid_content_type_5 = "pt:dict[pt:bool,pt:float]"
+ assert _is_valid_content_type_format(valid_content_type_5) is True
+
+ valid_content_type_6 = (
+ "pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:bytes], "
+ "pt:set[pt:int], pt:set[pt:float], pt:set[pt:bool], pt:set[pt:str], "
+ "pt:list[pt:bytes], pt:list[pt:int], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:str], "
+ "pt:dict[pt:bytes, pt:bytes], pt:dict[ pt:bytes , pt:int ] , pt:dict[pt:bytes, pt:float], pt:dict[pt:bytes, pt:bool], pt:dict[pt:bytes, pt:str], "
+ "pt:dict[pt:int, pt:bytes], pt:dict[pt:int, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:int, pt:bool], pt:dict[pt:int, pt:str], "
+ "pt:dict[pt:float, pt:bytes], pt:dict[pt:float, pt:int], pt:dict[pt:float, pt:float], pt:dict[pt:float, pt:bool], pt:dict[pt:float, pt:str], "
+ "pt:dict[pt:bool, pt:bytes], pt:dict[pt:bool, pt:int], pt:dict[pt:bool,pt:float], pt:dict[pt:bool, pt:bool], pt:dict[pt:bool, pt:str], "
+ "pt:dict[pt:str, pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:str,pt:float], pt:dict[pt:str, pt:bool], pt:dict[pt:str, pt:str]]]"
+ )
+ assert _is_valid_content_type_format(valid_content_type_6) is True
+
+ valid_content_type_7 = (
+ " pt:optional[ pt:dict[ pt:float , pt:bool ] ] "
+ )
+ assert _is_valid_content_type_format(valid_content_type_7) is True
+
+ ###################################################
+
+ invalid_content_type_1 = "ct:data"
+ assert _is_valid_content_type_format(invalid_content_type_1) is False
+
+ invalid_content_type_2 = "bool"
+ assert _is_valid_content_type_format(invalid_content_type_2) is False
+
+ invalid_content_type_3 = "pt: set[pt:int]"
+ assert _is_valid_content_type_format(invalid_content_type_3) is False
+
+ invalid_content_type_4 = "pt:list[string]"
+ assert _is_valid_content_type_format(invalid_content_type_4) is False
+
+ invalid_content_type_5 = "pt:dict[pt:bool, pt:integer]"
+ assert _is_valid_content_type_format(invalid_content_type_5) is False
+
+ invalid_content_type_6 = "pt:union{pt:boolean, pt:int]"
+ assert _is_valid_content_type_format(invalid_content_type_6) is False
+
+ invalid_content_type_7 = "pt:optional[pt:str, pt:int, pt:list[pt:bool]]"
+ assert _is_valid_content_type_format(invalid_content_type_7) is False
+
+ def test_validate_performatives(self):
+ """Test for the '_validate_performatives' method."""
+ valid_content_type_1 = "offer"
+ valid_result_1, valid_msg_1 = _validate_performatives(valid_content_type_1)
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Performative '{}' is valid.".format(valid_content_type_1)
+
+ valid_content_type_2 = "send_HTTP_message"
+ valid_result_2, valid_msg_2 = _validate_performatives(valid_content_type_2)
+ assert valid_result_2 is True
+ assert valid_msg_2 == "Performative '{}' is valid.".format(valid_content_type_2)
+
+ valid_content_type_3 = "request_2PL"
+ valid_result_3, valid_msg_3 = _validate_performatives(valid_content_type_3)
+ assert valid_result_3 is True
+ assert valid_msg_3 == "Performative '{}' is valid.".format(valid_content_type_3)
+
+ valid_content_type_4 = "argue"
+ valid_result_4, valid_msg_4 = _validate_performatives(valid_content_type_4)
+ assert valid_result_4 is True
+ assert valid_msg_4 == "Performative '{}' is valid.".format(valid_content_type_4)
+
+ ###################################################
+
+ invalid_content_type_1 = "_offer"
+ invalid_result_1, invalid_msg_1 = _validate_performatives(
+ invalid_content_type_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_content_type_1, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_2 = "request_"
+ invalid_result_2, invalid_msg_2 = _validate_performatives(
+ invalid_content_type_2
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_content_type_2, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_3 = "_query_"
+ invalid_result_3, invalid_msg_3 = _validate_performatives(
+ invalid_content_type_3
+ )
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_content_type_3, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_4 = "$end"
+ invalid_result_4, invalid_msg_4 = _validate_performatives(
+ invalid_content_type_4
+ )
+ assert invalid_result_4 is False
+ assert (
+ invalid_msg_4
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_content_type_4, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_5 = "create()"
+ invalid_result_5, invalid_msg_5 = _validate_performatives(
+ invalid_content_type_5
+ )
+ assert invalid_result_5 is False
+ assert (
+ invalid_msg_5
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_content_type_5, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_6 = "body"
+ invalid_result_6, invalid_msg_6 = _validate_performatives(
+ invalid_content_type_6
+ )
+ assert invalid_result_6 is False
+ assert (
+ invalid_msg_6
+ == "Invalid name for performative '{}'. This name is reserved.".format(
+ invalid_content_type_6,
+ )
+ )
+
+ invalid_content_type_7 = "message_id"
+ invalid_result_7, invalid_msg_7 = _validate_performatives(
+ invalid_content_type_7
+ )
+ assert invalid_result_7 is False
+ assert (
+ invalid_msg_6
+ == "Invalid name for performative '{}'. This name is reserved.".format(
+ invalid_content_type_6,
+ )
+ )
+
+ def test_validate_content_name(self):
+ """Test for the '_validate_content_name' method."""
+ performative = "some_performative"
+
+ valid_content_type_1 = "content"
+ valid_result_1, valid_msg_1 = _validate_content_name(
+ valid_content_type_1, performative
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Content name '{}' of performative '{}' is valid.".format(
+ valid_content_type_1, performative
+ )
+
+ valid_content_type_2 = "HTTP_msg_name"
+ valid_result_2, valid_msg_2 = _validate_content_name(
+ valid_content_type_2, performative
+ )
+ assert valid_result_2 is True
+ assert valid_msg_2 == "Content name '{}' of performative '{}' is valid.".format(
+ valid_content_type_2, performative
+ )
+
+ valid_content_type_3 = "number_of_3PLs"
+ valid_result_3, valid_msg_3 = _validate_content_name(
+ valid_content_type_3, performative
+ )
+ assert valid_result_3 is True
+ assert valid_msg_3 == "Content name '{}' of performative '{}' is valid.".format(
+ valid_content_type_3, performative
+ )
+
+ valid_content_type_4 = "model"
+ valid_result_4, valid_msg_4 = _validate_content_name(
+ valid_content_type_4, performative
+ )
+ assert valid_result_4 is True
+ assert valid_msg_4 == "Content name '{}' of performative '{}' is valid.".format(
+ valid_content_type_4, performative
+ )
+
+ ###################################################
+
+ invalid_content_type_1 = "_content"
+ invalid_result_1, invalid_msg_1 = _validate_content_name(
+ invalid_content_type_1, performative
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
+ invalid_content_type_1, performative, CONTENT_NAME_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_2 = "content_"
+ invalid_result_2, invalid_msg_2 = _validate_content_name(
+ invalid_content_type_2, performative
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
+ invalid_content_type_2, performative, CONTENT_NAME_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_3 = "_content_"
+ invalid_result_3, invalid_msg_3 = _validate_content_name(
+ invalid_content_type_3, performative
+ )
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
+ invalid_content_type_3, performative, CONTENT_NAME_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_4 = "con^en^"
+ invalid_result_4, invalid_msg_4 = _validate_content_name(
+ invalid_content_type_4, performative
+ )
+ assert invalid_result_4 is False
+ assert (
+ invalid_msg_4
+ == "Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
+ invalid_content_type_4, performative, CONTENT_NAME_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_5 = "some_content()"
+ invalid_result_5, invalid_msg_5 = _validate_content_name(
+ invalid_content_type_5, performative
+ )
+ assert invalid_result_5 is False
+ assert (
+ invalid_msg_5
+ == "Invalid name for content '{}' of performative '{}'. Content names must match the following regular expression: {} ".format(
+ invalid_content_type_5, performative, CONTENT_NAME_REGEX_PATTERN
+ )
+ )
+
+ invalid_content_type_6 = "target"
+ invalid_result_6, invalid_msg_6 = _validate_content_name(
+ invalid_content_type_6, performative
+ )
+ assert invalid_result_6 is False
+ assert (
+ invalid_msg_6
+ == "Invalid name for content '{}' of performative '{}'. This name is reserved.".format(
+ invalid_content_type_6, performative,
+ )
+ )
+
+ invalid_content_type_7 = "performative"
+ invalid_result_7, invalid_msg_7 = _validate_content_name(
+ invalid_content_type_7, performative
+ )
+ assert invalid_result_7 is False
+ assert (
+ invalid_msg_7
+ == "Invalid name for content '{}' of performative '{}'. This name is reserved.".format(
+ invalid_content_type_7, performative,
+ )
+ )
+
+ def test_validate_content_type(self):
+ """Test for the '_validate_content_type' method."""
+ performative = "some_performative"
+ content_name = "some_content_name"
+
+ valid_content_type_1 = "ct:DataModel"
+ valid_result_1, valid_msg_1 = _validate_content_type(
+ valid_content_type_1, content_name, performative
+ )
+ assert valid_result_1 is True
+ assert (
+ valid_msg_1
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_2 = "pt:int"
+ valid_result_2, valid_msg_2 = _validate_content_type(
+ valid_content_type_2, content_name, performative
+ )
+ assert valid_result_2 is True
+ assert (
+ valid_msg_2
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_3 = "pt:set[pt:float]"
+ valid_result_3, valid_msg_3 = _validate_content_type(
+ valid_content_type_3, content_name, performative
+ )
+ assert valid_result_3 is True
+ assert (
+ valid_msg_3
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_4 = "pt:list[pt:bool]"
+ valid_result_4, valid_msg_4 = _validate_content_type(
+ valid_content_type_4, content_name, performative
+ )
+ assert valid_result_4 is True
+ assert (
+ valid_msg_4
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_5 = "pt:dict[pt:bool,pt:float]"
+ valid_result_5, valid_msg_5 = _validate_content_type(
+ valid_content_type_5, content_name, performative
+ )
+ assert valid_result_5 is True
+ assert (
+ valid_msg_5
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_6 = (
+ "pt:optional[pt:union[pt:bytes, pt:int, pt:float, pt:bool, pt:str, pt:set[pt:bytes], "
+ "pt:set[pt:int], pt:set[pt:float], pt:set[pt:bool], pt:set[pt:str], "
+ "pt:list[pt:bytes], pt:list[pt:int], pt:list[pt:float], pt:list[pt:bool], pt:list[pt:str], "
+ "pt:dict[pt:bytes, pt:bytes], pt:dict[ pt:bytes , pt:int ] , pt:dict[pt:bytes, pt:float], pt:dict[pt:bytes, pt:bool], pt:dict[pt:bytes, pt:str], "
+ "pt:dict[pt:int, pt:bytes], pt:dict[pt:int, pt:int], pt:dict[pt:int, pt:float], pt:dict[pt:int, pt:bool], pt:dict[pt:int, pt:str], "
+ "pt:dict[pt:float, pt:bytes], pt:dict[pt:float, pt:int], pt:dict[pt:float, pt:float], pt:dict[pt:float, pt:bool], pt:dict[pt:float, pt:str], "
+ "pt:dict[pt:bool, pt:bytes], pt:dict[pt:bool, pt:int], pt:dict[pt:bool,pt:float], pt:dict[pt:bool, pt:bool], pt:dict[pt:bool, pt:str], "
+ "pt:dict[pt:str, pt:bytes], pt:dict[pt:str, pt:int], pt:dict[pt:str,pt:float], pt:dict[pt:str, pt:bool], pt:dict[pt:str, pt:str]]]"
+ )
+ valid_result_6, valid_msg_6 = _validate_content_type(
+ valid_content_type_6, content_name, performative
+ )
+ assert valid_result_6 is True
+ assert (
+ valid_msg_6
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ valid_content_type_7 = (
+ " pt:optional[ pt:dict[ pt:float , pt:bool ] ] "
+ )
+ valid_result_7, valid_msg_7 = _validate_content_type(
+ valid_content_type_7, content_name, performative
+ )
+ assert valid_result_7 is True
+ assert (
+ valid_msg_7
+ == "Type of content '{}' of performative '{}' is valid.".format(
+ content_name, performative
+ )
+ )
+
+ ###################################################
+
+ invalid_content_type_1 = "ct:data"
+ invalid_result_1, invalid_msg_1 = _validate_content_type(
+ invalid_content_type_1, content_name, performative
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_2 = "bool"
+ invalid_result_2, invalid_msg_2 = _validate_content_type(
+ invalid_content_type_2, content_name, performative
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_3 = "pt: set[pt:int]"
+ invalid_result_3, invalid_msg_3 = _validate_content_type(
+ invalid_content_type_3, content_name, performative
+ )
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_4 = "pt:list[string]"
+ invalid_result_4, invalid_msg_4 = _validate_content_type(
+ invalid_content_type_4, content_name, performative
+ )
+ assert invalid_result_4 is False
+ assert (
+ invalid_msg_4
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_5 = "pt:dict[pt:bool, pt:integer]"
+ invalid_result_5, invalid_msg_5 = _validate_content_type(
+ invalid_content_type_5, content_name, performative
+ )
+ assert invalid_result_5 is False
+ assert (
+ invalid_msg_5
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_6 = "pt:union{pt:boolean, pt:int]"
+ invalid_result_6, invalid_msg_6 = _validate_content_type(
+ invalid_content_type_6, content_name, performative
+ )
+ assert invalid_result_6 is False
+ assert (
+ invalid_msg_6
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ invalid_content_type_7 = "pt:optional[pt:str, pt:int, pt:list[pt:bool]]"
+ invalid_result_7, invalid_msg_7 = _validate_content_type(
+ invalid_content_type_7, content_name, performative
+ )
+ assert invalid_result_7 is False
+ assert (
+ invalid_msg_7
+ == "Invalid type for content '{}' of performative '{}'. See documentation for the correct format of specification types.".format(
+ content_name, performative,
+ )
+ )
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification",)
+ def test_validate_speech_acts_section(self, mocked_spec):
+ """Test for the '_validate_speech_acts_section' method."""
+ valid_speech_act_content_config_1 = SpeechActContentConfig(
+ content_1="ct:CustomType", content_2="pt:int"
+ )
+ valid_speech_act_content_config_2 = SpeechActContentConfig(
+ content_3="ct:DataModel"
+ )
+ valid_speech_act_content_config_3 = SpeechActContentConfig()
+
+ speech_act_1 = CRUDCollection()
+ speech_act_1.create("perm_1", valid_speech_act_content_config_1)
+ speech_act_1.create("perm_2", valid_speech_act_content_config_2)
+ speech_act_1.create("perm_3", valid_speech_act_content_config_3)
+
+ mocked_spec.speech_acts = speech_act_1
+
+ (
+ valid_result_1,
+ valid_msg_1,
+ valid_all_per_1,
+ valid_all_content_1,
+ ) = _validate_speech_acts_section(mocked_spec)
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Speech-acts are valid."
+ assert valid_all_per_1 == {"perm_1", "perm_2", "perm_3"}
+ assert valid_all_content_1 == {"ct:CustomType", "ct:DataModel"}
+
+ ###################################################
+
+ speech_act_3 = CRUDCollection()
+ invalid_perm = "_query_"
+ speech_act_3.create(invalid_perm, valid_speech_act_content_config_1)
+
+ mocked_spec.speech_acts = speech_act_3
+
+ (
+ invalid_result_1,
+ invalid_msg_1,
+ invalid_all_per_1,
+ invalid_all_content_1,
+ ) = _validate_speech_acts_section(mocked_spec)
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Invalid name for performative '{}'. Performative names must match the following regular expression: {} ".format(
+ invalid_perm, PERFORMATIVE_REGEX_PATTERN
+ )
+ )
+ assert invalid_all_per_1 is None
+ assert invalid_all_content_1 is None
+
+ invalid_speech_act_content_config_1 = SpeechActContentConfig(target="pt:int")
+ speech_act_4 = CRUDCollection()
+ valid_perm = "perm_1"
+ speech_act_4.create(valid_perm, invalid_speech_act_content_config_1)
+
+ mocked_spec.speech_acts = speech_act_4
+
+ (
+ invalid_result_2,
+ invalid_msg_2,
+ invalid_all_per_2,
+ invalid_all_content_2,
+ ) = _validate_speech_acts_section(mocked_spec)
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Invalid name for content '{}' of performative '{}'. This name is reserved.".format(
+ "target", valid_perm,
+ )
+ )
+ assert invalid_all_per_2 is None
+ assert invalid_all_content_2 is None
+
+ invalid_speech_act_content_config_2 = SpeechActContentConfig(
+ conten_name_1="pt: set[pt:int]"
+ )
+ speech_act_5 = CRUDCollection()
+ valid_perm = "perm_1"
+ speech_act_5.create(valid_perm, invalid_speech_act_content_config_2)
+
+ mocked_spec.speech_acts = speech_act_5
+
+ (
+ invalid_result_3,
+ invalid_msg_3,
+ invalid_all_per_3,
+ invalid_all_content_3,
+ ) = _validate_speech_acts_section(mocked_spec)
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Invalid type for content 'conten_name_1' of performative '{}'. See documentation for the correct format of specification types.".format(
+ valid_perm,
+ )
+ )
+ assert invalid_all_per_3 is None
+ assert invalid_all_content_3 is None
+
+ speech_act_6 = CRUDCollection()
+ mocked_spec.speech_acts = speech_act_6
+
+ (
+ invalid_result_4,
+ invalid_msg_4,
+ invalid_all_per_4,
+ invalid_all_content_4,
+ ) = _validate_speech_acts_section(mocked_spec)
+ assert invalid_result_4 is False
+ assert invalid_msg_4 == "Speech-acts cannot be empty!"
+ assert invalid_all_per_4 is None
+ assert invalid_all_content_4 is None
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification",)
+ def test_validate_protocol_buffer_schema_code_snippets(self, mocked_spec):
+ """Test for the '_validate_protocol_buffer_schema_code_snippets' method."""
+ valid_protobuf_snippet_1 = {
+ "ct:DataModel": "bytes bytes_field = 1;\nint32 int_field = 2;\nfloat float_field = 3;\nbool bool_field = 4;\nstring str_field = 5;\nrepeated int32 set_field = 6;\nrepeated string list_field = 7;\nmap dict_field = 8;\n"
+ }
+ valid_all_content_1 = {"ct:DataModel"}
+ mocked_spec.protobuf_snippets = valid_protobuf_snippet_1
+
+ valid_result_1, valid_msg_1, = _validate_protocol_buffer_schema_code_snippets(
+ mocked_spec, valid_all_content_1
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Protobuf code snippet section is valid."
+
+ valid_protobuf_snippet_2 = {}
+ valid_all_content_2 = set()
+ mocked_spec.protobuf_snippets = valid_protobuf_snippet_2
+
+ valid_result_2, valid_msg_2, = _validate_protocol_buffer_schema_code_snippets(
+ mocked_spec, valid_all_content_2
+ )
+ assert valid_result_2 is True
+ assert valid_msg_2 == "Protobuf code snippet section is valid."
+
+ ###################################################
+
+ invalid_protobuf_snippet_1 = {
+ "ct:DataModel": "bytes bytes_field = 1;\nint32 int_field = 2;\nfloat float_field = 3;\nbool bool_field = 4;\nstring str_field = 5;",
+ "ct:Query": "bytes bytes_field = 1;",
+ }
+ invalid_all_content_1 = {"ct:DataModel"}
+ mocked_spec.protobuf_snippets = invalid_protobuf_snippet_1
+
+ (
+ invalid_result_1,
+ invalid_msg_1,
+ ) = _validate_protocol_buffer_schema_code_snippets(
+ mocked_spec, invalid_all_content_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Extra protobuf code snippet provided. Type 'ct:Query' is not used anywhere in your protocol definition."
+ )
+
+ invalid_protobuf_snippet_2 = {
+ "ct:DataModel": "bytes bytes_field = 1;\nint32 int_field = 2;\nfloat float_field = 3;",
+ }
+ invalid_all_content_2 = {"ct:DataModel", "ct:Frame"}
+ mocked_spec.protobuf_snippets = invalid_protobuf_snippet_2
+
+ (
+ invalid_result_2,
+ invalid_msg_2,
+ ) = _validate_protocol_buffer_schema_code_snippets(
+ mocked_spec, invalid_all_content_2
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "No protobuf code snippet is provided for the following custom types: {}".format(
+ {"ct:Frame"},
+ )
+ )
+
+ def test_validate_initiation(self):
+ """Test for the '_validate_initiation' method."""
+ valid_initiation_1 = ["perm_1", "perm_2"]
+ valid_performatives_set_1 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ valid_result_1, valid_msg_1 = _validate_initiation(
+ valid_initiation_1, valid_performatives_set_1
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Initial messages are valid."
+
+ ###################################################
+
+ invalid_initiation_1 = []
+ invalid_performatives_set_1 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ invalid_result_1, invalid_msg_1 = _validate_initiation(
+ invalid_initiation_1, invalid_performatives_set_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "At least one initial performative for this dialogue must be specified."
+ )
+
+ invalid_initiation_2 = ["perm_5"]
+ invalid_performatives_set_2 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ invalid_result_2, invalid_msg_2 = _validate_initiation(
+ invalid_initiation_2, invalid_performatives_set_2
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Performative 'perm_5' specified in \"initiation\" is not defined in the protocol's speech-acts."
+ )
+
+ def test_validate_reply(self):
+ """Test for the '_validate_reply' method."""
+ valid_reply_1 = {
+ "performative_ct": ["performative_pct"],
+ "performative_pt": ["performative_pmt"],
+ "performative_pct": ["performative_mt", "performative_o"],
+ "performative_pmt": ["performative_mt", "performative_o"],
+ "performative_mt": [],
+ "performative_o": [],
+ "performative_empty_contents": ["performative_empty_contents"],
+ }
+ valid_performatives_set_1 = {
+ "performative_ct",
+ "performative_pt",
+ "performative_pct",
+ "performative_pmt",
+ "performative_mt",
+ "performative_o",
+ "performative_empty_contents",
+ }
+
+ valid_result_1, valid_msg_1, = _validate_reply(
+ valid_reply_1, valid_performatives_set_1
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Reply structure is valid."
+
+ ###################################################
+
+ invalid_reply_1 = {
+ "perm_1": ["perm_2"],
+ "perm_2": ["perm_3"],
+ "perm_3": ["perm_4"],
+ "perm_4": [],
+ }
+ invalid_performatives_set_1 = {"perm_1", "perm_2", "perm_3", "perm_4", "perm_5"}
+
+ invalid_result_1, invalid_msg_1, = _validate_reply(
+ invalid_reply_1, invalid_performatives_set_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "No reply is provided for the following performatives: {}".format(
+ {"perm_5"},
+ )
+ )
+
+ invalid_reply_2 = {
+ "perm_1": ["perm_2"],
+ "perm_2": ["perm_3"],
+ "perm_3": ["perm_4"],
+ "perm_4": ["perm_5"],
+ "perm_5": [],
+ }
+ invalid_performatives_set_2 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+
+ invalid_result_2, invalid_msg_2, = _validate_reply(
+ invalid_reply_2, invalid_performatives_set_2
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Performative 'perm_5' specified in \"reply\" is not defined in the protocol's speech-acts."
+ )
+
+ def test_validate_termination(self):
+ """Test for the '_validate_termination' method."""
+ valid_termination_1 = ["perm_4", "perm_3"]
+ valid_performatives_set_1 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ valid_result_1, valid_msg_1 = _validate_termination(
+ valid_termination_1, valid_performatives_set_1
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Terminal messages are valid."
+
+ ###################################################
+
+ invalid_termination_1 = []
+ invalid_performatives_set_1 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ invalid_result_1, invalid_msg_1 = _validate_termination(
+ invalid_termination_1, invalid_performatives_set_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "At least one terminal performative for this dialogue must be specified."
+ )
+
+ invalid_termination_2 = ["perm_5"]
+ invalid_performatives_set_2 = {"perm_1", "perm_2", "perm_3", "perm_4"}
+ invalid_result_2, invalid_msg_2 = _validate_termination(
+ invalid_termination_2, invalid_performatives_set_2
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Performative 'perm_5' specified in \"termination\" is not defined in the protocol's speech-acts."
+ )
+
+ def test_validate_roles(self):
+ """Test for the '_validate_roles' method."""
+ valid_roles_1 = {"role_1", "role_2"}
+ valid_result_1, valid_msg_1 = _validate_roles(valid_roles_1)
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Dialogue roles are valid."
+
+ valid_roles_2 = {"role_1"}
+ valid_result_2, valid_msg_2 = _validate_roles(valid_roles_2)
+ assert valid_result_2 is True
+ assert valid_msg_2 == "Dialogue roles are valid."
+
+ ###################################################
+
+ invalid_roles_1 = set()
+ invalid_result_1, invalid_msg_1 = _validate_roles(invalid_roles_1)
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "There must be either 1 or 2 roles defined in this dialogue. Found 0"
+ )
+
+ invalid_roles_2 = {"role_1", "role_2", "role_3"}
+ invalid_result_2, invalid_msg_2 = _validate_roles(invalid_roles_2)
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "There must be either 1 or 2 roles defined in this dialogue. Found 3"
+ )
+
+ invalid_roles_3 = {"_agent_"}
+ invalid_result_3, invalid_msg_3 = _validate_roles(invalid_roles_3)
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Invalid name for role '_agent_'. Role names must match the following regular expression: {} ".format(
+ ROLE_REGEX_PATTERN
+ )
+ )
+
+ def test_validate_end_states(self):
+ """Test for the '_validate_end_states' method."""
+ valid_end_states_1 = ["end_state_1", "end_state_2"]
+ valid_result_1, valid_msg_1 = _validate_end_states(valid_end_states_1)
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Dialogue end_states are valid."
+
+ valid_end_states_2 = []
+ valid_result_2, valid_msg_2 = _validate_end_states(valid_end_states_2)
+ assert valid_result_2 is True
+ assert valid_msg_2 == "Dialogue end_states are valid."
+
+ ###################################################
+
+ invalid_end_states_1 = ["_end_state_1"]
+ invalid_result_1, invalid_msg_1 = _validate_end_states(invalid_end_states_1)
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Invalid name for end_state '_end_state_1'. End_state names must match the following regular expression: {} ".format(
+ END_STATE_REGEX_PATTERN
+ )
+ )
+
+ invalid_end_states_2 = ["end_$tate_1"]
+ invalid_result_2, invalid_msg_2 = _validate_end_states(invalid_end_states_2)
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "Invalid name for end_state 'end_$tate_1'. End_state names must match the following regular expression: {} ".format(
+ END_STATE_REGEX_PATTERN
+ )
+ )
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification",)
+ def test_validate_dialogue_section(self, mocked_spec):
+ """Test for the '_validate_dialogue_section' method."""
+ valid_dialogue_config_1 = {
+ "initiation": ["performative_ct", "performative_pt"],
+ "reply": {
+ "performative_ct": ["performative_pct"],
+ "performative_pt": ["performative_pmt"],
+ "performative_pct": ["performative_mt", "performative_o"],
+ "performative_pmt": ["performative_mt", "performative_o"],
+ "performative_mt": [],
+ "performative_o": [],
+ "performative_empty_contents": ["performative_empty_contents"],
+ },
+ "termination": [
+ "performative_mt",
+ "performative_o",
+ "performative_empty_contents",
+ ],
+ "roles": {"role_1": None, "role_2": None},
+ "end_states": ["end_state_1", "end_state_2", "end_state_3"],
+ }
+ valid_performatives_set_1 = {
+ "performative_ct",
+ "performative_pt",
+ "performative_pct",
+ "performative_pmt",
+ "performative_mt",
+ "performative_o",
+ "performative_empty_contents",
+ }
+ mocked_spec.dialogue_config = valid_dialogue_config_1
+
+ valid_result_1, valid_msg_1, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Dialogue section of the protocol specification is valid."
+
+ ###################################################
+
+ invalid_dialogue_config_1 = valid_dialogue_config_1.copy()
+ invalid_dialogue_config_1["initiation"] = ["new_performative"]
+
+ mocked_spec.dialogue_config = invalid_dialogue_config_1
+
+ invalid_result_1, invalid_msg_1, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert invalid_result_1 is False
+ assert (
+ invalid_msg_1
+ == "Performative 'new_performative' specified in \"initiation\" is not defined in the protocol's speech-acts."
+ )
+
+ invalid_dialogue_config_2 = valid_dialogue_config_1.copy()
+ invalid_dialogue_config_2["reply"] = {
+ "performative_ct": ["performative_pct"],
+ "performative_pt": ["performative_pmt"],
+ "performative_pct": ["performative_mt", "performative_o"],
+ "performative_pmt": ["performative_mt", "performative_o"],
+ "performative_mt": [],
+ "performative_o": [],
+ }
+
+ mocked_spec.dialogue_config = invalid_dialogue_config_2
+
+ invalid_result_2, invalid_msg_2, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert invalid_result_2 is False
+ assert (
+ invalid_msg_2
+ == "No reply is provided for the following performatives: {}".format(
+ {"performative_empty_contents"},
+ )
+ )
+
+ invalid_dialogue_config_3 = valid_dialogue_config_1.copy()
+ invalid_dialogue_config_3["termination"] = ["new_performative"]
+
+ mocked_spec.dialogue_config = invalid_dialogue_config_3
+
+ invalid_result_3, invalid_msg_3, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert invalid_result_3 is False
+ assert (
+ invalid_msg_3
+ == "Performative 'new_performative' specified in \"termination\" is not defined in the protocol's speech-acts."
+ )
+
+ invalid_dialogue_config_4 = valid_dialogue_config_1.copy()
+ invalid_dialogue_config_4["roles"] = {
+ "role_1": None,
+ "role_2": None,
+ "role_3": None,
+ }
+
+ mocked_spec.dialogue_config = invalid_dialogue_config_4
+
+ invalid_result_4, invalid_msg_4, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert invalid_result_4 is False
+ assert (
+ invalid_msg_4
+ == "There must be either 1 or 2 roles defined in this dialogue. Found 3"
+ )
+
+ invalid_dialogue_config_5 = valid_dialogue_config_1.copy()
+ invalid_dialogue_config_5["end_states"] = ["end_$tate_1"]
+
+ mocked_spec.dialogue_config = invalid_dialogue_config_5
+
+ invalid_result_5, invalid_msg_5, = _validate_dialogue_section(
+ mocked_spec, valid_performatives_set_1
+ )
+ assert invalid_result_5 is False
+ assert (
+ invalid_msg_5
+ == "Invalid name for end_state 'end_$tate_1'. End_state names must match the following regular expression: {} ".format(
+ END_STATE_REGEX_PATTERN
+ )
+ )
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification")
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_speech_acts_section",
+ return_value=tuple([True, "Speech_acts are correct!", set(), set()]),
+ )
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets",
+ return_value=tuple([True, "Protobuf snippets are correct!"]),
+ )
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_dialogue_section",
+ return_value=tuple([True, "Dialogue section is correct!"]),
+ )
+ def test_validate_positive(
+ self,
+ mocked_spec,
+ macked_validate_speech_acts,
+ macked_validate_protobuf,
+ macked_validate_dialogue,
+ ):
+ """Positive test for the 'validate' method: invalid dialogue section."""
+ valid_result_1, valid_msg_1, = validate(mocked_spec)
+ assert valid_result_1 is True
+ assert valid_msg_1 == "Protocol specification is valid."
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification")
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_speech_acts_section",
+ return_value=tuple([False, "Some error on speech_acts.", None, None]),
+ )
+ def test_validate_negative_invalid_speech_acts(
+ self, mocked_spec, macked_validate_speech_acts
+ ):
+ """Negative test for the 'validate' method: invalid speech_acts."""
+ invalid_result_1, invalid_msg_1, = validate(mocked_spec)
+ assert invalid_result_1 is False
+ assert invalid_msg_1 == "Some error on speech_acts."
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification")
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_speech_acts_section",
+ return_value=tuple([True, "Speech_acts are correct!", set(), set()]),
+ )
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets",
+ return_value=tuple([False, "Some error on protobuf snippets."]),
+ )
+ def test_validate_negative_invalid_protobuf_snippets(
+ self, mocked_spec, macked_validate_speech_acts, macked_validate_protobuf
+ ):
+ """Negative test for the 'validate' method: invalid protobuf snippets."""
+ invalid_result_1, invalid_msg_1, = validate(mocked_spec)
+ assert invalid_result_1 is False
+ assert invalid_msg_1 == "Some error on protobuf snippets."
+
+ @mock.patch("aea.configurations.base.ProtocolSpecification")
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_speech_acts_section",
+ return_value=tuple([True, "Speech_acts are correct!", set(), set()]),
+ )
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_protocol_buffer_schema_code_snippets",
+ return_value=tuple([True, "Protobuf snippets are correct!"]),
+ )
+ @mock.patch(
+ "aea.protocols.generator.validate._validate_dialogue_section",
+ return_value=tuple([False, "Some error on dialogue section."]),
+ )
+ def test_validate_negative_invalid_dialogue_section(
+ self,
+ mocked_spec,
+ macked_validate_speech_acts,
+ macked_validate_protobuf,
+ macked_validate_dialogue,
+ ):
+ """Negative test for the 'validate' method: invalid dialogue section."""
+ invalid_result_1, invalid_msg_1, = validate(mocked_spec)
+ assert invalid_result_1 is False
+ assert invalid_msg_1 == "Some error on dialogue section."
diff --git a/tests/test_registries/test_base.py b/tests/test_registries/test_base.py
index 1b5ea7ed80..e27399d787 100644
--- a/tests/test_registries/test_base.py
+++ b/tests/test_registries/test_base.py
@@ -80,7 +80,7 @@ def setup_class(cls):
cls.registry = AgentComponentRegistry()
cls.registry.register(contract.component_id, cast(Contract, contract))
cls.expected_contract_ids = {
- PublicId.from_str("fetchai/erc1155:0.6.0"),
+ PublicId.from_str("fetchai/erc1155:0.7.0"),
}
def test_fetch_all(self):
@@ -91,14 +91,14 @@ def test_fetch_all(self):
def test_fetch(self):
"""Test that the `fetch` method works as expected."""
- contract_id = PublicId.from_str("fetchai/erc1155:0.6.0")
+ contract_id = PublicId.from_str("fetchai/erc1155:0.7.0")
contract = self.registry.fetch(ComponentId(ComponentType.CONTRACT, contract_id))
assert isinstance(contract, Contract)
assert contract.id == contract_id
def test_unregister(self):
"""Test that the 'unregister' method works as expected."""
- contract_id_removed = PublicId.from_str("fetchai/erc1155:0.6.0")
+ contract_id_removed = PublicId.from_str("fetchai/erc1155:0.7.0")
component_id = ComponentId(ComponentType.CONTRACT, contract_id_removed)
contract_removed = self.registry.fetch(component_id)
self.registry.unregister(contract_removed.component_id)
@@ -153,7 +153,7 @@ def setup_class(cls):
cls.expected_protocol_ids = {
DEFAULT_PROTOCOL,
- PublicId.from_str("fetchai/fipa:0.4.0"),
+ PublicId.from_str("fetchai/fipa:0.5.0"),
}
def test_fetch_all(self):
@@ -244,7 +244,7 @@ def setup_class(cls):
cls.error_skill_public_id = DEFAULT_SKILL
cls.dummy_skill_public_id = PublicId.from_str("dummy_author/dummy:0.1.0")
- cls.contract_public_id = PublicId.from_str("fetchai/erc1155:0.6.0")
+ cls.contract_public_id = PublicId.from_str("fetchai/erc1155:0.7.0")
def test_unregister_handler(self):
"""Test that the unregister of handlers work correctly."""
@@ -390,24 +390,6 @@ def test_add_component_raises_error(self):
with pytest.raises(ValueError):
self.resources.add_component(a_component)
- def test_inject_contracts_unknown_contract(self):
- """Test inject contracts when there is a missing contract."""
- public_id = PublicId.from_str("author/name:0.1.0")
- mock_skill = MagicMock(**{"config.contracts": {public_id}})
- with pytest.raises(
- ValueError, match=f"Missing contract for contract id {public_id}"
- ):
- self.resources.inject_contracts(mock_skill)
-
- def test_inject_contracts(self):
- """Test inject contracts."""
- with unittest.mock.patch.object(
- self.resources._component_registry, "fetch", return_value=object()
- ):
- public_id = PublicId.from_str("author/name:0.1.0")
- mock_skill = MagicMock(**{"config.contracts": {public_id}})
- self.resources.inject_contracts(mock_skill)
-
def test_register_behaviour_with_already_existing_skill_id(self):
"""Test that registering a behaviour with an already existing skill id behaves as expected."""
# this should raise an error, since the 'dummy" skill already has a behaviour named "dummy"
@@ -535,11 +517,13 @@ def test_handle_internal_messages(self):
"""Test that the internal messages are handled."""
t = SigningMessage(
performative=SigningMessage.Performative.SIGNED_TRANSACTION,
- skill_callback_ids=[str(PublicId("dummy_author", "dummy", "0.1.0"))],
+ skill_callback_ids=(str(PublicId("dummy_author", "dummy", "0.1.0")),),
skill_callback_info={},
- crypto_id="ledger_id",
+ # crypto_id="ledger_id",
signed_transaction=SignedTransaction("ledger_id", "tx"),
)
+ t.counterparty = "skill"
+ t.sender = "decision_maker"
self.aea.decision_maker.message_out_queue.put(t)
self.aea._filter.handle_internal_messages()
@@ -667,6 +651,30 @@ def setup_class(cls):
"""Set up the tests."""
cls.registry = HandlerRegistry()
+ def test_register_and_unregister_dynamically(self):
+ """Test register when protocol id is None."""
+ assert len(self.registry._dynamically_added) == 0
+ self.registry.register(
+ (PublicId.from_str("author/name:0.1.0"), "name"),
+ MagicMock(SUPPORTED_PROTOCOL="author/protocol:0.1.0"),
+ is_dynamically_added=True,
+ )
+ assert len(self.registry._dynamically_added) == 1
+ self.registry.unregister((PublicId.from_str("author/name:0.1.0"), "name"),)
+ assert len(self.registry._dynamically_added) == 0
+
+ def test_register_and_teardown_dynamically(self):
+ """Test register when protocol id is None."""
+ assert len(self.registry._dynamically_added) == 0
+ self.registry.register(
+ (PublicId.from_str("author/name:0.1.0"), "name"),
+ MagicMock(SUPPORTED_PROTOCOL="author/protocol:0.1.0"),
+ is_dynamically_added=True,
+ )
+ assert len(self.registry._dynamically_added) == 1
+ self.registry.teardown()
+ assert len(self.registry._dynamically_added) == 0
+
def test_register_when_protocol_id_is_none(self):
"""Test register when protocol id is None."""
with pytest.raises(
diff --git a/tests/test_registries/test_filter.py b/tests/test_registries/test_filter.py
index bfbd93323a..ff5ed6cf5a 100644
--- a/tests/test_registries/test_filter.py
+++ b/tests/test_registries/test_filter.py
@@ -29,6 +29,7 @@
from aea.skills.base import Skill
from tests.data.dummy_skill.behaviours import DummyBehaviour
+from tests.data.dummy_skill.handlers import DummyHandler
class TestFilter:
@@ -142,6 +143,52 @@ def test_handle_internal_message_new_behaviours_with_error(self):
# restore previous state
self.resources.component_registry.unregister(skill.component_id)
+ def test_handle_internal_message_new_handlers(self):
+ """Test handle internal message when there are new handlers to register."""
+ skill = Skill(
+ SkillConfig("name", "author", "0.1.0"),
+ handlers={},
+ behaviours={},
+ models={},
+ )
+ self.resources.add_skill(skill)
+ new_handler = DummyHandler(name="dummy2", skill_context=skill.skill_context)
+ skill.skill_context.new_handlers.put(new_handler)
+ self.filter.handle_internal_messages()
+
+ assert self.decision_make_queue.empty()
+ assert len(self.resources.handler_registry.fetch_all()) == 1
+ # restore previous state
+ self.resources.remove_skill(skill.public_id)
+ assert len(self.resources.handler_registry.fetch_all()) == 0
+
+ def test_handle_internal_message_new_handlers_with_error(self):
+ """Test handle internal message when an error happens while registering a new handler."""
+ skill = Skill(
+ SkillConfig("name", "author", "0.1.0"),
+ handlers={},
+ behaviours={},
+ models={},
+ )
+ self.resources.add_skill(skill)
+ new_handler = DummyHandler(name="dummy2", skill_context=skill.skill_context)
+ with unittest.mock.patch.object(
+ self.resources.handler_registry, "register", side_effect=ValueError
+ ):
+ with unittest.mock.patch.object(
+ aea.registries.filter.logger, "warning"
+ ) as mock_logger_warning:
+ skill.skill_context.new_handlers.put(new_handler)
+ self.filter.handle_internal_messages()
+
+ mock_logger_warning.assert_called_with(
+ "Error when trying to add a new handler: "
+ )
+ assert self.decision_make_queue.empty()
+ assert len(self.resources.handler_registry.fetch_all()) == 0
+ # restore previous state
+ self.resources.component_registry.unregister(skill.component_id)
+
def test_handle_signing_message(self):
"""Test the handling of a signing message."""
public_id = "author/non_existing_skill:0.1.0"
diff --git a/tests/test_skills/test_base.py b/tests/test_skills/test_base.py
index 89f86b1170..13105caffa 100644
--- a/tests/test_skills/test_base.py
+++ b/tests/test_skills/test_base.py
@@ -17,25 +17,43 @@
#
# ------------------------------------------------------------------------------
-"""This module contains the tests for the base classes for the skills."""
+"""This module contains the tests for the base classes for the skills."""
+import unittest.mock
+from pathlib import Path
from queue import Queue
+from types import SimpleNamespace
from unittest import TestCase, mock
-from unittest.mock import Mock
+from unittest.mock import MagicMock, Mock
+import pytest
+
+import aea
from aea.aea import AEA
-from aea.connections.base import ConnectionStatus
+from aea.configurations.base import PublicId, SkillComponentConfiguration
from aea.crypto.wallet import Wallet
from aea.decision_maker.default import GoalPursuitReadiness, OwnershipState, Preferences
+from aea.exceptions import AEAException
from aea.identity.base import Identity
+from aea.multiplexer import ConnectionStatus
from aea.registries.resources import Resources
-from aea.skills.base import SkillComponent, SkillContext
+from aea.skills.base import (
+ Behaviour,
+ Handler,
+ Model,
+ Skill,
+ SkillComponent,
+ SkillContext,
+ _check_duplicate_classes,
+ _print_warning_message_for_non_declared_skill_components,
+)
from tests.conftest import (
COSMOS,
COSMOS_PRIVATE_KEY_PATH,
ETHEREUM,
ETHEREUM_PRIVATE_KEY_PATH,
+ ROOT_DIR,
_make_dummy_connection,
)
@@ -55,7 +73,9 @@ def setup_class(cls):
)
cls.my_aea = AEA(cls.identity, cls.wallet, resources=Resources())
cls.my_aea.resources.add_connection(cls.connection)
- cls.skill_context = SkillContext(cls.my_aea.context)
+ cls.skill_context = SkillContext(
+ cls.my_aea.context, skill=MagicMock(contracts={})
+ )
def test_agent_name(self):
"""Test the agent's name."""
@@ -101,6 +121,44 @@ def test_message_in_queue(self):
"""Test the 'message_in_queue' property."""
assert isinstance(self.skill_context.message_in_queue, Queue)
+ def test_logger_setter(self):
+ """Test the logger setter."""
+ logger = self.skill_context.logger
+ self.skill_context._logger = None
+ self.skill_context.logger = logger
+ assert self.skill_context.logger == logger
+
+ def test_agent_context_setter(self):
+ """Test the agent context setter."""
+ agent_context = self.skill_context._agent_context
+ self.skill_context.set_agent_context(agent_context)
+ assert self.skill_context.agent_name == agent_context.agent_name
+ assert self.skill_context.agent_address == agent_context.address
+ assert self.skill_context.agent_addresses == agent_context.addresses
+
+ def test_is_active_property(self):
+ """Test is_active property getter."""
+ assert self.skill_context.is_active is True
+
+ def test_new_behaviours_queue(self):
+ """Test 'new_behaviours_queue' property getter."""
+ assert isinstance(self.skill_context.new_behaviours, Queue)
+
+ def test_new_handlers_queue(self):
+ """Test 'new_behaviours_queue' property getter."""
+ assert isinstance(self.skill_context.new_handlers, Queue)
+
+ def test_search_service_address(self):
+ """Test 'search_service_address' property getter."""
+ assert (
+ self.skill_context.search_service_address
+ == self.my_aea.context.search_service_address
+ )
+
+ def test_namespace(self):
+ """Test the 'namespace' property getter."""
+ assert isinstance(self.skill_context.namespace, SimpleNamespace)
+
@classmethod
def teardown_class(cls):
"""Test teardown."""
@@ -125,7 +183,7 @@ def test_skill_id_positive(self):
obj._skill.config.public_id = "public_id"
obj.skill_id
- @mock.patch("aea.skills.base.logger.debug")
+ @mock.patch("aea.skills.base._default_logger.debug")
@mock.patch("aea.skills.base.SkillContext.skill_id")
def test_is_active_positive(self, skill_id_mock, debug_mock):
"""Test is_active setter positive result"""
@@ -217,3 +275,189 @@ def test_config_positive(self):
configuration=Mock(args={}), skill_context="ctx", name="name"
)
component.config
+
+ def test_kwargs_not_empty(self):
+ """Test the case when there are some kwargs not-empty"""
+ kwargs = dict(foo="bar")
+ component_name = "component_name"
+ skill_context = SkillContext()
+ with mock.patch.object(skill_context.logger, "warning") as mock_logger:
+ self.TestComponent(component_name, skill_context, **kwargs)
+ mock_logger.assert_any_call(
+ f"The kwargs={kwargs} passed to {component_name} have not been set!"
+ )
+
+
+def test_load_skill():
+ """Test the loading of a skill."""
+ agent_context = MagicMock()
+ skill = Skill.from_dir(
+ Path(ROOT_DIR, "tests", "data", "dummy_skill"), agent_context=agent_context
+ )
+ assert isinstance(skill, Skill)
+
+
+def test_behaviour():
+ """Test behaviour initialization."""
+
+ class CustomBehaviour(Behaviour):
+ def setup(self) -> None:
+ pass
+
+ def teardown(self) -> None:
+ pass
+
+ def act(self) -> None:
+ pass
+
+ behaviour = CustomBehaviour("behaviour", skill_context=MagicMock())
+
+ # test getters (default values)
+ assert behaviour.tick_interval == 0.001
+ assert behaviour.start_at is None
+ assert behaviour.is_done() is False
+
+
+def test_behaviour_parse_module_without_configs():
+ """call Behaviour.parse_module without configurations."""
+ assert Behaviour.parse_module(MagicMock(), {}, MagicMock()) == {}
+
+
+def test_behaviour_parse_module_missing_class():
+ """Test Behaviour.parse_module when a class is missing."""
+ skill_context = SkillContext(
+ skill=MagicMock(skill_id=PublicId.from_str("author/name:0.1.0"))
+ )
+ dummy_behaviours_path = Path(
+ ROOT_DIR, "tests", "data", "dummy_skill", "behaviours.py"
+ )
+ with unittest.mock.patch.object(
+ aea.skills.base._default_logger, "warning"
+ ) as mock_logger_warning:
+ behaviours_by_id = Behaviour.parse_module(
+ dummy_behaviours_path,
+ {
+ "dummy_behaviour": SkillComponentConfiguration("DummyBehaviour"),
+ "unknown_behaviour": SkillComponentConfiguration("UnknownBehaviour"),
+ },
+ skill_context,
+ )
+ mock_logger_warning.assert_called_with(
+ "Behaviour 'UnknownBehaviour' cannot be found."
+ )
+ assert "dummy_behaviour" in behaviours_by_id
+
+
+def test_handler_parse_module_without_configs():
+ """call Handler.parse_module without configurations."""
+ assert Handler.parse_module(MagicMock(), {}, MagicMock()) == {}
+
+
+def test_handler_parse_module_missing_class():
+ """Test Handler.parse_module when a class is missing."""
+ skill_context = SkillContext(
+ skill=MagicMock(skill_id=PublicId.from_str("author/name:0.1.0"))
+ )
+ dummy_handlers_path = Path(ROOT_DIR, "tests", "data", "dummy_skill", "handlers.py")
+ with unittest.mock.patch.object(
+ aea.skills.base._default_logger, "warning"
+ ) as mock_logger_warning:
+ behaviours_by_id = Handler.parse_module(
+ dummy_handlers_path,
+ {
+ "dummy_handler": SkillComponentConfiguration("DummyHandler"),
+ "unknown_handelr": SkillComponentConfiguration("UnknownHandler"),
+ },
+ skill_context,
+ )
+ mock_logger_warning.assert_called_with(
+ "Handler 'UnknownHandler' cannot be found."
+ )
+ assert "dummy_handler" in behaviours_by_id
+
+
+def test_model_parse_module_without_configs():
+ """call Model.parse_module without configurations."""
+ assert Model.parse_module(MagicMock(), {}, MagicMock()) == {}
+
+
+def test_model_parse_module_missing_class():
+ """Test Model.parse_module when a class is missing."""
+ skill_context = SkillContext(
+ skill=MagicMock(skill_id=PublicId.from_str("author/name:0.1.0"))
+ )
+ dummy_models_path = Path(ROOT_DIR, "tests", "data", "dummy_skill")
+ with unittest.mock.patch.object(
+ aea.skills.base._default_logger, "warning"
+ ) as mock_logger_warning:
+ models_by_id = Model.parse_module(
+ dummy_models_path,
+ {
+ "dummy_model": SkillComponentConfiguration("DummyModel"),
+ "unknown_model": SkillComponentConfiguration("UnknownModel"),
+ },
+ skill_context,
+ )
+ mock_logger_warning.assert_called_with("Model 'UnknownModel' cannot be found.")
+ assert "dummy_model" in models_by_id
+
+
+def test_check_duplicate_classes():
+ """Test check duplicate classes."""
+ with pytest.raises(
+ AEAException,
+ match="Model 'ModelClass' present both in path_1 and path_2. Remove one of them.",
+ ):
+ _check_duplicate_classes(
+ [
+ ("ModelClass", MagicMock(__module__="path_1")),
+ ("ModelClass", MagicMock(__module__="path_2")),
+ ]
+ )
+
+
+def test_print_warning_message_for_non_declared_skill_components():
+ """Test the helper function '_print_warning_message_for_non_declared_skill_components'."""
+ with unittest.mock.patch.object(
+ aea.skills.base._default_logger, "warning"
+ ) as mock_logger_warning:
+ _print_warning_message_for_non_declared_skill_components(
+ SkillContext(),
+ {"unknown_class_1", "unknown_class_2"},
+ set(),
+ "type",
+ "path",
+ )
+ mock_logger_warning.assert_any_call(
+ "Class unknown_class_1 of type type found but not declared in the configuration file path."
+ )
+ mock_logger_warning.assert_any_call(
+ "Class unknown_class_2 of type type found but not declared in the configuration file path."
+ )
+
+
+class TestSkill:
+ """Test skill attributes."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set the tests up."""
+ cls.skill = Skill.from_dir(
+ Path(ROOT_DIR, "tests", "data", "dummy_skill"),
+ MagicMock(agent_name="agent_name"),
+ )
+
+ def test_logger(self):
+ """Test the logger getter."""
+ self.skill.logger
+
+ def test_logger_setter_raises_error(self):
+ """Test that the logger setter raises error."""
+ with pytest.raises(ValueError, match="Cannot set logger to a skill component."):
+ logger = self.skill.logger
+ self.skill.logger = logger
+
+ def test_skill_context(self):
+ """Test the skill context getter."""
+ context = self.skill.skill_context
+ assert isinstance(context, SkillContext)
diff --git a/tests/test_skills/test_error.py b/tests/test_skills/test_error.py
index 404ceedf29..38bdae7f44 100644
--- a/tests/test_skills/test_error.py
+++ b/tests/test_skills/test_error.py
@@ -21,13 +21,15 @@
import logging
import os
+import unittest.mock
from threading import Thread
from aea.aea import AEA
+from aea.configurations.base import PublicId
from aea.configurations.constants import DEFAULT_LEDGER, DEFAULT_PRIVATE_KEY_FILE
from aea.crypto.wallet import Wallet
from aea.identity.base import Identity
-from aea.mail.base import Envelope
+from aea.mail.base import Envelope, EnvelopeContext, URI
from aea.multiplexer import InBox, Multiplexer
from aea.protocols.default.message import DefaultMessage
from aea.registries.resources import Resources
@@ -167,10 +169,11 @@ def test_error_unsupported_skill(self):
performative=FipaMessage.Performative.ACCEPT,
)
msg.counterparty = self.address
+ msg.sender = self.address
envelope = Envelope(
- to=self.address,
- sender=self.address,
- protocol_id=DefaultMessage.protocol_id,
+ to=msg.counterparty,
+ sender=msg.sender,
+ protocol_id=msg.protocol_id,
message=msg,
)
@@ -183,6 +186,26 @@ def test_error_unsupported_skill(self):
assert msg.performative == DefaultMessage.Performative.ERROR
assert msg.error_code == DefaultMessage.ErrorCode.UNSUPPORTED_SKILL
+ def test_error_unsupported_skill_when_skill_id_is_none(self):
+ """Test the 'send_unsupported_skill' when the skill id in the envelope is None."""
+ skill_id = PublicId.from_str("author/skill:0.1.0")
+ protocol_id = PublicId.from_str("author/name:0.1.0")
+ envelope = Envelope(
+ to="",
+ sender="",
+ protocol_id=protocol_id,
+ message=b"",
+ context=EnvelopeContext(uri=URI(skill_id.to_uri_path)),
+ )
+ with unittest.mock.patch.object(self.skill_context.outbox, "put_message"):
+ with unittest.mock.patch.object(
+ self.skill_context._logger, "warning"
+ ) as mock_logger_warning:
+ self.my_error_handler.send_unsupported_skill(envelope)
+ mock_logger_warning.assert_called_with(
+ f"Cannot handle envelope: no active handler registered for the protocol_id='{protocol_id}' and skill_id='{skill_id}'."
+ )
+
def teardown(self):
"""Teardown method."""
self.my_aea.stop()
diff --git a/tests/test_skills/test_scaffold.py b/tests/test_skills/test_scaffold.py
new file mode 100644
index 0000000000..588f31662a
--- /dev/null
+++ b/tests/test_skills/test_scaffold.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 tests for the scaffold skill."""
+from unittest.mock import MagicMock
+
+import pytest
+
+from aea.skills.base import SkillContext
+from aea.skills.scaffold.behaviours import MyScaffoldBehaviour
+from aea.skills.scaffold.handlers import MyScaffoldHandler
+from aea.skills.scaffold.my_model import MyModel
+
+
+class TestScaffoldHandler:
+ """Tests for the scaffold handler."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set up the tests."""
+ cls.handler = MyScaffoldHandler("handler", SkillContext())
+
+ def test_supported_protocol(self):
+ """Test that the supported protocol is None."""
+ assert self.handler.SUPPORTED_PROTOCOL is None
+
+ def test_setup(self):
+ """Test that the setup method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.handler.setup()
+
+ def test_handle(self):
+ """Test that the handle method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.handler.handle(MagicMock())
+
+ def test_teardown(self):
+ """Test that the teardown method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.handler.teardown()
+
+
+class TestScaffoldBehaviour:
+ """Tests for the scaffold behaviour."""
+
+ @classmethod
+ def setup_class(cls):
+ """Set up the tests."""
+ cls.behaviour = MyScaffoldBehaviour("behaviour", SkillContext())
+
+ def test_setup(self):
+ """Test that the setup method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.behaviour.setup()
+
+ def test_handle(self):
+ """Test that the handle method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.behaviour.act()
+
+ def test_teardown(self):
+ """Test that the teardown method raises 'NotImplementedError'."""
+ with pytest.raises(NotImplementedError):
+ self.behaviour.teardown()
+
+
+def test_model_initialization():
+ """Test scaffold model initialization."""
+ MyModel("model", SkillContext())
diff --git a/tests/test_skills/test_tasks.py b/tests/test_skills/test_tasks.py
index 79bcc4049a..4308e14740 100644
--- a/tests/test_skills/test_tasks.py
+++ b/tests/test_skills/test_tasks.py
@@ -47,15 +47,15 @@ def test_call_already_executed(self):
with self.assertRaises(ValueError):
obj()
- @mock.patch("aea.skills.tasks.logger.debug")
- def test_call_exception_while_executing(self, debug_mock):
+ def test_call_exception_while_executing(self):
"""Test call obj exception raised while executing."""
obj = Task()
- obj.setup = mock.Mock()
- obj.execute = _raise_exception
- obj.teardown = mock.Mock()
- obj()
- debug_mock.assert_called_once()
+ with mock.patch.object(obj.logger, "debug") as debug_mock:
+ obj.setup = mock.Mock()
+ obj.execute = _raise_exception
+ obj.teardown = mock.Mock()
+ obj()
+ debug_mock.assert_called_once()
def test_is_executed_positive(self):
"""Test is_executed property positive result."""
@@ -93,20 +93,31 @@ def test_nb_workers_positive(self):
obj = TaskManager()
obj.nb_workers
- @mock.patch("aea.skills.tasks.logger.debug")
- def test_stop_already_stopped(self, debug_mock):
+ def test_stop_already_stopped(self):
"""Test stop method already stopped."""
obj = TaskManager()
- obj.stop()
- debug_mock.assert_called_once()
+ with mock.patch.object(obj.logger, "debug") as debug_mock:
+ obj.stop()
+ debug_mock.assert_called_once()
- @mock.patch("aea.skills.tasks.logger.debug")
- def test_start_already_started(self, debug_mock):
+ def test_start_already_started(self):
"""Test start method already started."""
obj = TaskManager()
- obj._stopped = False
- obj.start()
- debug_mock.assert_called_once()
+ with mock.patch.object(obj.logger, "debug") as debug_mock:
+ obj._stopped = False
+ obj.start()
+ debug_mock.assert_called_once()
+ obj.stop()
+
+ def test_start_lazy_pool_start(self):
+ """Test start method with lazy pool start."""
+ obj = TaskManager(is_lazy_pool_start=False)
+ with mock.patch.object(obj.logger, "debug") as debug_mock:
+ obj.start()
+ obj._stopped = True
+ obj.start()
+ debug_mock.assert_called_with("Pool was already started!")
+ obj.start()
def test_enqueue_task_stopped(self):
"""Test enqueue_task method manager stopped."""
diff --git a/tests/test_test_tools/test_click_testing.py b/tests/test_test_tools/test_click_testing.py
new file mode 100644
index 0000000000..f020666c2a
--- /dev/null
+++ b/tests/test_test_tools/test_click_testing.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 a test for aea.test_tools."""
+from unittest.mock import patch
+
+import pytest
+
+from aea.cli.core import cli
+from aea.test_tools.click_testing import CliRunner
+
+
+def test_invoke():
+ """Test runner invoke method."""
+ cli_runner = CliRunner()
+
+ result = cli_runner.invoke(cli, ["--help"])
+ assert (
+ "Command-line tool for setting up an Autonomous Economic Agent" in result.output
+ )
+
+ result = cli_runner.invoke(cli, "--help")
+ assert (
+ "Command-line tool for setting up an Autonomous Economic Agent" in result.output
+ )
+
+
+def test_invoke_error():
+ """Test runner invoke method raises an error."""
+ cli_runner = CliRunner()
+
+ with patch.object(cli, "main", side_effect=SystemExit(1)):
+ result = cli_runner.invoke(cli, ["--help"])
+ assert result.exit_code == 1
+
+ with patch.object(cli, "main", side_effect=SystemExit(object())):
+ result = cli_runner.invoke(cli, ["--help"])
+ assert result.exit_code == 1
+
+
+def test_catch_exception():
+ """Test runner invoke method raises an exception and its propogated."""
+ cli_runner = CliRunner()
+
+ # True
+ with patch.object(cli, "main", side_effect=ValueError("expected")):
+ result = cli_runner.invoke(cli, ["--help"])
+ assert result.exit_code == 1
+
+ # False
+
+ with pytest.raises(ValueError, match="expected"):
+ with patch.object(cli, "main", side_effect=ValueError("expected")):
+ result = cli_runner.invoke(cli, ["--help"], catch_exceptions=False)
+
+
+def test_mix_std_err_False():
+ """Test stderr and stdout not mixed."""
+ cli_runner = CliRunner(mix_stderr=False)
+
+ result = cli_runner.invoke(cli, "-v DEBUG run")
+ assert result.exit_code == 1
+ # check for access, no exception should be raised
+ result.stderr
+
+
+def test_mix_std_err_True():
+ """Test stderr and stdout are mixed."""
+ cli_runner = CliRunner(mix_stderr=True)
+
+ result = cli_runner.invoke(cli, "-v DEBUG run")
+ assert result.exit_code == 1
+
+ with pytest.raises(ValueError):
+ result.stderr
diff --git a/tests/test_test_tools/test_testcases.py b/tests/test_test_tools/test_testcases.py
new file mode 100644
index 0000000000..900c92c1de
--- /dev/null
+++ b/tests/test_test_tools/test_testcases.py
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+# ------------------------------------------------------------------------------
+#
+# Copyright 2018-2019 Fetch.AI Limited
+#
+# 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 a test for aea.test_tools.test_cases."""
+
+import os
+from pathlib import Path
+
+
+from aea.test_tools.test_cases import AEATestCase, AEATestCaseEmpty
+
+
+class TestGenericCases(AEATestCaseEmpty):
+ """Tests test for generic cases of AEATestCases."""
+
+ def test_disable_aea_logging(self):
+ """Call logging disable."""
+ self.disable_aea_logging()
+
+ def test_start_subprocess(self):
+ """Start a python subprocess and check output."""
+ proc = self.start_subprocess("-c", "print('hi')")
+ proc.wait(10)
+
+ assert "hi" in self.stdout[proc.pid]
+
+ def test_start_thread(self):
+ """Start and join thread for python code."""
+ called = False
+
+ def fn():
+ nonlocal called
+ called = True
+
+ thread = self.start_thread(fn)
+ thread.join(10)
+ assert called
+
+ def test_fetch_and_delete(self):
+ """Fetch and delete agent from repo."""
+ agent_name = "some_agent_for_tests"
+ self.fetch_agent("fetchai/my_first_aea:0.8.0", agent_name)
+ assert os.path.exists(agent_name)
+ self.delete_agents(agent_name)
+ assert not os.path.exists(agent_name)
+
+ def test_diff(self):
+ """Test difference_to_fetched_agent."""
+ agent_name = "some_agent_for_tests2"
+ self.fetch_agent("fetchai/my_first_aea:0.8.0", agent_name)
+ self.run_cli_command(
+ "config", "set", "agent.default_ledger", "test_ledger", cwd=agent_name
+ )
+ result = self.run_cli_command(
+ "config", "get", "agent.default_ledger", cwd=agent_name
+ )
+ assert b"test_ledger" in result.stdout_bytes
+ diff = self.difference_to_fetched_agent(
+ "fetchai/my_first_aea:0.8.0", agent_name
+ )
+ assert diff
+ assert "test_ledger" in diff[1]
+
+ def test_no_diff(self):
+ """Test no difference for two aea configs."""
+ agent_name = "some_agent_for_tests3"
+ self.fetch_agent("fetchai/my_first_aea:0.8.0", agent_name)
+ diff = self.difference_to_fetched_agent(
+ "fetchai/my_first_aea:0.8.0", agent_name
+ )
+ assert not diff
+
+ def test_terminate_subprocesses(self):
+ """Start and terminate long running python subprocess."""
+ proc = self.start_subprocess("-c", "import time; time.sleep(10)")
+ assert proc.returncode is None
+ self._terminate_subprocesses()
+ assert proc.returncode is not None
+
+ def test_miss_from_output(self):
+ """Test subprocess output missing output."""
+ proc = self.start_subprocess("-c", "print('hi')")
+ assert len(self.missing_from_output(proc, ["hi"], timeout=5)) == 0
+ assert "HI" in self.missing_from_output(proc, ["HI"], timeout=5)
+
+ def test_replace_file_content(self):
+ """Replace content of the file with another one."""
+ file1 = "file1.txt"
+ file2 = "file2.txt"
+
+ with open(file1, "w") as f:
+ f.write("hi")
+
+ with open(file2, "w") as f:
+ f.write("world")
+
+ self.replace_file_content(Path(file1), Path(file2))
+
+ with open(file2, "r") as f:
+ assert f.read() == "hi"
+
+
+class TestAddAndRejectComponent(AEATestCaseEmpty):
+ """Test add/reject components."""
+
+ def test_add_and_eject(self):
+ """Test add/reject components."""
+ result = self.add_item("skill", "fetchai/echo:0.4.0", local=True)
+ assert result.exit_code == 0
+
+ result = self.eject_item("skill", "fetchai/echo:0.4.0")
+ assert result.exit_code == 0
+
+
+class TestGenerateAndAddKey(AEATestCaseEmpty):
+ """Test generate and add private key."""
+
+ def test_generate_and_add_key(self):
+ """Test generate and add private key."""
+ result = self.generate_private_key("cosmos")
+ assert result.exit_code == 0
+ result = self.add_private_key(
+ "cosmos", "cosmos_private_key.txt", connection=True
+ )
+ assert result.exit_code == 0
+ result = self.add_private_key("cosmos", "cosmos_private_key.txt")
+ assert result.exit_code == 0
+
+
+class TestGetWealth(AEATestCaseEmpty):
+ """Test get_wealth."""
+
+ def test_get_wealth(self):
+ """Test get_wealth."""
+ # just call it, network related and quite unstable
+ self.get_wealth("cosmos")
+
+
+class TestAEA(AEATestCase):
+ """Test agent test set from path."""
+
+ path_to_aea = Path("tests") / "data" / "dummy_aea"
+
+ def test_agent_set(self):
+ """Test agent test set from path."""
+ result = self.run_cli_command(
+ "config", "get", "agent.agent_name", cwd=self.path_to_aea
+ )
+ assert b"Agent0" in result.stdout_bytes
+
+ def test_scaffold_and_fingerprint(self):
+ """Test component scaffold and fingerprint."""
+ result = self.scaffold_item("skill", "skill1")
+ assert result.exit_code == 0
+
+ result = self.fingerprint_item("skill", "fetchai/skill1:0.1.0")
+ assert result.exit_code == 0
diff --git a/tox.ini b/tox.ini
index e01ceb8f5d..5e30a3256e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,55 +1,29 @@
+; By default, testenvs are configured to:
+; - don't skip dist (skipsdist = False)
+; - don't skip the package installation (skip_install = False)
+; - don't use source installation (usedevelop = False)
+; where one of those steps is not necessary for the test,
+; we set the associated flag (e.g. for linting we don't need
+; the package installation).
[tox]
-envlist = bandit-main, bandit-tests, black, black-check, copyright_check, docs, flake8, liccheck, mypy, py3.8, py3.7, py3.6
-skipsdist = False
-ignore_basepython_conflict = True
+envlist = bandit, black, black-check, copyright_check, docs, flake8, liccheck, mypy, py{3.6,3.7,3.8}
-[testenv:py3.8]
-basepython = python3.8
-passenv = *
-deps =
- Cython
- pytest==5.3.5
- pytest-cov==2.8.1
- pytest-asyncio==0.10.0
- pytest-randomly==3.2.1
- docker
- colorlog==4.1.0
- defusedxml==0.6.0
- oef==0.8.1
- gym==0.15.6
- numpy==1.18.1
- vyper==0.1.0b12
- openapi-core==0.13.2
- openapi-spec-validator==0.2.8
- black==19.10b0
- mistune==2.0.0a4
- aiohttp==3.6.2
- SQLAlchemy==1.3.16
- pynacl==1.3.0
- pexpect==4.8.0
- pytest-rerunfailures==9.0
-
-commands =
- pip install git+https://github.com/pytoolz/cytoolz.git#egg=cytoolz==0.10.1.dev0
- pip install .[all]
- pip install -i https://test.pypi.org/simple/ fetch-p2p-api==0.0.2
- pytest -rfE --doctest-modules aea packages/fetchai/protocols packages/fetchai/connections tests/ --cov-report=html --cov-report=xml --cov-report=term --cov=aea --cov=packages/fetchai/protocols --cov=packages/fetchai/connections {posargs}
-
-[testenv:py3.7]
-basepython = python3.7
+[testenv]
+basepython = python3
+whitelist_externals = /bin/sh
passenv = *
+extras = all
deps =
pytest==5.3.5
pytest-cov==2.8.1
pytest-asyncio==0.10.0
pytest-randomly==3.2.1
- docker
+ docker==4.2.0
colorlog==4.1.0
defusedxml==0.6.0
oef==0.8.1
gym==0.15.6
numpy==1.18.1
- tensorflow==1.14.0
vyper==0.1.0b12
openapi-core==0.13.2
openapi-spec-validator==0.2.8
@@ -61,72 +35,63 @@ deps =
pexpect==4.8.0
pytest-rerunfailures==9.0
-commands =
- pip install .[all]
- pip install -i https://test.pypi.org/simple/ fetch-p2p-api==0.0.2
- pytest -rfE --doctest-modules aea packages/fetchai/protocols packages/fetchai/connections tests/ --cov-report=html --cov-report=xml --cov-report=term --cov=aea --cov=packages/fetchai/protocols --cov=packages/fetchai/connections {posargs}
+commands = pip install -i https://test.pypi.org/simple/ fetch-p2p-api==0.0.2
+ pytest -rfE --doctest-modules aea packages/fetchai/protocols packages/fetchai/connections tests/ --cov-report=html --cov-report=xml --cov-report=term --cov=aea --cov=packages/fetchai/protocols --cov=packages/fetchai/connections {posargs}
[testenv:py3.6]
basepython = python3.6
-passenv = *
-deps =
- pytest==5.3.5
- pytest-cov==2.8.1
- pytest-asyncio==0.10.0
- pytest-randomly==3.2.1
- docker
- colorlog==4.1.0
- defusedxml==0.6.0
- oef==0.8.1
- gym==0.15.6
- numpy==1.18.1
- tensorflow==1.14.0
- vyper==0.1.0b12
- openapi-core==0.13.2
- openapi-spec-validator==0.2.8
- black==19.10b0
- mistune==2.0.0a4
- aiohttp==3.6.2
- SQLAlchemy==1.3.16
- pynacl==1.3.0
- pexpect==4.8.0
- pytest-rerunfailures==9.0
+[testenv:py3.7]
+basepython = python3.7
-commands =
- pip install .[all]
- pip install -i https://test.pypi.org/simple/ fetch-p2p-api==0.0.2
- pytest -rfE --doctest-modules aea packages/fetchai/protocols packages/fetchai/connections tests/ --cov-report=html --cov-report=xml --cov-report=term --cov=aea --cov=packages/fetchai/protocols --cov=packages/fetchai/connections {posargs}
+[testenv:py3.8]
+basepython = python3.8
[testenv:bandit]
+skipsdist = True
+skip_install = True
deps = bandit==1.6.2
commands = bandit -s B101 -r aea benchmark examples packages scripts tests
[testenv:black]
+skipsdist = True
+skip_install = True
deps = black==19.10b0
commands = black aea benchmark examples packages scripts tests
[testenv:black-check]
+skipsdist = True
+skip_install = True
deps = black==19.10b0
commands = black aea benchmark examples packages scripts tests --check --verbose
[testenv:copyright_check]
+skipsdist = True
+skip_install = True
+deps =
commands = {toxinidir}/scripts/check_copyright_notice.py --directory {toxinidir}
[testenv:hash_check]
-deps = python-dotenv
+skipsdist = True
+usedevelop = True
+deps = ipfshttpclient==0.4.12
commands = {toxinidir}/scripts/generate_ipfs_hashes.py --check {posargs}
[testenv:package_version_checks]
-deps = python-dotenv
+skipsdist = True
+usedevelop = True
+deps =
commands = {toxinidir}/scripts/check_package_versions_in_docs.py
[testenv:package_dependencies_checks]
-deps = python-dotenv
+skipsdist = True
+usedevelop = True
+deps =
commands = {toxinidir}/scripts/check_package_dependencies.py
-
[testenv:docs]
+skipsdist = True
+skip_install = True
description = Build the documentation.
deps = markdown==3.2.1
mkdocs==1.1
@@ -137,6 +102,8 @@ commands = pip3 install git+https://github.com/pugong/mkdocs-mermaid-plugin.git#
mkdocs build --clean
[testenv:docs-serve]
+skipsdist = True
+skip_install = True
description = Run a development server for working on documentation.
deps = markdown==3.2.1
mkdocs==1.1
@@ -149,6 +116,8 @@ commands = pip3 install git+https://github.com/pugong/mkdocs-mermaid-plugin.git#
mkdocs serve -a localhost:8080
[testenv:flake8]
+skipsdist = True
+skip_install = True
deps = flake8==3.7.9
flake8-bugbear==20.1.4
flake8-docstrings==1.5.0
@@ -157,22 +126,28 @@ deps = flake8==3.7.9
commands = flake8 aea benchmark examples packages scripts tests
[testenv:liccheck]
+skipsdist = True
+usedevelop = True
deps = liccheck==0.4.3
-commands = pip install ".[all]"
- {toxinidir}/scripts/freeze_dependencies.py -o {envtmpdir}/requirements.txt
+commands = {toxinidir}/scripts/freeze_dependencies.py -o {envtmpdir}/requirements.txt
liccheck -s strategy.ini -r {envtmpdir}/requirements.txt -l PARANOID
[testenv:mypy]
+skipsdist = True
+skip_install = True
deps = mypy==0.761
aiohttp==3.6.2
+ packaging==20.4
commands = mypy aea benchmark examples packages scripts tests
[testenv:pylint]
+skipsdist = True
deps = pylint==2.5.2
pytest==5.3.5
-commands = pip install .[all]
- pylint aea benchmark examples packages scripts --disable=E1136
+commands = sh -c "pylint aea benchmark packages scripts examples/* --disable=E1136"
[testenv:safety]
+skipsdist = True
+skip_install = True
deps = safety==1.8.5
commands = safety check -i 37524 -i 38038 -i 37776 -i 38039