From 8addd599d338b79ab35ad9ef0884ba641416b048 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 27 Sep 2023 12:15:08 -0600 Subject: [PATCH 01/26] feat: update agent addresses --- python/examples/06-send-tokens/main.py | 6 ++-- .../08-local-network-interaction/agent1.py | 4 +-- .../08-local-network-interaction/agent2.py | 4 +-- .../09-booking-protocol-demo/restaurant.py | 2 +- .../examples/09-booking-protocol-demo/user.py | 2 +- python/examples/10-cleaning-demo/cleaner.py | 2 +- python/examples/10-cleaning-demo/user.py | 2 +- python/examples/11-mailbox-agents/alice.py | 2 +- python/examples/11-mailbox-agents/bob.py | 2 +- python/examples/12-remote-agents/agent1.py | 2 +- python/examples/12-remote-agents/agent2.py | 2 +- .../examples/13-agent-name-service/agent1.py | 12 ++++--- .../examples/13-agent-name-service/agent2.py | 4 +-- python/examples/14-broadcast/main.py | 6 ++-- python/src/uagents/agent.py | 31 ++++++++-------- python/src/uagents/config.py | 10 +++--- python/src/uagents/context.py | 26 ++++++++------ python/src/uagents/network.py | 35 ++++++++++--------- python/src/uagents/resolver.py | 25 ++++++++----- python/src/uagents/setup.py | 22 +++++++----- 20 files changed, 111 insertions(+), 90 deletions(-) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index 25e235ee..a766043f 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -19,8 +19,8 @@ class TransactionInfo(Model): alice = Agent(name="alice", seed="alice secret phrase") bob = Agent(name="bob", seed="bob secret phrase") -fund_agent_if_low(alice.wallet.address()) -fund_agent_if_low(bob.wallet.address()) +fund_agent_if_low(alice) +fund_agent_if_low(bob) @alice.on_interval(period=10.0) @@ -36,7 +36,7 @@ async def request_funds(ctx: Context): @alice.on_message(model=TransactionInfo) async def confirm_transaction(ctx: Context, sender: str, msg: TransactionInfo): ctx.logger.info(f"Received transaction info from {sender}: {msg}") - tx_resp = await wait_for_tx_to_complete(msg.tx_hash) + tx_resp = await wait_for_tx_to_complete(msg.tx_hash, alice._ledger) coin_received = tx_resp.events["coin_received"] if ( diff --git a/python/examples/08-local-network-interaction/agent1.py b/python/examples/08-local-network-interaction/agent1.py index 157cb34f..301cff1d 100644 --- a/python/examples/08-local-network-interaction/agent1.py +++ b/python/examples/08-local-network-interaction/agent1.py @@ -16,8 +16,8 @@ class Message(Model): endpoint=["http://127.0.0.1:8001/submit"], ) -fund_agent_if_low(bob.wallet.address()) - +fund_agent_if_low(bob) +print(bob.address) @bob.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): diff --git a/python/examples/08-local-network-interaction/agent2.py b/python/examples/08-local-network-interaction/agent2.py index 149bb27b..d64a2141 100644 --- a/python/examples/08-local-network-interaction/agent2.py +++ b/python/examples/08-local-network-interaction/agent2.py @@ -6,7 +6,7 @@ class Message(Model): message: str -RECIPIENT_ADDRESS = "agent1q2kxet3vh0scsf0sm7y2erzz33cve6tv5uk63x64upw5g68kr0chkv7hw50" +RECIPIENT_ADDRESS = "test-agent://agent1q2kxet3vh0scsf0sm7y2erzz33cve6tv5uk63x64upw5g68kr0chkv7hw50" alice = Agent( name="alice", @@ -15,7 +15,7 @@ class Message(Model): endpoint=["http://127.0.0.1:8000/submit"], ) -fund_agent_if_low(alice.wallet.address()) +fund_agent_if_low(alice) @alice.on_interval(period=2.0) diff --git a/python/examples/09-booking-protocol-demo/restaurant.py b/python/examples/09-booking-protocol-demo/restaurant.py index b74ca64a..ad37a0b9 100644 --- a/python/examples/09-booking-protocol-demo/restaurant.py +++ b/python/examples/09-booking-protocol-demo/restaurant.py @@ -15,7 +15,7 @@ }, ) -fund_agent_if_low(restaurant.wallet.address()) +fund_agent_if_low(restaurant) # build the restaurant agent from stock protocols and publish their details restaurant.include(query_proto, publish_manifest=True) diff --git a/python/examples/09-booking-protocol-demo/user.py b/python/examples/09-booking-protocol-demo/user.py index fc09668a..fda06c6a 100644 --- a/python/examples/09-booking-protocol-demo/user.py +++ b/python/examples/09-booking-protocol-demo/user.py @@ -19,7 +19,7 @@ }, ) -fund_agent_if_low(user.wallet.address()) +fund_agent_if_low(user) table_query = QueryTableRequest( guests=3, diff --git a/python/examples/10-cleaning-demo/cleaner.py b/python/examples/10-cleaning-demo/cleaner.py index 5a300c05..cd2ce745 100644 --- a/python/examples/10-cleaning-demo/cleaner.py +++ b/python/examples/10-cleaning-demo/cleaner.py @@ -19,7 +19,7 @@ }, ) -fund_agent_if_low(cleaner.wallet.address()) +fund_agent_if_low(cleaner) # build the cleaning service agent from the cleaning protocol diff --git a/python/examples/10-cleaning-demo/user.py b/python/examples/10-cleaning-demo/user.py index c0bc4cea..41a4962a 100644 --- a/python/examples/10-cleaning-demo/user.py +++ b/python/examples/10-cleaning-demo/user.py @@ -23,7 +23,7 @@ }, ) -fund_agent_if_low(user.wallet.address()) +fund_agent_if_low(user) request = ServiceRequest( user=user.name, diff --git a/python/examples/11-mailbox-agents/alice.py b/python/examples/11-mailbox-agents/alice.py index a822ec8b..160a6d82 100644 --- a/python/examples/11-mailbox-agents/alice.py +++ b/python/examples/11-mailbox-agents/alice.py @@ -22,7 +22,7 @@ class Message(Model): mailbox=f"{API_KEY}@wss://agentverse.ai", ) -fund_agent_if_low(agent.wallet.address()) +fund_agent_if_low(agent) @agent.on_message(model=Message, replies={Message}) diff --git a/python/examples/11-mailbox-agents/bob.py b/python/examples/11-mailbox-agents/bob.py index 06dd3c0a..4b48838e 100644 --- a/python/examples/11-mailbox-agents/bob.py +++ b/python/examples/11-mailbox-agents/bob.py @@ -25,7 +25,7 @@ class Message(Model): mailbox=f"{API_KEY}@wss://agentverse.ai", ) -fund_agent_if_low(agent.wallet.address()) +fund_agent_if_low(agent) @agent.on_interval(period=2.0) diff --git a/python/examples/12-remote-agents/agent1.py b/python/examples/12-remote-agents/agent1.py index 09a4bd02..34359e39 100644 --- a/python/examples/12-remote-agents/agent1.py +++ b/python/examples/12-remote-agents/agent1.py @@ -29,7 +29,7 @@ class Message(Model): endpoint=[f"{http_tunnel.public_url}/submit"], ) -fund_agent_if_low(alice.wallet.address()) +fund_agent_if_low(alice) @alice.on_message(model=Message) diff --git a/python/examples/12-remote-agents/agent2.py b/python/examples/12-remote-agents/agent2.py index c9661ed7..6b489233 100644 --- a/python/examples/12-remote-agents/agent2.py +++ b/python/examples/12-remote-agents/agent2.py @@ -16,7 +16,7 @@ class Message(Model): endpoint=["http://127.0.0.1:8001/submit"], ) -fund_agent_if_low(bob.wallet.address()) +fund_agent_if_low(bob) ALICE_ADDRESS = "agent1qv2l7qzcd2g2rcv2p93tqflrcaq5dk7c2xc7fcnfq3s37zgkhxjmq5mfyvz" diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index b70295fb..fa839a86 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -1,6 +1,6 @@ from cosmpy.aerial.wallet import LocalWallet -from uagents.network import get_ledger, get_name_service_contract +from uagents.network import get_ledger, get_faucet, get_name_service_contract from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model @@ -19,19 +19,21 @@ class Message(Model): endpoint=["http://localhost:8001/submit"], ) -ledger = get_ledger() + my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") name_service_contract = get_name_service_contract() DOMAIN = "agent" -for wallet in [my_wallet, bob.wallet]: - fund_agent_if_low(wallet.address()) +faucet = get_faucet() +faucet.get_wealth(my_wallet) + +fund_agent_if_low(bob) @bob.on_event("startup") async def register_agent_name(ctx: Context): await name_service_contract.register( - ledger, my_wallet, ctx.address, ctx.name, DOMAIN + bob._ledger, my_wallet, ctx.address, ctx.name, DOMAIN ) diff --git a/python/examples/13-agent-name-service/agent2.py b/python/examples/13-agent-name-service/agent2.py index 10709f46..2deb7fde 100644 --- a/python/examples/13-agent-name-service/agent2.py +++ b/python/examples/13-agent-name-service/agent2.py @@ -13,9 +13,7 @@ class Message(Model): endpoint=["http://localhost:8000/submit"], ) - -fund_agent_if_low(alice.wallet.address()) - +fund_agent_if_low(alice) @alice.on_interval(period=5) async def alice_interval_handler(ctx: Context): diff --git a/python/examples/14-broadcast/main.py b/python/examples/14-broadcast/main.py index 457ce6f9..86c30caa 100644 --- a/python/examples/14-broadcast/main.py +++ b/python/examples/14-broadcast/main.py @@ -8,9 +8,9 @@ bob = Agent(name="bob", seed="bob recovery phrase") charles = Agent(name="charles", seed="charles recovery phrase") -fund_agent_if_low(alice.wallet.address()) -fund_agent_if_low(bob.wallet.address()) -fund_agent_if_low(charles.wallet.address()) +fund_agent_if_low(alice) +fund_agent_if_low(bob) +fund_agent_if_low(charles) class BroadcastExampleRequest(Model): diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index 5afa6bc9..b7be82a9 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -143,6 +143,7 @@ class Agent(Sink): def __init__( self, name: Optional[str] = None, + test: Optional[bool] = True, port: Optional[int] = None, seed: Optional[str] = None, endpoint: Optional[Union[str, List[str], Dict[str, dict]]] = None, @@ -167,6 +168,7 @@ def __init__( version (Optional[str]): The version of the agent. """ self._name = name + self._test = test self._port = port if port is not None else 8000 self._background_tasks: Set[asyncio.Task] = set() self._resolver = ( @@ -210,9 +212,9 @@ def __init__( else: self._mailbox_client = None - self._ledger = get_ledger() - self._almanac_contract = get_almanac_contract() - self._storage = KeyValueStore(self.address[0:16]) + self._ledger = get_ledger(self._test) + self._almanac_contract = get_almanac_contract(self._test) + self._storage = KeyValueStore(self._identity.address[0:16]) self._interval_handlers: List[Tuple[IntervalCallback, float]] = [] self._interval_messages: Set[str] = set() self._signed_message_handlers: Dict[str, MessageCallback] = {} @@ -233,7 +235,7 @@ def __init__( self.protocols: Dict[str, Protocol] = {} self._ctx = Context( - self._identity.address, + self.address, self._name, self._storage, self._resolver, @@ -248,7 +250,7 @@ def __init__( ) # register with the dispatcher - self._dispatcher.register(self.address, self) + self._dispatcher.register(self._identity.address, self) if not self._use_mailbox: self._server = ASGIServer( @@ -281,7 +283,7 @@ def _initialize_wallet_and_identity(self, seed, name): prefix=LEDGER_PREFIX, ) if name is None: - self._name = self.address[0:16] + self._name = self._identity.address[0:16] @property def name(self) -> str: @@ -301,7 +303,8 @@ def address(self) -> str: Returns: str: The agent's address. """ - return self._identity.address + prefix = "test-agent://" if self._test else "agent://" + return prefix + self._identity.address @property def wallet(self) -> LocalWallet: @@ -413,7 +416,7 @@ def sign_registration(self) -> str: assert self._almanac_contract.address is not None return self._identity.sign_registration( str(self._almanac_contract.address), - self._almanac_contract.get_sequence(self.address), + self._almanac_contract.get_sequence(self._identity.address), ) def update_endpoints(self, endpoints: List[Dict[str, Any]]): @@ -460,12 +463,12 @@ async def register(self): # register if not yet registered or registration is about to expire # or anything has changed from the last registration if ( - not self._almanac_contract.is_registered(self.address) - or self._almanac_contract.get_expiry(self.address) + not self._almanac_contract.is_registered(self._identity.address) + or self._almanac_contract.get_expiry(self._identity.address) < REGISTRATION_UPDATE_INTERVAL_SECONDS - or self._endpoints != self._almanac_contract.get_endpoints(self.address) + or self._endpoints != self._almanac_contract.get_endpoints(self._identity.address) or list(self.protocols.keys()) - != self._almanac_contract.get_protocols(self.address) + != self._almanac_contract.get_protocols(self._identity.address) ): agent_balance = self._ledger.query_bank_balance( Address(self.wallet.address()) @@ -482,7 +485,7 @@ async def register(self): await self._almanac_contract.register( self._ledger, self.wallet, - self.address, + self._identity.address, list(self.protocols.keys()), self._endpoints, signature, @@ -800,7 +803,7 @@ async def _process_message_queue(self): continue context = Context( - self._identity.address, + self.address, self._name, self._storage, self._resolver, diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index f22fbfdc..059963e6 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -8,15 +8,15 @@ logging.basicConfig(level=logging.INFO) -class AgentNetwork(Enum): - FETCHAI_TESTNET = 1 - FETCHAI_MAINNET = 2 - +#class AgentNetwork(Enum): +# FETCHAI_TESTNET = 1 +# FETCHAI_MAINNET = 2 AGENT_PREFIX = "agent" LEDGER_PREFIX = "fetch" USER_PREFIX = "user" CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" +TESTNET_CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" CONTRACT_NAME_SERVICE = ( "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" ) @@ -25,7 +25,7 @@ class AgentNetwork(Enum): REGISTRATION_UPDATE_INTERVAL_SECONDS = 3600 REGISTRATION_RETRY_INTERVAL_SECONDS = 60 AVERAGE_BLOCK_INTERVAL = 5.7 -AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET +#AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET AGENTVERSE_URL = "https://agentverse.ai" ALMANAC_API_URL = AGENTVERSE_URL + "/v1/almanac/" diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index d10203e3..2b14ad04 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -374,6 +374,10 @@ async def send_raw( Returns: MsgStatus: The delivery status of the message. """ + + # Destination without ledger prefix + raw_destination = destination[-65:] + # Check if this message is a reply if ( self._message_received is not None @@ -391,7 +395,7 @@ async def send_raw( return MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid reply", - destination=destination, + destination=raw_destination, endpoint="", ) # Check if this message is a valid interval message @@ -403,15 +407,15 @@ async def send_raw( return MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid interval message", - destination=destination, + destination=raw_destination, endpoint="", ) # Handle local dispatch of messages - if dispatcher.contains(destination): + if dispatcher.contains(raw_destination): await dispatcher.dispatch( - self.address, - destination, + self._identity.address, + raw_destination, schema_digest, json_message, self._session, @@ -419,18 +423,18 @@ async def send_raw( return MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=destination, + destination=raw_destination, endpoint="", ) # Handle queries waiting for a response - if destination in self._queries: - self._queries[destination].set_result((json_message, schema_digest)) - del self._queries[destination] + if raw_destination in self._queries: + self._queries[raw_destination].set_result((json_message, schema_digest)) + del self._queries[raw_destination] return MsgStatus( status=DeliveryStatus.DELIVERED, detail="Sync message resolved", - destination=destination, + destination=raw_destination, endpoint="", ) @@ -453,7 +457,7 @@ async def send_raw( # Handle external dispatch of messages env = Envelope( version=1, - sender=self.address, + sender=self._identity.address, target=destination_address, session=self._session or uuid.uuid4(), schema_digest=schema_digest, diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index 74c47e61..e9d8a68f 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -20,10 +20,9 @@ from cosmpy.aerial.wallet import LocalWallet from uagents.config import ( - AgentNetwork, CONTRACT_ALMANAC, + TESTNET_CONTRACT_ALMANAC, CONTRACT_NAME_SERVICE, - AGENT_NETWORK, AVERAGE_BLOCK_INTERVAL, REGISTRATION_FEE, REGISTRATION_DENOM, @@ -33,23 +32,20 @@ logger = get_logger("network") -# Setting up the Ledger and Faucet based on Agent Network -if AGENT_NETWORK == AgentNetwork.FETCHAI_TESTNET: - _ledger = LedgerClient(NetworkConfig.fetchai_stable_testnet()) - _faucet_api = FaucetApi(NetworkConfig.fetchai_stable_testnet()) -elif AGENT_NETWORK == AgentNetwork.FETCHAI_MAINNET: - _ledger = LedgerClient(NetworkConfig.fetchai_mainnet()) -else: - raise NotImplementedError +_faucet_api = FaucetApi(NetworkConfig.fetchai_stable_testnet()) +_testnet_ledger = LedgerClient(NetworkConfig.fetchai_stable_testnet()) +_ledger = LedgerClient(NetworkConfig.fetchai_mainnet()) -def get_ledger() -> LedgerClient: +def get_ledger(test: bool) -> LedgerClient: """ Get the Ledger client. Returns: LedgerClient: The Ledger client instance. """ + if test: + return _testnet_ledger return _ledger @@ -65,6 +61,7 @@ def get_faucet() -> FaucetApi: async def wait_for_tx_to_complete( tx_hash: str, + ledger: LedgerClient, timeout: Optional[timedelta] = None, poll_period: Optional[timedelta] = None, ) -> TxResponse: @@ -88,7 +85,7 @@ async def wait_for_tx_to_complete( start = datetime.now() while True: try: - return _ledger.query_tx(tx_hash) + return ledger.query_tx(tx_hash) except NotFoundError: pass @@ -231,7 +228,7 @@ async def register( transaction = prepare_and_broadcast_basic_transaction( ledger, transaction, wallet ) - await wait_for_tx_to_complete(transaction.tx_hash) + await wait_for_tx_to_complete(transaction.tx_hash, ledger) def get_sequence(self, address: str) -> int: """ @@ -250,15 +247,18 @@ def get_sequence(self, address: str) -> int: _almanac_contract = AlmanacContract(None, _ledger, CONTRACT_ALMANAC) +_testnet_almanac_contract = AlmanacContract(None, _testnet_ledger, TESTNET_CONTRACT_ALMANAC) -def get_almanac_contract() -> AlmanacContract: +def get_almanac_contract(test: bool) -> AlmanacContract: """ Get the AlmanacContract instance. Returns: AlmanacContract: The AlmanacContract instance. """ + if test: + return _testnet_almanac_contract return _almanac_contract @@ -376,8 +376,9 @@ async def register( domain (str): The domain in which the name is registered. """ logger.info("Registering name...") + chain_id = ledger.query_chain_id() - if not get_almanac_contract().is_registered(agent_address): + if not get_almanac_contract(chain_id == "dorado-1").is_registered(agent_address): logger.warning( f"Agent {name} needs to be registered in almanac contract to register its name" ) @@ -401,11 +402,11 @@ async def register( transaction = prepare_and_broadcast_basic_transaction( ledger, transaction, wallet ) - await wait_for_tx_to_complete(transaction.tx_hash) + await wait_for_tx_to_complete(transaction.tx_hash, ledger) logger.info("Registering name...complete") -_name_service_contract = NameServiceContract(None, _ledger, CONTRACT_NAME_SERVICE) +_name_service_contract = NameServiceContract(None, _testnet_ledger, CONTRACT_NAME_SERVICE) def get_name_service_contract() -> NameServiceContract: diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 63a35db8..2de1fef1 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -7,8 +7,10 @@ from uagents.config import DEFAULT_MAX_ENDPOINTS from uagents.network import get_almanac_contract, get_name_service_contract +_testnet_prefixe = "test-agent://" +_mainnet_prefix = "agent://" -def query_record(agent_address: str, service: str) -> dict: +def query_record(agent_address: str, service: str, test: bool) -> dict: """ Query a record from the Almanac contract. @@ -19,7 +21,7 @@ def query_record(agent_address: str, service: str) -> dict: Returns: dict: The query result. """ - contract = get_almanac_contract() + contract = get_almanac_contract(test) query_msg = { "query_record": {"agent_address": agent_address, "record_type": service} } @@ -46,7 +48,7 @@ def get_agent_address(name: str) -> str: return None -def is_agent_address(address): +def is_agent_address(address) -> tuple: """ Check if the provided address is a valid agent address. @@ -59,10 +61,14 @@ def is_agent_address(address): if not isinstance(address, str): return False - prefix = "agent" + prefixes = [_testnet_prefixe , _mainnet_prefix, ""] expected_length = 65 - return address.startswith(prefix) and len(address) == expected_length + for prefix in prefixes: + if address.startswith(prefix) and len(address) == expected_length + len(prefix): + return (True, prefix) + + return (False, None) class Resolver(ABC): @@ -105,8 +111,9 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Returns: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - if is_agent_address(destination): - return await self._almanc_resolver.resolve(destination) + is_address, prefix = is_agent_address(destination) + if is_address: + return await self._almanc_resolver.resolve(destination[len(prefix):], not prefix == _mainnet_prefix) return await self._name_service_resolver.resolve(destination) @@ -120,7 +127,7 @@ def __init__(self, max_endpoints: Optional[int] = None): """ self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS - async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: + async def resolve(self, destination: str, test: bool) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the Almanac contract. @@ -130,7 +137,7 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Returns: Tuple[str, List[str]]: The address and resolved endpoints. """ - result = query_record(destination, "service") + result = query_record(destination, "service", test) if result is not None: record = result.get("record") or {} endpoint_list = ( diff --git a/python/src/uagents/setup.py b/python/src/uagents/setup.py index 50d189e8..4f0bba29 100644 --- a/python/src/uagents/setup.py +++ b/python/src/uagents/setup.py @@ -9,8 +9,7 @@ LOGGER = get_logger("setup") - -def fund_agent_if_low(wallet_address: str): +def fund_agent_if_low(agent: Agent): """ Checks the agent's wallet balance and adds funds if it's below the registration fee. @@ -20,16 +19,23 @@ def fund_agent_if_low(wallet_address: str): Returns: None """ - ledger = get_ledger() + ledger = get_ledger(agent._test) faucet = get_faucet() - agent_balance = ledger.query_bank_balance(Address(wallet_address)) + agent_balance = ledger.query_bank_balance(Address(agent.wallet.address())) + + if not agent._test: + LOGGER.warning(f"Faucet only available for testnet, please add FET tokens to your wallet {agent.wallet.address()}") + LOGGER.info(f"Current FET balance: {agent_balance}") + return if agent_balance < REGISTRATION_FEE: - # Add tokens to agent's wallet - LOGGER.info("Adding funds to agent...") - faucet.get_wealth(wallet_address) - LOGGER.info("Adding funds to agent...complete") + try: + LOGGER.info("Adding funds to agent...") + faucet.get_wealth(agent.wallet.address()) + LOGGER.info("Adding funds to agent...complete") + except Exception as e: + LOGGER.error(f"Failed to add funds to agent: {str(e)}") def register_agent_with_mailbox(agent: Agent, email: str): From 9b5a06d9f06fca2a7821dc96ec9d1bb75da88ced Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Thu, 28 Sep 2023 11:44:23 -0600 Subject: [PATCH 02/26] fix: tests --- .../examples/13-agent-name-service/agent1.py | 12 ++++-- python/src/uagents/resolver.py | 6 +-- python/tests/test_agent.py | 2 +- python/tests/test_agent_address.py | 9 +++-- python/tests/test_agent_registration.py | 12 +++--- python/tests/test_context.py | 38 +++++++++---------- python/tests/test_msg_verify.py | 2 +- python/tests/test_server.py | 36 +++++++++--------- 8 files changed, 62 insertions(+), 55 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index fa839a86..c180acb9 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -4,6 +4,8 @@ from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model +from uagents.config import REGISTRATION_FEE + # NOTE: Run agent1.py before running agent2.py @@ -19,21 +21,25 @@ class Message(Model): endpoint=["http://localhost:8001/submit"], ) +fund_agent_if_low(bob) my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") name_service_contract = get_name_service_contract() DOMAIN = "agent" faucet = get_faucet() -faucet.get_wealth(my_wallet) +agent_balance = bob._ledger.query_bank_balance(my_wallet) -fund_agent_if_low(bob) +if agent_balance < REGISTRATION_FEE: + print("Adding funds to wallet...") + faucet.get_wealth(my_wallet) + print("Adding funds to wallet...complete") @bob.on_event("startup") async def register_agent_name(ctx: Context): await name_service_contract.register( - bob._ledger, my_wallet, ctx.address, ctx.name, DOMAIN + bob._ledger, my_wallet, ctx.address[-65:], ctx.name, DOMAIN ) diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 2de1fef1..291a62f6 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -114,7 +114,7 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: is_address, prefix = is_agent_address(destination) if is_address: return await self._almanc_resolver.resolve(destination[len(prefix):], not prefix == _mainnet_prefix) - return await self._name_service_resolver.resolve(destination) + return await self._name_service_resolver.resolve(destination, not prefix == _mainnet_prefix) class AlmanacResolver(Resolver): @@ -167,7 +167,7 @@ def __init__(self, max_endpoints: Optional[int] = None): self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS self._almanac_resolver = AlmanacResolver(max_endpoints=self._max_endpoints) - async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: + async def resolve(self, destination: str, test: bool) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the NameService contract. @@ -179,7 +179,7 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: """ address = get_agent_address(destination) if address is not None: - return await self._almanac_resolver.resolve(address) + return await self._almanac_resolver.resolve(address, test) return None, [] diff --git a/python/tests/test_agent.py b/python/tests/test_agent.py index 36ac435a..f51dcd21 100644 --- a/python/tests/test_agent.py +++ b/python/tests/test_agent.py @@ -30,7 +30,7 @@ def test_agent_init(self): self.assertIsNotNone(self.agent._wallet) self.assertIsNotNone(self.agent._identity) self.assertIsNotNone(self.agent._server) - self.assertTrue(self.agent._dispatcher.contains(self.agent.address)) + self.assertTrue(self.agent._dispatcher.contains(self.agent.address[-65:])) self.assertTrue(isinstance(self.agent._resolver, GlobalResolver)) def test_agent_on_interval(self): diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index c9c29dc2..df60e985 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -3,6 +3,7 @@ from uagents import Agent from uagents.crypto import Identity +test_prefix = "test-agent://" class TestAgentAdress(unittest.TestCase): def test_agent_from_seed(self): @@ -13,19 +14,19 @@ def test_agent_from_seed(self): bob_target_address = Identity.from_seed("bob recovery password", 0).address self.assertEqual( - alice.address == alice_target_address, + alice.address == test_prefix + alice_target_address, True, "Alice's address does not match", ) self.assertEqual( - bob.address == bob_target_address, True, "Bobs's address does not match" + bob.address == test_prefix + bob_target_address, True, "Bobs's address does not match" ) def test_agent_generate(self): alice = Agent(name="alice") - self.assertEqual(alice.address[:5] == "agent", True) - self.assertEqual(len(alice.address) == 65, True) + self.assertEqual(alice.address[-65:-60] == "agent", True) + self.assertEqual(len(alice.address) == 65 + len(test_prefix), True) if __name__ == "__main__": diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index 90675a51..f4f78380 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -11,12 +11,12 @@ class TestRegistration(unittest.IsolatedAsyncioTestCase): async def test_almanac_registration(self): agent = Agent(endpoint=["http://localhost:8000/submit"]) - fund_agent_if_low(agent.wallet.address()) + fund_agent_if_low(agent) await agent.register() self.assertEqual( - agent._almanac_contract.is_registered(agent.address), + agent._almanac_contract.is_registered(agent.address[-65:]), True, "Almanac registration failed", ) @@ -48,12 +48,12 @@ async def test_name_service_registration(self): domain = "agent" - fund_agent_if_low(agent.wallet.address()) + fund_agent_if_low(agent) await agent.register() self.assertEqual( - agent._almanac_contract.is_registered(agent.address), + agent._almanac_contract.is_registered(agent.address[-65:]), True, "Almanac registration failed", ) @@ -69,7 +69,7 @@ async def test_name_service_registration(self): self.assertEqual(is_owner, False) await name_service_contract.register( - agent._ledger, agent.wallet, agent.address, agent.name, domain=domain + agent._ledger, agent.wallet, agent.address[-65:], agent.name, domain=domain ) is_name_available = name_service_contract.is_name_available(agent.name, domain) @@ -83,7 +83,7 @@ async def test_name_service_registration(self): query_address = get_agent_address(agent.name + "." + domain) self.assertEqual( - query_address == agent.address, True, "Service contract registration failed" + query_address == agent.address[-65:], True, "Service contract registration failed" ) diff --git a/python/tests/test_context.py b/python/tests/test_context.py index c57895a6..7d4e2c9d 100644 --- a/python/tests/test_context.py +++ b/python/tests/test_context.py @@ -25,10 +25,10 @@ class Message(Model): endpoints = ["http://localhost:8000"] clyde = Agent(name="clyde", seed="clyde recovery phrase", endpoint=endpoints) -dispatcher.unregister(clyde.address, clyde) +dispatcher.unregister(clyde.address[-65:], clyde) resolver = RulesBasedResolver( rules={ - clyde.address: endpoints, + clyde.address[-65:]: endpoints, } ) alice = Agent(name="alice", seed="alice recovery phrase", resolve=resolver) @@ -49,7 +49,7 @@ async def test_send_local_dispatch(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address, + destination=bob.address[-65:], endpoint="", ) @@ -64,7 +64,7 @@ async def test_send_local_dispatch_valid_reply(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address, + destination=bob.address[-65:], endpoint="", ) @@ -81,7 +81,7 @@ async def test_send_local_dispatch_invalid_reply(self): exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid reply", - destination=bob.address, + destination=bob.address[-65:], endpoint="", ) @@ -95,7 +95,7 @@ async def test_send_local_dispatch_valid_interval_msg(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address, + destination=bob.address[-65:], endpoint="", ) @@ -108,7 +108,7 @@ async def test_send_local_dispatch_invalid_interval_msg(self): exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid interval message", - destination=bob.address, + destination=bob.address[-65:], endpoint="", ) @@ -116,12 +116,12 @@ async def test_send_local_dispatch_invalid_interval_msg(self): async def test_send_resolve_sync_query(self): future = asyncio.Future() - self.context._queries[clyde.address] = future + self.context._queries[clyde.address[-65:]] = future result = await self.context.send(clyde.address, msg) exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Sync message resolved", - destination=clyde.address, + destination=clyde.address[-65:], endpoint="", ) @@ -149,13 +149,13 @@ async def test_send_external_dispatch_success(self, mocked_responses): mocked_responses.post(endpoints[0], status=200) # Perform the actual operation - result = await self.context.send(clyde.address, msg) + result = await self.context.send(clyde.address[-65:], msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address, + destination=clyde.address[-65:], endpoint=endpoints[0], ) @@ -168,13 +168,13 @@ async def test_send_external_dispatch_failure(self, mocked_responses): mocked_responses.post(endpoints[0], status=404) # Perform the actual operation - result = await self.context.send(clyde.address, msg) + result = await self.context.send(clyde.address[-65:], msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Message delivery failed", - destination=clyde.address, + destination=clyde.address[-65:], endpoint="", ) @@ -192,13 +192,13 @@ async def test_send_external_dispatch_multiple_endpoints_first_success( mocked_responses.post(endpoints[1], status=404) # Perform the actual operation - result = await self.context.send(clyde.address, msg) + result = await self.context.send(clyde.address[-65:], msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address, + destination=clyde.address[-65:], endpoint=endpoints[0], ) @@ -221,13 +221,13 @@ async def test_send_external_dispatch_multiple_endpoints_second_success( mocked_responses.post(endpoints[1], status=200) # Perform the actual operation - result = await self.context.send(clyde.address, msg) + result = await self.context.send(clyde.address[-65:], msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address, + destination=clyde.address[-65:], endpoint=endpoints[1], ) @@ -247,13 +247,13 @@ async def test_send_external_dispatch_multiple_endpoints_failure( mocked_responses.post(endpoints[1], status=404) # Perform the actual operation - result = await self.context.send(clyde.address, msg) + result = await self.context.send(clyde.address[-65:], msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Message delivery failed", - destination=clyde.address, + destination=clyde.address[-65:], endpoint="", ) diff --git a/python/tests/test_msg_verify.py b/python/tests/test_msg_verify.py index b2b107a2..ae6fa7fd 100644 --- a/python/tests/test_msg_verify.py +++ b/python/tests/test_msg_verify.py @@ -23,7 +23,7 @@ def test_sign_and_verify_message(self): signature = alice.sign_digest(encoded_msg) # Message signature can be verified using alice address - result = Identity.verify_digest(alice.address, encoded_msg, signature) + result = Identity.verify_digest(alice.address[-65:], encoded_msg, signature) self.assertEqual(result, True, "Verification failed") diff --git a/python/tests/test_server.py b/python/tests/test_server.py index a58fb063..f84c4241 100644 --- a/python/tests/test_server.py +++ b/python/tests/test_server.py @@ -32,8 +32,8 @@ async def test_message_success(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -77,7 +77,7 @@ async def test_message_success_unsigned(self): env = Envelope( version=1, sender=user, - target=self.agent.address, + target=self.agent.address[-65:], session=session, protocol=Model.build_schema_digest(message), ) @@ -121,7 +121,7 @@ async def test_message_success_sync(self): env = Envelope( version=1, sender=user, - target=self.agent.address, + target=self.agent.address[-65:], session=session, protocol=Model.build_schema_digest(message), ) @@ -146,7 +146,7 @@ async def test_message_success_sync(self): ), asyncio.create_task(self.mock_process_sync_message(user, reply)), ) - response = enclose_response(reply, self.agent.address, session) + response = enclose_response(reply, self.agent.address[-65:], session) mock_send.assert_has_calls( [ call( @@ -171,8 +171,8 @@ async def test_message_success_sync_unsigned(self): session = uuid.uuid4() env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=session, protocol=Model.build_schema_digest(message), ) @@ -197,10 +197,10 @@ async def test_message_success_sync_unsigned(self): ) ), asyncio.create_task( - self.mock_process_sync_message(self.bob.address, reply) + self.mock_process_sync_message(self.bob.address[-65:], reply) ), ) - response = enclose_response(reply, self.agent.address, session) + response = enclose_response(reply, self.agent.address[-65:], session) mock_send.assert_has_calls( [ call( @@ -223,8 +223,8 @@ async def test_message_fail_wrong_path(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -265,8 +265,8 @@ async def test_message_fail_wrong_headers(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -339,8 +339,8 @@ async def test_message_fail_unsigned(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -380,8 +380,8 @@ async def test_message_fail_verify(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, - target=self.agent.address, + sender=self.bob.address[-65:], + target=self.agent.address[-65:], session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -422,7 +422,7 @@ async def test_message_fail_dispatch(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address, + sender=self.bob.address[-65:], target=generate_user_address(), session=uuid.uuid4(), protocol=Model.build_schema_digest(message), From f5269d387fb6385163182e81f8e307d6bb6842c3 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Thu, 28 Sep 2023 12:05:55 -0600 Subject: [PATCH 03/26] fix: run black --- .../08-local-network-interaction/agent1.py | 2 +- .../08-local-network-interaction/agent2.py | 4 +++- .../examples/13-agent-name-service/agent2.py | 1 + python/src/uagents/agent.py | 3 ++- python/src/uagents/config.py | 8 +++++--- python/src/uagents/network.py | 19 ++++++++++++++----- python/src/uagents/resolver.py | 19 ++++++++++++++----- python/src/uagents/setup.py | 5 ++++- python/tests/test_agent_address.py | 5 ++++- python/tests/test_agent_registration.py | 4 +++- 10 files changed, 51 insertions(+), 19 deletions(-) diff --git a/python/examples/08-local-network-interaction/agent1.py b/python/examples/08-local-network-interaction/agent1.py index 301cff1d..ed4e95f9 100644 --- a/python/examples/08-local-network-interaction/agent1.py +++ b/python/examples/08-local-network-interaction/agent1.py @@ -17,7 +17,7 @@ class Message(Model): ) fund_agent_if_low(bob) -print(bob.address) + @bob.on_message(model=Message) async def message_handler(ctx: Context, sender: str, msg: Message): diff --git a/python/examples/08-local-network-interaction/agent2.py b/python/examples/08-local-network-interaction/agent2.py index d64a2141..c8f9d000 100644 --- a/python/examples/08-local-network-interaction/agent2.py +++ b/python/examples/08-local-network-interaction/agent2.py @@ -6,7 +6,9 @@ class Message(Model): message: str -RECIPIENT_ADDRESS = "test-agent://agent1q2kxet3vh0scsf0sm7y2erzz33cve6tv5uk63x64upw5g68kr0chkv7hw50" +RECIPIENT_ADDRESS = ( + "test-agent://agent1q2kxet3vh0scsf0sm7y2erzz33cve6tv5uk63x64upw5g68kr0chkv7hw50" +) alice = Agent( name="alice", diff --git a/python/examples/13-agent-name-service/agent2.py b/python/examples/13-agent-name-service/agent2.py index 2deb7fde..7fde1832 100644 --- a/python/examples/13-agent-name-service/agent2.py +++ b/python/examples/13-agent-name-service/agent2.py @@ -15,6 +15,7 @@ class Message(Model): fund_agent_if_low(alice) + @alice.on_interval(period=5) async def alice_interval_handler(ctx: Context): bob_name = "bob-0.agent" diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index b7be82a9..41d08e68 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -466,7 +466,8 @@ async def register(self): not self._almanac_contract.is_registered(self._identity.address) or self._almanac_contract.get_expiry(self._identity.address) < REGISTRATION_UPDATE_INTERVAL_SECONDS - or self._endpoints != self._almanac_contract.get_endpoints(self._identity.address) + or self._endpoints + != self._almanac_contract.get_endpoints(self._identity.address) or list(self.protocols.keys()) != self._almanac_contract.get_protocols(self._identity.address) ): diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index 059963e6..d14132a7 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -8,7 +8,7 @@ logging.basicConfig(level=logging.INFO) -#class AgentNetwork(Enum): +# class AgentNetwork(Enum): # FETCHAI_TESTNET = 1 # FETCHAI_MAINNET = 2 @@ -16,7 +16,9 @@ LEDGER_PREFIX = "fetch" USER_PREFIX = "user" CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" -TESTNET_CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" +TESTNET_CONTRACT_ALMANAC = ( + "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" +) CONTRACT_NAME_SERVICE = ( "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" ) @@ -25,7 +27,7 @@ REGISTRATION_UPDATE_INTERVAL_SECONDS = 3600 REGISTRATION_RETRY_INTERVAL_SECONDS = 60 AVERAGE_BLOCK_INTERVAL = 5.7 -#AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET +# AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET AGENTVERSE_URL = "https://agentverse.ai" ALMANAC_API_URL = AGENTVERSE_URL + "/v1/almanac/" diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index e9d8a68f..2346f9de 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -35,7 +35,10 @@ _faucet_api = FaucetApi(NetworkConfig.fetchai_stable_testnet()) _testnet_ledger = LedgerClient(NetworkConfig.fetchai_stable_testnet()) -_ledger = LedgerClient(NetworkConfig.fetchai_mainnet()) +_ledger = LedgerClient( + NetworkConfig.fetchai_stable_testnet() +) # LedgerClient(NetworkConfig.fetchai_mainnet()) + def get_ledger(test: bool) -> LedgerClient: """ @@ -45,7 +48,7 @@ def get_ledger(test: bool) -> LedgerClient: LedgerClient: The Ledger client instance. """ if test: - return _testnet_ledger + return _testnet_ledger return _ledger @@ -247,7 +250,9 @@ def get_sequence(self, address: str) -> int: _almanac_contract = AlmanacContract(None, _ledger, CONTRACT_ALMANAC) -_testnet_almanac_contract = AlmanacContract(None, _testnet_ledger, TESTNET_CONTRACT_ALMANAC) +_testnet_almanac_contract = AlmanacContract( + None, _testnet_ledger, TESTNET_CONTRACT_ALMANAC +) def get_almanac_contract(test: bool) -> AlmanacContract: @@ -378,7 +383,9 @@ async def register( logger.info("Registering name...") chain_id = ledger.query_chain_id() - if not get_almanac_contract(chain_id == "dorado-1").is_registered(agent_address): + if not get_almanac_contract(chain_id == "dorado-1").is_registered( + agent_address + ): logger.warning( f"Agent {name} needs to be registered in almanac contract to register its name" ) @@ -406,7 +413,9 @@ async def register( logger.info("Registering name...complete") -_name_service_contract = NameServiceContract(None, _testnet_ledger, CONTRACT_NAME_SERVICE) +_name_service_contract = NameServiceContract( + None, _testnet_ledger, CONTRACT_NAME_SERVICE +) def get_name_service_contract() -> NameServiceContract: diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 291a62f6..71dec444 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -10,6 +10,7 @@ _testnet_prefixe = "test-agent://" _mainnet_prefix = "agent://" + def query_record(agent_address: str, service: str, test: bool) -> dict: """ Query a record from the Almanac contract. @@ -61,7 +62,7 @@ def is_agent_address(address) -> tuple: if not isinstance(address, str): return False - prefixes = [_testnet_prefixe , _mainnet_prefix, ""] + prefixes = [_testnet_prefixe, _mainnet_prefix, ""] expected_length = 65 for prefix in prefixes: @@ -113,8 +114,12 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: """ is_address, prefix = is_agent_address(destination) if is_address: - return await self._almanc_resolver.resolve(destination[len(prefix):], not prefix == _mainnet_prefix) - return await self._name_service_resolver.resolve(destination, not prefix == _mainnet_prefix) + return await self._almanc_resolver.resolve( + destination[len(prefix) :], not prefix == _mainnet_prefix + ) + return await self._name_service_resolver.resolve( + destination, not prefix == _mainnet_prefix + ) class AlmanacResolver(Resolver): @@ -127,7 +132,9 @@ def __init__(self, max_endpoints: Optional[int] = None): """ self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS - async def resolve(self, destination: str, test: bool) -> Tuple[Optional[str], List[str]]: + async def resolve( + self, destination: str, test: bool + ) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the Almanac contract. @@ -167,7 +174,9 @@ def __init__(self, max_endpoints: Optional[int] = None): self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS self._almanac_resolver = AlmanacResolver(max_endpoints=self._max_endpoints) - async def resolve(self, destination: str, test: bool) -> Tuple[Optional[str], List[str]]: + async def resolve( + self, destination: str, test: bool + ) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the NameService contract. diff --git a/python/src/uagents/setup.py b/python/src/uagents/setup.py index 4f0bba29..8f531b47 100644 --- a/python/src/uagents/setup.py +++ b/python/src/uagents/setup.py @@ -9,6 +9,7 @@ LOGGER = get_logger("setup") + def fund_agent_if_low(agent: Agent): """ Checks the agent's wallet balance and adds funds if it's below the registration fee. @@ -25,7 +26,9 @@ def fund_agent_if_low(agent: Agent): agent_balance = ledger.query_bank_balance(Address(agent.wallet.address())) if not agent._test: - LOGGER.warning(f"Faucet only available for testnet, please add FET tokens to your wallet {agent.wallet.address()}") + LOGGER.warning( + f"Faucet only available for testnet, please add FET tokens to your wallet {agent.wallet.address()}" + ) LOGGER.info(f"Current FET balance: {agent_balance}") return diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index df60e985..bec8fdee 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -5,6 +5,7 @@ test_prefix = "test-agent://" + class TestAgentAdress(unittest.TestCase): def test_agent_from_seed(self): alice = Agent(name="alice", seed="alice recovery password") @@ -19,7 +20,9 @@ def test_agent_from_seed(self): "Alice's address does not match", ) self.assertEqual( - bob.address == test_prefix + bob_target_address, True, "Bobs's address does not match" + bob.address == test_prefix + bob_target_address, + True, + "Bobs's address does not match", ) def test_agent_generate(self): diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index f4f78380..a837bc2c 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -83,7 +83,9 @@ async def test_name_service_registration(self): query_address = get_agent_address(agent.name + "." + domain) self.assertEqual( - query_address == agent.address[-65:], True, "Service contract registration failed" + query_address == agent.address[-65:], + True, + "Service contract registration failed", ) From 7e62da35c4a2744cc2ec16b9a2b93f59986936c8 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Thu, 28 Sep 2023 19:50:20 -0600 Subject: [PATCH 04/26] fix: pylint --- python/examples/06-send-tokens/main.py | 2 ++ python/examples/13-agent-name-service/agent1.py | 8 +++++--- python/src/uagents/config.py | 3 ++- python/src/uagents/resolver.py | 10 +++++----- python/src/uagents/setup.py | 8 +++++--- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index a766043f..9cfe3ec0 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -2,6 +2,8 @@ from uagents.network import wait_for_tx_to_complete from uagents.setup import fund_agent_if_low +# pylint: disable=protected-access + class PaymentRequest(Model): wallet_address: str diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index c180acb9..c6abf1ba 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -1,6 +1,6 @@ from cosmpy.aerial.wallet import LocalWallet -from uagents.network import get_ledger, get_faucet, get_name_service_contract +from uagents.network import get_faucet, get_name_service_contract from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model @@ -9,6 +9,8 @@ # NOTE: Run agent1.py before running agent2.py +# pylint: disable=protected-access + class Message(Model): message: str @@ -28,9 +30,9 @@ class Message(Model): DOMAIN = "agent" faucet = get_faucet() -agent_balance = bob._ledger.query_bank_balance(my_wallet) +AGENT_BALANCE = bob._ledger.query_bank_balance(my_wallet) -if agent_balance < REGISTRATION_FEE: +if AGENT_BALANCE < REGISTRATION_FEE: print("Adding funds to wallet...") faucet.get_wealth(my_wallet) print("Adding funds to wallet...complete") diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index d14132a7..07cce529 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -1,6 +1,7 @@ import logging import sys -from enum import Enum + +# from enum import Enum from typing import Any, Dict, List, Optional, Union from uvicorn.logging import DefaultFormatter diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 71dec444..0324d9ea 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -7,8 +7,8 @@ from uagents.config import DEFAULT_MAX_ENDPOINTS from uagents.network import get_almanac_contract, get_name_service_contract -_testnet_prefixe = "test-agent://" -_mainnet_prefix = "agent://" +TESTNET_PREFIX = "test-agent://" +MAINNET_PREFIX = "agent://" def query_record(agent_address: str, service: str, test: bool) -> dict: @@ -62,7 +62,7 @@ def is_agent_address(address) -> tuple: if not isinstance(address, str): return False - prefixes = [_testnet_prefixe, _mainnet_prefix, ""] + prefixes = [TESTNET_PREFIX, MAINNET_PREFIX, ""] expected_length = 65 for prefix in prefixes: @@ -115,10 +115,10 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: is_address, prefix = is_agent_address(destination) if is_address: return await self._almanc_resolver.resolve( - destination[len(prefix) :], not prefix == _mainnet_prefix + destination[len(prefix) :], not prefix == MAINNET_PREFIX ) return await self._name_service_resolver.resolve( - destination, not prefix == _mainnet_prefix + destination, not prefix == MAINNET_PREFIX ) diff --git a/python/src/uagents/setup.py b/python/src/uagents/setup.py index 8f531b47..616e9a0b 100644 --- a/python/src/uagents/setup.py +++ b/python/src/uagents/setup.py @@ -10,6 +10,7 @@ LOGGER = get_logger("setup") +# pylint: disable=protected-access def fund_agent_if_low(agent: Agent): """ Checks the agent's wallet balance and adds funds if it's below the registration fee. @@ -27,7 +28,8 @@ def fund_agent_if_low(agent: Agent): if not agent._test: LOGGER.warning( - f"Faucet only available for testnet, please add FET tokens to your wallet {agent.wallet.address()}" + "Faucet only available for testnet, please add FET tokens to your wallet " + f"{agent.wallet.address()}" ) LOGGER.info(f"Current FET balance: {agent_balance}") return @@ -37,8 +39,8 @@ def fund_agent_if_low(agent: Agent): LOGGER.info("Adding funds to agent...") faucet.get_wealth(agent.wallet.address()) LOGGER.info("Adding funds to agent...complete") - except Exception as e: - LOGGER.error(f"Failed to add funds to agent: {str(e)}") + except Exception as ex: + LOGGER.error(f"Failed to add funds to agent: {str(ex)}") def register_agent_with_mailbox(agent: Agent, email: str): From 3494270e73d9cd973d15f22dbf2dcdc446ef8bee Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Fri, 29 Sep 2023 05:35:53 -0600 Subject: [PATCH 05/26] fix: pylint --- python/examples/06-send-tokens/main.py | 2 +- python/src/uagents/config.py | 8 +++----- python/src/uagents/resolver.py | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index 9cfe3ec0..0147117c 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -38,7 +38,7 @@ async def request_funds(ctx: Context): @alice.on_message(model=TransactionInfo) async def confirm_transaction(ctx: Context, sender: str, msg: TransactionInfo): ctx.logger.info(f"Received transaction info from {sender}: {msg}") - tx_resp = await wait_for_tx_to_complete(msg.tx_hash, alice._ledger) + tx_resp = await wait_for_tx_to_complete(msg.tx_hash, ctx.ledger) coin_received = tx_resp.events["coin_received"] if ( diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index 07cce529..6383de00 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -9,13 +9,12 @@ logging.basicConfig(level=logging.INFO) -# class AgentNetwork(Enum): -# FETCHAI_TESTNET = 1 -# FETCHAI_MAINNET = 2 - AGENT_PREFIX = "agent" LEDGER_PREFIX = "fetch" USER_PREFIX = "user" +TESTNET_PREFIX = "test-agent://" +MAINNET_PREFIX = "agent://" + CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" TESTNET_CONTRACT_ALMANAC = ( "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" @@ -28,7 +27,6 @@ REGISTRATION_UPDATE_INTERVAL_SECONDS = 3600 REGISTRATION_RETRY_INTERVAL_SECONDS = 60 AVERAGE_BLOCK_INTERVAL = 5.7 -# AGENT_NETWORK = AgentNetwork.FETCHAI_TESTNET AGENTVERSE_URL = "https://agentverse.ai" ALMANAC_API_URL = AGENTVERSE_URL + "/v1/almanac/" diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 0324d9ea..6eca39f5 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -4,11 +4,10 @@ from typing import Dict, List, Optional, Tuple import random -from uagents.config import DEFAULT_MAX_ENDPOINTS +from uagents.config import DEFAULT_MAX_ENDPOINTS, TESTNET_PREFIX, MAINNET_PREFIX from uagents.network import get_almanac_contract, get_name_service_contract -TESTNET_PREFIX = "test-agent://" -MAINNET_PREFIX = "agent://" +# pylint: disable=arguments-differ def query_record(agent_address: str, service: str, test: bool) -> dict: From 67d4634979c3a9b8e7f882b448e34a850354d3d3 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Fri, 29 Sep 2023 05:39:37 -0600 Subject: [PATCH 06/26] fix: variable name --- python/tests/test_agent_address.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index bec8fdee..994262ec 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -2,8 +2,7 @@ from uagents import Agent from uagents.crypto import Identity - -test_prefix = "test-agent://" +from uagents.config import TESTNET_PREFIX class TestAgentAdress(unittest.TestCase): @@ -15,12 +14,12 @@ def test_agent_from_seed(self): bob_target_address = Identity.from_seed("bob recovery password", 0).address self.assertEqual( - alice.address == test_prefix + alice_target_address, + alice.address == TESTNET_PREFIX + alice_target_address, True, "Alice's address does not match", ) self.assertEqual( - bob.address == test_prefix + bob_target_address, + bob.address == TESTNET_PREFIX + bob_target_address, True, "Bobs's address does not match", ) @@ -29,7 +28,7 @@ def test_agent_generate(self): alice = Agent(name="alice") self.assertEqual(alice.address[-65:-60] == "agent", True) - self.assertEqual(len(alice.address) == 65 + len(test_prefix), True) + self.assertEqual(len(alice.address) == 65 + len(TESTNET_PREFIX), True) if __name__ == "__main__": From 61220ceb09caebdd405797d1b6f3454f0d6b3c1e Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Fri, 29 Sep 2023 08:18:21 -0600 Subject: [PATCH 07/26] feat: added agent ledger and balance properties --- .../examples/13-agent-name-service/agent1.py | 10 +++---- python/src/uagents/agent.py | 26 +++++++++++++++++-- python/src/uagents/config.py | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index c6abf1ba..113a1b92 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -1,6 +1,6 @@ from cosmpy.aerial.wallet import LocalWallet -from uagents.network import get_faucet, get_name_service_contract +from uagents.network import get_faucet, get_name_service_contract, _testnet_ledger from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model @@ -9,8 +9,6 @@ # NOTE: Run agent1.py before running agent2.py -# pylint: disable=protected-access - class Message(Model): message: str @@ -30,9 +28,9 @@ class Message(Model): DOMAIN = "agent" faucet = get_faucet() -AGENT_BALANCE = bob._ledger.query_bank_balance(my_wallet) +WALLET_BALANCE = _testnet_ledger.query_bank_balance(my_wallet) -if AGENT_BALANCE < REGISTRATION_FEE: +if WALLET_BALANCE < REGISTRATION_FEE: print("Adding funds to wallet...") faucet.get_wealth(my_wallet) print("Adding funds to wallet...complete") @@ -41,7 +39,7 @@ class Message(Model): @bob.on_event("startup") async def register_agent_name(ctx: Context): await name_service_contract.register( - bob._ledger, my_wallet, ctx.address[-65:], ctx.name, DOMAIN + bob.ledger, my_wallet, ctx.address[-65:], ctx.name, DOMAIN ) diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index 41d08e68..0a0a8563 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -9,6 +9,7 @@ from cosmpy.aerial.wallet import LocalWallet, PrivateKey from cosmpy.crypto.address import Address +from cosmpy.aerial.client import LedgerClient from uagents.asgi import ASGIServer from uagents.context import ( @@ -316,6 +317,16 @@ def wallet(self) -> LocalWallet: """ return self._wallet + @property + def ledger(self) -> LedgerClient: + """ + Get the ledger of the agent. + + Returns: + LedgerClient: The agent's ledger + """ + return self._ledger + @property def storage(self) -> KeyValueStore: """ @@ -356,6 +367,17 @@ def mailbox_client(self) -> MailboxClient: """ return self._mailbox_client + @property + def balance(self) -> int: + """ + Get the balance of the agent. + + Returns: + int: Bank balance. + """ + + return self.ledger.query_bank_balance(Address(self.wallet.address())) + @mailbox.setter def mailbox(self, config: Union[str, Dict[str, str]]): """ @@ -471,7 +493,7 @@ async def register(self): or list(self.protocols.keys()) != self._almanac_contract.get_protocols(self._identity.address) ): - agent_balance = self._ledger.query_bank_balance( + agent_balance = self.ledger.query_bank_balance( Address(self.wallet.address()) ) @@ -484,7 +506,7 @@ async def register(self): self._logger.info("Registering on almanac contract...") signature = self.sign_registration() await self._almanac_contract.register( - self._ledger, + self.ledger, self.wallet, self._identity.address, list(self.protocols.keys()), diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index 6383de00..c85999fb 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -1,7 +1,7 @@ import logging import sys -# from enum import Enum + from typing import Any, Dict, List, Optional, Union from uvicorn.logging import DefaultFormatter From f85a553ed325181c71b8093ffcef53d05fbbf1c6 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Mon, 2 Oct 2023 07:06:07 -0600 Subject: [PATCH 08/26] feat: added network_address to agent --- python/examples/01-first-agent/main.py | 4 +- python/examples/02-interval-task/main.py | 4 +- python/examples/05-send-msg/main.py | 2 +- python/examples/06-send-tokens/main.py | 4 +- python/examples/07-msg-verification/main.py | 4 +- .../examples/13-agent-name-service/agent1.py | 2 +- python/src/uagents/agent.py | 39 ++++++++++++------ python/src/uagents/context.py | 16 +++++++- python/tests/test_agent.py | 4 +- python/tests/test_agent_address.py | 13 +++--- python/tests/test_agent_registration.py | 12 +++--- python/tests/test_context.py | 40 +++++++++---------- python/tests/test_msg_verify.py | 2 +- python/tests/test_server.py | 38 +++++++++--------- 14 files changed, 104 insertions(+), 80 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index 8b52ac74..d33a5c22 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -5,7 +5,9 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.address}.") + ctx.logger.info( + f"Hello, I'm agent {ctx.name} and my address is {ctx.network_address}." + ) if __name__ == "__main__": diff --git a/python/examples/02-interval-task/main.py b/python/examples/02-interval-task/main.py index a52cfdd5..3114dcc2 100644 --- a/python/examples/02-interval-task/main.py +++ b/python/examples/02-interval-task/main.py @@ -5,7 +5,9 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.address}.") + ctx.logger.info( + f"Hello, I'm agent {ctx.name} and my address is {ctx.network_address}." + ) @agent.on_interval(period=2.0) diff --git a/python/examples/05-send-msg/main.py b/python/examples/05-send-msg/main.py index 775a6097..423cb860 100644 --- a/python/examples/05-send-msg/main.py +++ b/python/examples/05-send-msg/main.py @@ -12,7 +12,7 @@ class Message(Model): @alice.on_interval(period=2.0) async def send_message(ctx: Context): msg = f"Hello there {bob.name} my name is {alice.name}." - await ctx.send(bob.address, Message(text=msg)) + await ctx.send(bob.network_address, Message(text=msg)) @bob.on_message(model=Message) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index 0147117c..d7c9ec3e 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -28,7 +28,7 @@ class TransactionInfo(Model): @alice.on_interval(period=10.0) async def request_funds(ctx: Context): await ctx.send( - bob.address, + bob.network_address, PaymentRequest( wallet_address=str(ctx.wallet.address()), amount=AMOUNT, denom=DENOM ), @@ -58,7 +58,7 @@ async def send_payment(ctx: Context, sender: str, msg: PaymentRequest): ) # send the tx hash so alice can confirm - await ctx.send(alice.address, TransactionInfo(tx_hash=transaction.tx_hash)) + await ctx.send(alice.network_address, TransactionInfo(tx_hash=transaction.tx_hash)) bureau = Bureau() diff --git a/python/examples/07-msg-verification/main.py b/python/examples/07-msg-verification/main.py index 397eb0b0..087a0381 100644 --- a/python/examples/07-msg-verification/main.py +++ b/python/examples/07-msg-verification/main.py @@ -24,7 +24,7 @@ async def send_message(ctx: Context): msg = "Hello there bob." digest = encode(msg) await ctx.send( - bob.address, + bob.network_address, Message(message=msg, digest=digest.hex(), signature=alice.sign_digest(digest)), ) @@ -53,7 +53,7 @@ async def bob_rx_message(ctx: Context, sender: str, msg: Message): # send the response await ctx.send( - alice.address, + alice.network_address, Message(message=msg, digest=digest.hex(), signature=bob.sign_digest(digest)), ) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 113a1b92..5effbe80 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -39,7 +39,7 @@ class Message(Model): @bob.on_event("startup") async def register_agent_name(ctx: Context): await name_service_contract.register( - bob.ledger, my_wallet, ctx.address[-65:], ctx.name, DOMAIN + bob.ledger, my_wallet, ctx.address, ctx.name, DOMAIN ) diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index 0a0a8563..955d5021 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -35,6 +35,8 @@ REGISTRATION_UPDATE_INTERVAL_SECONDS, LEDGER_PREFIX, REGISTRATION_RETRY_INTERVAL_SECONDS, + TESTNET_PREFIX, + MAINNET_PREFIX, parse_endpoint_config, parse_agentverse_config, get_logger, @@ -215,7 +217,7 @@ def __init__( self._ledger = get_ledger(self._test) self._almanac_contract = get_almanac_contract(self._test) - self._storage = KeyValueStore(self._identity.address[0:16]) + self._storage = KeyValueStore(self.address[0:16]) self._interval_handlers: List[Tuple[IntervalCallback, float]] = [] self._interval_messages: Set[str] = set() self._signed_message_handlers: Dict[str, MessageCallback] = {} @@ -236,7 +238,8 @@ def __init__( self.protocols: Dict[str, Protocol] = {} self._ctx = Context( - self.address, + self._identity.address, + self.network_address, self._name, self._storage, self._resolver, @@ -251,7 +254,7 @@ def __init__( ) # register with the dispatcher - self._dispatcher.register(self._identity.address, self) + self._dispatcher.register(self.address, self) if not self._use_mailbox: self._server = ASGIServer( @@ -284,7 +287,7 @@ def _initialize_wallet_and_identity(self, seed, name): prefix=LEDGER_PREFIX, ) if name is None: - self._name = self._identity.address[0:16] + self._name = self.address[0:16] @property def name(self) -> str: @@ -304,7 +307,17 @@ def address(self) -> str: Returns: str: The agent's address. """ - prefix = "test-agent://" if self._test else "agent://" + return self._identity.address + + @property + def network_address(self) -> str: + """ + Get the address of the agent used for communication including the network prefix. + + Returns: + str: The agent's address and network prefix. + """ + prefix = TESTNET_PREFIX if self._test else MAINNET_PREFIX return prefix + self._identity.address @property @@ -438,7 +451,7 @@ def sign_registration(self) -> str: assert self._almanac_contract.address is not None return self._identity.sign_registration( str(self._almanac_contract.address), - self._almanac_contract.get_sequence(self._identity.address), + self._almanac_contract.get_sequence(self.address), ) def update_endpoints(self, endpoints: List[Dict[str, Any]]): @@ -485,13 +498,12 @@ async def register(self): # register if not yet registered or registration is about to expire # or anything has changed from the last registration if ( - not self._almanac_contract.is_registered(self._identity.address) - or self._almanac_contract.get_expiry(self._identity.address) + not self._almanac_contract.is_registered(self.address) + or self._almanac_contract.get_expiry(self.address) < REGISTRATION_UPDATE_INTERVAL_SECONDS - or self._endpoints - != self._almanac_contract.get_endpoints(self._identity.address) + or self._endpoints != self._almanac_contract.get_endpoints(self.address) or list(self.protocols.keys()) - != self._almanac_contract.get_protocols(self._identity.address) + != self._almanac_contract.get_protocols(self.address) ): agent_balance = self.ledger.query_bank_balance( Address(self.wallet.address()) @@ -508,7 +520,7 @@ async def register(self): await self._almanac_contract.register( self.ledger, self.wallet, - self._identity.address, + self.address, list(self.protocols.keys()), self._endpoints, signature, @@ -826,7 +838,8 @@ async def _process_message_queue(self): continue context = Context( - self.address, + self._identity.address, + self.network_address, self._name, self._storage, self._resolver, diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index 2b14ad04..ebe085d2 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -134,6 +134,7 @@ class Context: def __init__( self, address: str, + network_address: str, name: Optional[str], storage: KeyValueStore, resolve: Resolver, @@ -174,6 +175,7 @@ def __init__( self.ledger = ledger self._name = name self._address = str(address) + self._network_address = str(network_address) self._resolver = resolve self._identity = identity self._queries = queries @@ -206,6 +208,16 @@ def address(self) -> str: """ return self._address + @property + def network_address(self) -> str: + """ + Get the address of the agent used for communication including the network prefix. + + Returns: + str: The agent's address and network prefix. + """ + return self._network_address + @property def logger(self) -> logging.Logger: """ @@ -414,7 +426,7 @@ async def send_raw( # Handle local dispatch of messages if dispatcher.contains(raw_destination): await dispatcher.dispatch( - self._identity.address, + self.address, raw_destination, schema_digest, json_message, @@ -457,7 +469,7 @@ async def send_raw( # Handle external dispatch of messages env = Envelope( version=1, - sender=self._identity.address, + sender=self.address, target=destination_address, session=self._session or uuid.uuid4(), schema_digest=schema_digest, diff --git a/python/tests/test_agent.py b/python/tests/test_agent.py index f51dcd21..bc85b6b5 100644 --- a/python/tests/test_agent.py +++ b/python/tests/test_agent.py @@ -30,7 +30,7 @@ def test_agent_init(self): self.assertIsNotNone(self.agent._wallet) self.assertIsNotNone(self.agent._identity) self.assertIsNotNone(self.agent._server) - self.assertTrue(self.agent._dispatcher.contains(self.agent.address[-65:])) + self.assertTrue(self.agent._dispatcher.contains(self.agent.address)) self.assertTrue(isinstance(self.agent._resolver, GlobalResolver)) def test_agent_on_interval(self): @@ -85,4 +85,4 @@ def _(ctx): shutdown_handlers = self.agent._on_shutdown self.assertEqual(len(shutdown_handlers), 1) self.assertTrue(isinstance(shutdown_handlers[0], Callable)) - self.assertIsNone(self.agent._ctx.storage.get("shutdown")) + self.assertIsNone(self.agent._ctx.storage.get("shutdown")) \ No newline at end of file diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index 994262ec..ec9b5f96 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -2,7 +2,6 @@ from uagents import Agent from uagents.crypto import Identity -from uagents.config import TESTNET_PREFIX class TestAgentAdress(unittest.TestCase): @@ -14,22 +13,20 @@ def test_agent_from_seed(self): bob_target_address = Identity.from_seed("bob recovery password", 0).address self.assertEqual( - alice.address == TESTNET_PREFIX + alice_target_address, + alice.address == alice_target_address, True, "Alice's address does not match", ) self.assertEqual( - bob.address == TESTNET_PREFIX + bob_target_address, - True, - "Bobs's address does not match", + bob.address == bob_target_address, True, "Bobs's address does not match" ) def test_agent_generate(self): alice = Agent(name="alice") - self.assertEqual(alice.address[-65:-60] == "agent", True) - self.assertEqual(len(alice.address) == 65 + len(TESTNET_PREFIX), True) + self.assertEqual(alice.address[:5] == "agent", True) + self.assertEqual(len(alice.address) == 65, True) if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index a837bc2c..4d6d691d 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -16,7 +16,7 @@ async def test_almanac_registration(self): await agent.register() self.assertEqual( - agent._almanac_contract.is_registered(agent.address[-65:]), + agent._almanac_contract.is_registered(agent.address), True, "Almanac registration failed", ) @@ -53,7 +53,7 @@ async def test_name_service_registration(self): await agent.register() self.assertEqual( - agent._almanac_contract.is_registered(agent.address[-65:]), + agent._almanac_contract.is_registered(agent.address), True, "Almanac registration failed", ) @@ -69,7 +69,7 @@ async def test_name_service_registration(self): self.assertEqual(is_owner, False) await name_service_contract.register( - agent._ledger, agent.wallet, agent.address[-65:], agent.name, domain=domain + agent._ledger, agent.wallet, agent.address, agent.name, domain=domain ) is_name_available = name_service_contract.is_name_available(agent.name, domain) @@ -83,11 +83,9 @@ async def test_name_service_registration(self): query_address = get_agent_address(agent.name + "." + domain) self.assertEqual( - query_address == agent.address[-65:], - True, - "Service contract registration failed", + query_address == agent.address, True, "Service contract registration failed" ) if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file diff --git a/python/tests/test_context.py b/python/tests/test_context.py index 7d4e2c9d..2c2ade95 100644 --- a/python/tests/test_context.py +++ b/python/tests/test_context.py @@ -25,10 +25,10 @@ class Message(Model): endpoints = ["http://localhost:8000"] clyde = Agent(name="clyde", seed="clyde recovery phrase", endpoint=endpoints) -dispatcher.unregister(clyde.address[-65:], clyde) +dispatcher.unregister(clyde.address, clyde) resolver = RulesBasedResolver( rules={ - clyde.address[-65:]: endpoints, + clyde.address: endpoints, } ) alice = Agent(name="alice", seed="alice recovery phrase", resolve=resolver) @@ -49,7 +49,7 @@ async def test_send_local_dispatch(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address[-65:], + destination=bob.address, endpoint="", ) @@ -64,7 +64,7 @@ async def test_send_local_dispatch_valid_reply(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address[-65:], + destination=bob.address, endpoint="", ) @@ -81,7 +81,7 @@ async def test_send_local_dispatch_invalid_reply(self): exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid reply", - destination=bob.address[-65:], + destination=bob.address, endpoint="", ) @@ -95,7 +95,7 @@ async def test_send_local_dispatch_valid_interval_msg(self): exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message dispatched locally", - destination=bob.address[-65:], + destination=bob.address, endpoint="", ) @@ -108,7 +108,7 @@ async def test_send_local_dispatch_invalid_interval_msg(self): exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid interval message", - destination=bob.address[-65:], + destination=bob.address, endpoint="", ) @@ -116,12 +116,12 @@ async def test_send_local_dispatch_invalid_interval_msg(self): async def test_send_resolve_sync_query(self): future = asyncio.Future() - self.context._queries[clyde.address[-65:]] = future + self.context._queries[clyde.address] = future result = await self.context.send(clyde.address, msg) exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Sync message resolved", - destination=clyde.address[-65:], + destination=clyde.address, endpoint="", ) @@ -149,13 +149,13 @@ async def test_send_external_dispatch_success(self, mocked_responses): mocked_responses.post(endpoints[0], status=200) # Perform the actual operation - result = await self.context.send(clyde.address[-65:], msg) + result = await self.context.send(clyde.address, msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address[-65:], + destination=clyde.address, endpoint=endpoints[0], ) @@ -168,13 +168,13 @@ async def test_send_external_dispatch_failure(self, mocked_responses): mocked_responses.post(endpoints[0], status=404) # Perform the actual operation - result = await self.context.send(clyde.address[-65:], msg) + result = await self.context.send(clyde.address, msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Message delivery failed", - destination=clyde.address[-65:], + destination=clyde.address, endpoint="", ) @@ -192,13 +192,13 @@ async def test_send_external_dispatch_multiple_endpoints_first_success( mocked_responses.post(endpoints[1], status=404) # Perform the actual operation - result = await self.context.send(clyde.address[-65:], msg) + result = await self.context.send(clyde.address, msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address[-65:], + destination=clyde.address, endpoint=endpoints[0], ) @@ -221,13 +221,13 @@ async def test_send_external_dispatch_multiple_endpoints_second_success( mocked_responses.post(endpoints[1], status=200) # Perform the actual operation - result = await self.context.send(clyde.address[-65:], msg) + result = await self.context.send(clyde.address, msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.DELIVERED, detail="Message successfully delivered via HTTP", - destination=clyde.address[-65:], + destination=clyde.address, endpoint=endpoints[1], ) @@ -247,17 +247,17 @@ async def test_send_external_dispatch_multiple_endpoints_failure( mocked_responses.post(endpoints[1], status=404) # Perform the actual operation - result = await self.context.send(clyde.address[-65:], msg) + result = await self.context.send(clyde.address, msg) # Define the expected message status exp_msg_status = MsgStatus( status=DeliveryStatus.FAILED, detail="Message delivery failed", - destination=clyde.address[-65:], + destination=clyde.address, endpoint="", ) # Assertions self.assertEqual(result, exp_msg_status) - endpoints.pop() + endpoints.pop() \ No newline at end of file diff --git a/python/tests/test_msg_verify.py b/python/tests/test_msg_verify.py index ae6fa7fd..b2b107a2 100644 --- a/python/tests/test_msg_verify.py +++ b/python/tests/test_msg_verify.py @@ -23,7 +23,7 @@ def test_sign_and_verify_message(self): signature = alice.sign_digest(encoded_msg) # Message signature can be verified using alice address - result = Identity.verify_digest(alice.address[-65:], encoded_msg, signature) + result = Identity.verify_digest(alice.address, encoded_msg, signature) self.assertEqual(result, True, "Verification failed") diff --git a/python/tests/test_server.py b/python/tests/test_server.py index f84c4241..0e1997e4 100644 --- a/python/tests/test_server.py +++ b/python/tests/test_server.py @@ -32,8 +32,8 @@ async def test_message_success(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -77,7 +77,7 @@ async def test_message_success_unsigned(self): env = Envelope( version=1, sender=user, - target=self.agent.address[-65:], + target=self.agent.address, session=session, protocol=Model.build_schema_digest(message), ) @@ -121,7 +121,7 @@ async def test_message_success_sync(self): env = Envelope( version=1, sender=user, - target=self.agent.address[-65:], + target=self.agent.address, session=session, protocol=Model.build_schema_digest(message), ) @@ -146,7 +146,7 @@ async def test_message_success_sync(self): ), asyncio.create_task(self.mock_process_sync_message(user, reply)), ) - response = enclose_response(reply, self.agent.address[-65:], session) + response = enclose_response(reply, self.agent.address, session) mock_send.assert_has_calls( [ call( @@ -171,8 +171,8 @@ async def test_message_success_sync_unsigned(self): session = uuid.uuid4() env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=session, protocol=Model.build_schema_digest(message), ) @@ -197,10 +197,10 @@ async def test_message_success_sync_unsigned(self): ) ), asyncio.create_task( - self.mock_process_sync_message(self.bob.address[-65:], reply) + self.mock_process_sync_message(self.bob.address, reply) ), ) - response = enclose_response(reply, self.agent.address[-65:], session) + response = enclose_response(reply, self.agent.address, session) mock_send.assert_has_calls( [ call( @@ -223,8 +223,8 @@ async def test_message_fail_wrong_path(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -265,8 +265,8 @@ async def test_message_fail_wrong_headers(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -339,8 +339,8 @@ async def test_message_fail_unsigned(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -380,8 +380,8 @@ async def test_message_fail_verify(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], - target=self.agent.address[-65:], + sender=self.bob.address, + target=self.agent.address, session=uuid.uuid4(), protocol=Model.build_schema_digest(message), ) @@ -422,7 +422,7 @@ async def test_message_fail_dispatch(self): message = Message(message="hello") env = Envelope( version=1, - sender=self.bob.address[-65:], + sender=self.bob.address, target=generate_user_address(), session=uuid.uuid4(), protocol=Model.build_schema_digest(message), @@ -520,4 +520,4 @@ async def test_request_from_browser(self): if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From 28bf7c953e78f0c145552d9bf3f356ac6f6559a4 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Mon, 2 Oct 2023 07:09:01 -0600 Subject: [PATCH 09/26] fix: minor tests fix --- python/tests/test_agent.py | 2 +- python/tests/test_agent_address.py | 2 +- python/tests/test_agent_registration.py | 2 +- python/tests/test_context.py | 2 +- python/tests/test_server.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/tests/test_agent.py b/python/tests/test_agent.py index bc85b6b5..36ac435a 100644 --- a/python/tests/test_agent.py +++ b/python/tests/test_agent.py @@ -85,4 +85,4 @@ def _(ctx): shutdown_handlers = self.agent._on_shutdown self.assertEqual(len(shutdown_handlers), 1) self.assertTrue(isinstance(shutdown_handlers[0], Callable)) - self.assertIsNone(self.agent._ctx.storage.get("shutdown")) \ No newline at end of file + self.assertIsNone(self.agent._ctx.storage.get("shutdown")) diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index ec9b5f96..c9c29dc2 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -29,4 +29,4 @@ def test_agent_generate(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index 4d6d691d..c04b3d56 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -88,4 +88,4 @@ async def test_name_service_registration(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/python/tests/test_context.py b/python/tests/test_context.py index 2c2ade95..c57895a6 100644 --- a/python/tests/test_context.py +++ b/python/tests/test_context.py @@ -260,4 +260,4 @@ async def test_send_external_dispatch_multiple_endpoints_failure( # Assertions self.assertEqual(result, exp_msg_status) - endpoints.pop() \ No newline at end of file + endpoints.pop() diff --git a/python/tests/test_server.py b/python/tests/test_server.py index 0e1997e4..a58fb063 100644 --- a/python/tests/test_server.py +++ b/python/tests/test_server.py @@ -520,4 +520,4 @@ async def test_request_from_browser(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 474e9b8e32a3767f31a8797be548ae55fd8fa100 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Mon, 2 Oct 2023 10:17:37 -0600 Subject: [PATCH 10/26] feat: changed name to agent.identifier --- python/examples/01-first-agent/main.py | 2 +- python/examples/02-interval-task/main.py | 2 +- python/examples/05-send-msg/main.py | 2 +- python/examples/06-send-tokens/main.py | 6 ++---- python/examples/07-msg-verification/main.py | 4 ++-- python/src/uagents/agent.py | 12 ++++-------- python/src/uagents/context.py | 8 ++++---- 7 files changed, 15 insertions(+), 21 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index d33a5c22..a9065d79 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -6,7 +6,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): ctx.logger.info( - f"Hello, I'm agent {ctx.name} and my address is {ctx.network_address}." + f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}." ) diff --git a/python/examples/02-interval-task/main.py b/python/examples/02-interval-task/main.py index 3114dcc2..9987d12a 100644 --- a/python/examples/02-interval-task/main.py +++ b/python/examples/02-interval-task/main.py @@ -6,7 +6,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): ctx.logger.info( - f"Hello, I'm agent {ctx.name} and my address is {ctx.network_address}." + f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}." ) diff --git a/python/examples/05-send-msg/main.py b/python/examples/05-send-msg/main.py index 423cb860..b11e1e61 100644 --- a/python/examples/05-send-msg/main.py +++ b/python/examples/05-send-msg/main.py @@ -12,7 +12,7 @@ class Message(Model): @alice.on_interval(period=2.0) async def send_message(ctx: Context): msg = f"Hello there {bob.name} my name is {alice.name}." - await ctx.send(bob.network_address, Message(text=msg)) + await ctx.send(bob.identifier, Message(text=msg)) @bob.on_message(model=Message) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index d7c9ec3e..3da95aaa 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -2,8 +2,6 @@ from uagents.network import wait_for_tx_to_complete from uagents.setup import fund_agent_if_low -# pylint: disable=protected-access - class PaymentRequest(Model): wallet_address: str @@ -28,7 +26,7 @@ class TransactionInfo(Model): @alice.on_interval(period=10.0) async def request_funds(ctx: Context): await ctx.send( - bob.network_address, + bob.identifier, PaymentRequest( wallet_address=str(ctx.wallet.address()), amount=AMOUNT, denom=DENOM ), @@ -58,7 +56,7 @@ async def send_payment(ctx: Context, sender: str, msg: PaymentRequest): ) # send the tx hash so alice can confirm - await ctx.send(alice.network_address, TransactionInfo(tx_hash=transaction.tx_hash)) + await ctx.send(alice.identifier, TransactionInfo(tx_hash=transaction.tx_hash)) bureau = Bureau() diff --git a/python/examples/07-msg-verification/main.py b/python/examples/07-msg-verification/main.py index 087a0381..d317a5b7 100644 --- a/python/examples/07-msg-verification/main.py +++ b/python/examples/07-msg-verification/main.py @@ -24,7 +24,7 @@ async def send_message(ctx: Context): msg = "Hello there bob." digest = encode(msg) await ctx.send( - bob.network_address, + bob.identifier, Message(message=msg, digest=digest.hex(), signature=alice.sign_digest(digest)), ) @@ -53,7 +53,7 @@ async def bob_rx_message(ctx: Context, sender: str, msg: Message): # send the response await ctx.send( - alice.network_address, + alice.identifier, Message(message=msg, digest=digest.hex(), signature=bob.sign_digest(digest)), ) diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index 955d5021..ddb42a36 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -239,7 +239,7 @@ def __init__( self._ctx = Context( self._identity.address, - self.network_address, + self.identifier, self._name, self._storage, self._resolver, @@ -310,7 +310,7 @@ def address(self) -> str: return self._identity.address @property - def network_address(self) -> str: + def identifier(self) -> str: """ Get the address of the agent used for communication including the network prefix. @@ -505,11 +505,7 @@ async def register(self): or list(self.protocols.keys()) != self._almanac_contract.get_protocols(self.address) ): - agent_balance = self.ledger.query_bank_balance( - Address(self.wallet.address()) - ) - - if agent_balance < REGISTRATION_FEE: + if self.balance < REGISTRATION_FEE: self._logger.warning( f"I do not have enough funds to register on Almanac contract\ \nFund using wallet address: {self.wallet.address()}" @@ -839,7 +835,7 @@ async def _process_message_queue(self): context = Context( self._identity.address, - self.network_address, + self.identifier, self._name, self._storage, self._resolver, diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index ebe085d2..effbb7aa 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -134,7 +134,7 @@ class Context: def __init__( self, address: str, - network_address: str, + identifier: str, name: Optional[str], storage: KeyValueStore, resolve: Resolver, @@ -175,7 +175,7 @@ def __init__( self.ledger = ledger self._name = name self._address = str(address) - self._network_address = str(network_address) + self._identifier = str(identifier) self._resolver = resolve self._identity = identity self._queries = queries @@ -209,14 +209,14 @@ def address(self) -> str: return self._address @property - def network_address(self) -> str: + def identifier(self) -> str: """ Get the address of the agent used for communication including the network prefix. Returns: str: The agent's address and network prefix. """ - return self._network_address + return self._identifier @property def logger(self) -> logging.Logger: From a2c9ce368ea17d6b561ed07e73fb9ebbfbeeb481 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Mon, 2 Oct 2023 10:22:25 -0600 Subject: [PATCH 11/26] fix: black --- python/examples/01-first-agent/main.py | 4 +--- python/examples/02-interval-task/main.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index a9065d79..60737695 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -5,9 +5,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info( - f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}." - ) + ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}.") if __name__ == "__main__": diff --git a/python/examples/02-interval-task/main.py b/python/examples/02-interval-task/main.py index 9987d12a..a7d04836 100644 --- a/python/examples/02-interval-task/main.py +++ b/python/examples/02-interval-task/main.py @@ -5,9 +5,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info( - f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}." - ) + ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}.") @agent.on_interval(period=2.0) From 32d5e61aef74c859fd7116a3fcca3930906da80c Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Mon, 2 Oct 2023 17:16:02 -0600 Subject: [PATCH 12/26] feat: extract address from destination --- .../examples/13-agent-name-service/agent1.py | 5 +- python/src/uagents/context.py | 89 ++++++++++++------- 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 5effbe80..1dc4eaef 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -1,6 +1,6 @@ from cosmpy.aerial.wallet import LocalWallet -from uagents.network import get_faucet, get_name_service_contract, _testnet_ledger +from uagents.network import get_faucet, get_ledger, get_name_service_contract from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model @@ -28,7 +28,8 @@ class Message(Model): DOMAIN = "agent" faucet = get_faucet() -WALLET_BALANCE = _testnet_ledger.query_bank_balance(my_wallet) +ledger = get_ledger(True) +WALLET_BALANCE = ledger.query_bank_balance(my_wallet) if WALLET_BALANCE < REGISTRATION_FEE: print("Adding funds to wallet...") diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index effbb7aa..45e1abb6 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -29,6 +29,8 @@ ALMANAC_API_URL, DEFAULT_ENVELOPE_TIMEOUT_SECONDS, DEFAULT_SEARCH_LIMIT, + TESTNET_PREFIX, + MAINNET_PREFIX, ) from uagents.crypto import Identity from uagents.dispatch import JsonStr, dispatcher @@ -37,6 +39,7 @@ from uagents.resolver import Resolver from uagents.storage import KeyValueStore + if TYPE_CHECKING: from uagents.protocol import Protocol @@ -45,6 +48,29 @@ EventCallback = Callable[["Context"], Awaitable[None]] +def extract_agent_address(destination: str) -> str: + """ + Extract the agent address from the provided destination. + + Args: + destination (str): The destination address to check and extract. + + Returns: + str: The extracted agent address if valid, or None if not valid. + """ + + prefixes = [TESTNET_PREFIX, MAINNET_PREFIX, ""] + expected_length = 65 + + for prefix in prefixes: + if destination.startswith(prefix) and len(destination) == expected_length + len( + prefix + ): + return destination[len(prefix) :] + + return None + + class DeliveryStatus(str, Enum): """Delivery status of a message.""" @@ -387,9 +413,6 @@ async def send_raw( MsgStatus: The delivery status of the message. """ - # Destination without ledger prefix - raw_destination = destination[-65:] - # Check if this message is a reply if ( self._message_received is not None @@ -407,7 +430,7 @@ async def send_raw( return MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid reply", - destination=raw_destination, + destination=destination, endpoint="", ) # Check if this message is a valid interval message @@ -419,36 +442,42 @@ async def send_raw( return MsgStatus( status=DeliveryStatus.FAILED, detail="Invalid interval message", - destination=raw_destination, + destination=destination, endpoint="", ) - # Handle local dispatch of messages - if dispatcher.contains(raw_destination): - await dispatcher.dispatch( - self.address, - raw_destination, - schema_digest, - json_message, - self._session, - ) - return MsgStatus( - status=DeliveryStatus.DELIVERED, - detail="Message dispatched locally", - destination=raw_destination, - endpoint="", - ) + # Destination without ledger prefix + destination_address = extract_agent_address(destination) + + if destination_address is not None: + # Handle local dispatch of messages + if dispatcher.contains(destination_address): + await dispatcher.dispatch( + self.address, + destination_address, + schema_digest, + json_message, + self._session, + ) + return MsgStatus( + status=DeliveryStatus.DELIVERED, + detail="Message dispatched locally", + destination=destination_address, + endpoint="", + ) - # Handle queries waiting for a response - if raw_destination in self._queries: - self._queries[raw_destination].set_result((json_message, schema_digest)) - del self._queries[raw_destination] - return MsgStatus( - status=DeliveryStatus.DELIVERED, - detail="Sync message resolved", - destination=raw_destination, - endpoint="", - ) + # Handle queries waiting for a response + if destination_address in self._queries: + self._queries[destination_address].set_result( + (json_message, schema_digest) + ) + del self._queries[destination_address] + return MsgStatus( + status=DeliveryStatus.DELIVERED, + detail="Sync message resolved", + destination=destination_address, + endpoint="", + ) # Resolve the destination address and endpoint ('destination' can be a name or address) destination_address, endpoints = await self._resolver.resolve(destination) From b7c9155a97d9c0ec12f7b81f2faea401fe72ec11 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Tue, 3 Oct 2023 07:02:21 -0600 Subject: [PATCH 13/26] fix: extract_agent_address --- python/examples/01-first-agent/main.py | 7 ++++ python/src/uagents/context.py | 52 ++++++++------------------ python/src/uagents/resolver.py | 27 ++++++++++++- python/tests/test_agent_address.py | 29 ++++++++++++++ 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index 60737695..468f6f9a 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -1,6 +1,13 @@ from uagents import Agent, Context agent = Agent(name="alice") +a = "agent1blahblahblah" +b = "some-prefix://agent1blahblahblah" +c = "some-prefix://some_agent_name/agent1blahblahblah" + +print(a.split("://")[-1].split("/")[-1]) +print(b.split("://")[-1].split("/")[-1]) +print(c.split("://")[-1].split("/")[-1]) @agent.on_event("startup") diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index 45e1abb6..5fa26546 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -29,14 +29,12 @@ ALMANAC_API_URL, DEFAULT_ENVELOPE_TIMEOUT_SECONDS, DEFAULT_SEARCH_LIMIT, - TESTNET_PREFIX, - MAINNET_PREFIX, ) from uagents.crypto import Identity from uagents.dispatch import JsonStr, dispatcher from uagents.envelope import Envelope from uagents.models import ErrorMessage, Model -from uagents.resolver import Resolver +from uagents.resolver import Resolver, extract_agent_address from uagents.storage import KeyValueStore @@ -48,29 +46,6 @@ EventCallback = Callable[["Context"], Awaitable[None]] -def extract_agent_address(destination: str) -> str: - """ - Extract the agent address from the provided destination. - - Args: - destination (str): The destination address to check and extract. - - Returns: - str: The extracted agent address if valid, or None if not valid. - """ - - prefixes = [TESTNET_PREFIX, MAINNET_PREFIX, ""] - expected_length = 65 - - for prefix in prefixes: - if destination.startswith(prefix) and len(destination) == expected_length + len( - prefix - ): - return destination[len(prefix) :] - - return None - - class DeliveryStatus(str, Enum): """Delivery status of a message.""" @@ -434,17 +409,20 @@ async def send_raw( endpoint="", ) # Check if this message is a valid interval message - if self._message_received is None and self._interval_messages: - if schema_digest not in self._interval_messages: - self._logger.exception( - f"Outgoing message {message_type} is not a valid interval message" - ) - return MsgStatus( - status=DeliveryStatus.FAILED, - detail="Invalid interval message", - destination=destination, - endpoint="", - ) + if ( + self._message_received is None + and self._interval_messages + and schema_digest not in self._interval_messages + ): + self._logger.exception( + f"Outgoing message {message_type} is not a valid interval message" + ) + return MsgStatus( + status=DeliveryStatus.FAILED, + detail="Invalid interval message", + destination=destination, + endpoint="", + ) # Destination without ledger prefix destination_address = extract_agent_address(destination) diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 6eca39f5..2a34b2a6 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -4,12 +4,37 @@ from typing import Dict, List, Optional, Tuple import random -from uagents.config import DEFAULT_MAX_ENDPOINTS, TESTNET_PREFIX, MAINNET_PREFIX +from uagents.config import ( + DEFAULT_MAX_ENDPOINTS, + TESTNET_PREFIX, + MAINNET_PREFIX, + AGENT_PREFIX, +) from uagents.network import get_almanac_contract, get_name_service_contract # pylint: disable=arguments-differ +def extract_agent_address(destination: str) -> str: + """ + Extract the agent address from the provided destination. + + Args: + destination (str): The destination address to check and extract. + + Returns: + str: The extracted agent address if valid, or None if not valid. + """ + + address = destination.split("://")[-1].split("/")[-1] + expected_length = 65 + + if len(address) == expected_length and address.startswith(AGENT_PREFIX): + return address + + return None + + def query_record(agent_address: str, service: str, test: bool) -> dict: """ Query a record from the Almanac contract. diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index c9c29dc2..6f92562a 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -2,6 +2,7 @@ from uagents import Agent from uagents.crypto import Identity +from uagents.resolver import extract_agent_address class TestAgentAdress(unittest.TestCase): @@ -27,6 +28,34 @@ def test_agent_generate(self): self.assertEqual(alice.address[:5] == "agent", True) self.assertEqual(len(alice.address) == 65, True) + def test_extract_valid_address(self): + valid_addresses = [ + "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "some-prefix://agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "some-prefix://some_agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + ] + + for val in valid_addresses: + self.assertEqual( + extract_agent_address(val) + == "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + True, + ) + + def test_extract_invalid_address(self): + invalid_addresses = [ + "other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "some-prefix:agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", + "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/agent_name", + "some-prefix::agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + ] + + for val in invalid_addresses: + self.assertEqual(extract_agent_address(val) == None, True) + if __name__ == "__main__": unittest.main() From fe9740088b7da63a8f2a14986328ea8ced017db9 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Tue, 3 Oct 2023 07:04:32 -0600 Subject: [PATCH 14/26] fix: minor fix --- python/examples/01-first-agent/main.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index 468f6f9a..60737695 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -1,13 +1,6 @@ from uagents import Agent, Context agent = Agent(name="alice") -a = "agent1blahblahblah" -b = "some-prefix://agent1blahblahblah" -c = "some-prefix://some_agent_name/agent1blahblahblah" - -print(a.split("://")[-1].split("/")[-1]) -print(b.split("://")[-1].split("/")[-1]) -print(c.split("://")[-1].split("/")[-1]) @agent.on_event("startup") From 24d1acfe0c540dee28d958e9382fa532b3209d68 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Tue, 3 Oct 2023 07:14:43 -0600 Subject: [PATCH 15/26] fix: pylint --- python/tests/test_agent_address.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index 6f92562a..505adc57 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -33,8 +33,8 @@ def test_extract_valid_address(self): "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "some-prefix://agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "some-prefix://some_agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "prefix://name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] for val in valid_addresses: @@ -49,12 +49,12 @@ def test_extract_invalid_address(self): "other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "some-prefix:agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", - "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/agent_name", + "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/name", "some-prefix::agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] for val in invalid_addresses: - self.assertEqual(extract_agent_address(val) == None, True) + self.assertEqual(extract_agent_address(val) is None, True) if __name__ == "__main__": From 0261661229b5c73188b90b08fa9eb8b9891f53fd Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Tue, 3 Oct 2023 10:49:11 -0600 Subject: [PATCH 16/26] fis: revert fund_agent to original --- python/examples/06-send-tokens/main.py | 4 +-- .../08-local-network-interaction/agent1.py | 2 +- .../08-local-network-interaction/agent2.py | 2 +- .../09-booking-protocol-demo/restaurant.py | 2 +- .../examples/09-booking-protocol-demo/user.py | 2 +- python/examples/10-cleaning-demo/cleaner.py | 2 +- python/examples/10-cleaning-demo/user.py | 2 +- python/examples/11-mailbox-agents/alice.py | 2 +- python/examples/11-mailbox-agents/bob.py | 2 +- python/examples/12-remote-agents/agent1.py | 2 +- python/examples/12-remote-agents/agent2.py | 2 +- .../examples/13-agent-name-service/agent1.py | 4 +-- .../examples/13-agent-name-service/agent2.py | 2 +- python/examples/14-broadcast/main.py | 6 ++--- python/src/uagents/setup.py | 25 ++++++------------- python/tests/test_agent_registration.py | 4 +-- 16 files changed, 28 insertions(+), 37 deletions(-) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index 3da95aaa..0ab63069 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -19,8 +19,8 @@ class TransactionInfo(Model): alice = Agent(name="alice", seed="alice secret phrase") bob = Agent(name="bob", seed="bob secret phrase") -fund_agent_if_low(alice) -fund_agent_if_low(bob) +fund_agent_if_low(alice.wallet.address()) +fund_agent_if_low(bob.wallet.address()) @alice.on_interval(period=10.0) diff --git a/python/examples/08-local-network-interaction/agent1.py b/python/examples/08-local-network-interaction/agent1.py index ed4e95f9..157cb34f 100644 --- a/python/examples/08-local-network-interaction/agent1.py +++ b/python/examples/08-local-network-interaction/agent1.py @@ -16,7 +16,7 @@ class Message(Model): endpoint=["http://127.0.0.1:8001/submit"], ) -fund_agent_if_low(bob) +fund_agent_if_low(bob.wallet.address()) @bob.on_message(model=Message) diff --git a/python/examples/08-local-network-interaction/agent2.py b/python/examples/08-local-network-interaction/agent2.py index c8f9d000..6b6b7a84 100644 --- a/python/examples/08-local-network-interaction/agent2.py +++ b/python/examples/08-local-network-interaction/agent2.py @@ -17,7 +17,7 @@ class Message(Model): endpoint=["http://127.0.0.1:8000/submit"], ) -fund_agent_if_low(alice) +fund_agent_if_low(alice.wallet.address()) @alice.on_interval(period=2.0) diff --git a/python/examples/09-booking-protocol-demo/restaurant.py b/python/examples/09-booking-protocol-demo/restaurant.py index ad37a0b9..b74ca64a 100644 --- a/python/examples/09-booking-protocol-demo/restaurant.py +++ b/python/examples/09-booking-protocol-demo/restaurant.py @@ -15,7 +15,7 @@ }, ) -fund_agent_if_low(restaurant) +fund_agent_if_low(restaurant.wallet.address()) # build the restaurant agent from stock protocols and publish their details restaurant.include(query_proto, publish_manifest=True) diff --git a/python/examples/09-booking-protocol-demo/user.py b/python/examples/09-booking-protocol-demo/user.py index fda06c6a..fc09668a 100644 --- a/python/examples/09-booking-protocol-demo/user.py +++ b/python/examples/09-booking-protocol-demo/user.py @@ -19,7 +19,7 @@ }, ) -fund_agent_if_low(user) +fund_agent_if_low(user.wallet.address()) table_query = QueryTableRequest( guests=3, diff --git a/python/examples/10-cleaning-demo/cleaner.py b/python/examples/10-cleaning-demo/cleaner.py index cd2ce745..5a300c05 100644 --- a/python/examples/10-cleaning-demo/cleaner.py +++ b/python/examples/10-cleaning-demo/cleaner.py @@ -19,7 +19,7 @@ }, ) -fund_agent_if_low(cleaner) +fund_agent_if_low(cleaner.wallet.address()) # build the cleaning service agent from the cleaning protocol diff --git a/python/examples/10-cleaning-demo/user.py b/python/examples/10-cleaning-demo/user.py index 41a4962a..c0bc4cea 100644 --- a/python/examples/10-cleaning-demo/user.py +++ b/python/examples/10-cleaning-demo/user.py @@ -23,7 +23,7 @@ }, ) -fund_agent_if_low(user) +fund_agent_if_low(user.wallet.address()) request = ServiceRequest( user=user.name, diff --git a/python/examples/11-mailbox-agents/alice.py b/python/examples/11-mailbox-agents/alice.py index 160a6d82..a822ec8b 100644 --- a/python/examples/11-mailbox-agents/alice.py +++ b/python/examples/11-mailbox-agents/alice.py @@ -22,7 +22,7 @@ class Message(Model): mailbox=f"{API_KEY}@wss://agentverse.ai", ) -fund_agent_if_low(agent) +fund_agent_if_low(agent.wallet.address()) @agent.on_message(model=Message, replies={Message}) diff --git a/python/examples/11-mailbox-agents/bob.py b/python/examples/11-mailbox-agents/bob.py index 4b48838e..06dd3c0a 100644 --- a/python/examples/11-mailbox-agents/bob.py +++ b/python/examples/11-mailbox-agents/bob.py @@ -25,7 +25,7 @@ class Message(Model): mailbox=f"{API_KEY}@wss://agentverse.ai", ) -fund_agent_if_low(agent) +fund_agent_if_low(agent.wallet.address()) @agent.on_interval(period=2.0) diff --git a/python/examples/12-remote-agents/agent1.py b/python/examples/12-remote-agents/agent1.py index 34359e39..09a4bd02 100644 --- a/python/examples/12-remote-agents/agent1.py +++ b/python/examples/12-remote-agents/agent1.py @@ -29,7 +29,7 @@ class Message(Model): endpoint=[f"{http_tunnel.public_url}/submit"], ) -fund_agent_if_low(alice) +fund_agent_if_low(alice.wallet.address()) @alice.on_message(model=Message) diff --git a/python/examples/12-remote-agents/agent2.py b/python/examples/12-remote-agents/agent2.py index 6b489233..c9661ed7 100644 --- a/python/examples/12-remote-agents/agent2.py +++ b/python/examples/12-remote-agents/agent2.py @@ -16,7 +16,7 @@ class Message(Model): endpoint=["http://127.0.0.1:8001/submit"], ) -fund_agent_if_low(bob) +fund_agent_if_low(bob.wallet.address()) ALICE_ADDRESS = "agent1qv2l7qzcd2g2rcv2p93tqflrcaq5dk7c2xc7fcnfq3s37zgkhxjmq5mfyvz" diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 1dc4eaef..d25e3aab 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -21,14 +21,14 @@ class Message(Model): endpoint=["http://localhost:8001/submit"], ) -fund_agent_if_low(bob) +fund_agent_if_low(bob.wallet.address()) my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") name_service_contract = get_name_service_contract() DOMAIN = "agent" faucet = get_faucet() -ledger = get_ledger(True) +ledger = get_ledger(test=True) WALLET_BALANCE = ledger.query_bank_balance(my_wallet) if WALLET_BALANCE < REGISTRATION_FEE: diff --git a/python/examples/13-agent-name-service/agent2.py b/python/examples/13-agent-name-service/agent2.py index 7fde1832..c10fb882 100644 --- a/python/examples/13-agent-name-service/agent2.py +++ b/python/examples/13-agent-name-service/agent2.py @@ -13,7 +13,7 @@ class Message(Model): endpoint=["http://localhost:8000/submit"], ) -fund_agent_if_low(alice) +fund_agent_if_low(alice.wallet.address()) @alice.on_interval(period=5) diff --git a/python/examples/14-broadcast/main.py b/python/examples/14-broadcast/main.py index 86c30caa..457ce6f9 100644 --- a/python/examples/14-broadcast/main.py +++ b/python/examples/14-broadcast/main.py @@ -8,9 +8,9 @@ bob = Agent(name="bob", seed="bob recovery phrase") charles = Agent(name="charles", seed="charles recovery phrase") -fund_agent_if_low(alice) -fund_agent_if_low(bob) -fund_agent_if_low(charles) +fund_agent_if_low(alice.wallet.address()) +fund_agent_if_low(bob.wallet.address()) +fund_agent_if_low(charles.wallet.address()) class BroadcastExampleRequest(Model): diff --git a/python/src/uagents/setup.py b/python/src/uagents/setup.py index 616e9a0b..44a51ceb 100644 --- a/python/src/uagents/setup.py +++ b/python/src/uagents/setup.py @@ -10,10 +10,9 @@ LOGGER = get_logger("setup") -# pylint: disable=protected-access -def fund_agent_if_low(agent: Agent): +def fund_agent_if_low(wallet_address: str): """ - Checks the agent's wallet balance and adds funds if it's below the registration fee. + Checks the agent's wallet balance and adds testnet funds if it's below the registration fee. Args: wallet_address (str): The wallet address of the agent. @@ -21,26 +20,18 @@ def fund_agent_if_low(agent: Agent): Returns: None """ - ledger = get_ledger(agent._test) + ledger = get_ledger(test=True) faucet = get_faucet() - agent_balance = ledger.query_bank_balance(Address(agent.wallet.address())) - - if not agent._test: - LOGGER.warning( - "Faucet only available for testnet, please add FET tokens to your wallet " - f"{agent.wallet.address()}" - ) - LOGGER.info(f"Current FET balance: {agent_balance}") - return + agent_balance = ledger.query_bank_balance(Address(wallet_address)) if agent_balance < REGISTRATION_FEE: try: - LOGGER.info("Adding funds to agent...") - faucet.get_wealth(agent.wallet.address()) - LOGGER.info("Adding funds to agent...complete") + LOGGER.info("Adding testnet funds to agent...") + faucet.get_wealth(wallet_address) + LOGGER.info("Adding testnet funds to agent...complete") except Exception as ex: - LOGGER.error(f"Failed to add funds to agent: {str(ex)}") + LOGGER.error(f"Failed to add testnet funds to agent: {str(ex)}") def register_agent_with_mailbox(agent: Agent, email: str): diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index c04b3d56..90675a51 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -11,7 +11,7 @@ class TestRegistration(unittest.IsolatedAsyncioTestCase): async def test_almanac_registration(self): agent = Agent(endpoint=["http://localhost:8000/submit"]) - fund_agent_if_low(agent) + fund_agent_if_low(agent.wallet.address()) await agent.register() @@ -48,7 +48,7 @@ async def test_name_service_registration(self): domain = "agent" - fund_agent_if_low(agent) + fund_agent_if_low(agent.wallet.address()) await agent.register() From 6ca7bbfb7760dd7e373f45bee04e7fd2701abc2e Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Tue, 3 Oct 2023 11:27:07 -0600 Subject: [PATCH 17/26] simplify exmaple 13 --- python/examples/13-agent-name-service/agent1.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index d25e3aab..24e6103c 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -1,6 +1,6 @@ from cosmpy.aerial.wallet import LocalWallet -from uagents.network import get_faucet, get_ledger, get_name_service_contract +from uagents.network import get_name_service_contract from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model @@ -21,20 +21,14 @@ class Message(Model): endpoint=["http://localhost:8001/submit"], ) -fund_agent_if_low(bob.wallet.address()) my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") name_service_contract = get_name_service_contract() DOMAIN = "agent" -faucet = get_faucet() -ledger = get_ledger(test=True) -WALLET_BALANCE = ledger.query_bank_balance(my_wallet) -if WALLET_BALANCE < REGISTRATION_FEE: - print("Adding funds to wallet...") - faucet.get_wealth(my_wallet) - print("Adding funds to wallet...complete") +for wallet in [my_wallet, bob.wallet]: + fund_agent_if_low(wallet.address()) @bob.on_event("startup") From f37dceaf16bc775efead22464496147216430f30 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 04:15:44 -0600 Subject: [PATCH 18/26] fix: unused import --- python/examples/13-agent-name-service/agent1.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 24e6103c..592754a9 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -4,8 +4,6 @@ from uagents.setup import fund_agent_if_low from uagents import Agent, Context, Model -from uagents.config import REGISTRATION_FEE - # NOTE: Run agent1.py before running agent2.py From c3160f2fc920d8ff8a918ca7d83ab8f90c00f1d6 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 06:28:51 -0600 Subject: [PATCH 19/26] feat: update name service resolver --- .../examples/13-agent-name-service/agent1.py | 2 +- python/src/uagents/config.py | 3 +++ python/src/uagents/network.py | 18 +++++++++++++----- python/src/uagents/resolver.py | 6 +++--- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/python/examples/13-agent-name-service/agent1.py b/python/examples/13-agent-name-service/agent1.py index 592754a9..b023f9c5 100644 --- a/python/examples/13-agent-name-service/agent1.py +++ b/python/examples/13-agent-name-service/agent1.py @@ -21,7 +21,7 @@ class Message(Model): my_wallet = LocalWallet.from_unsafe_seed("registration test wallet") -name_service_contract = get_name_service_contract() +name_service_contract = get_name_service_contract(test=True) DOMAIN = "agent" diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index c85999fb..6a3fde57 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -22,6 +22,9 @@ CONTRACT_NAME_SERVICE = ( "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" ) +TESTNET_CONTRACT_NAME_SERVICE = ( + "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" +) REGISTRATION_FEE = 500000000000000000 REGISTRATION_DENOM = "atestfet" REGISTRATION_UPDATE_INTERVAL_SECONDS = 3600 diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index 2346f9de..26f1194a 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -23,6 +23,7 @@ CONTRACT_ALMANAC, TESTNET_CONTRACT_ALMANAC, CONTRACT_NAME_SERVICE, + TESTNET_CONTRACT_NAME_SERVICE, AVERAGE_BLOCK_INTERVAL, REGISTRATION_FEE, REGISTRATION_DENOM, @@ -326,7 +327,7 @@ def is_domain_public(self, domain: str): return res["is_public"] def get_registration_tx( - self, name: str, wallet_address: str, agent_address: str, domain: str + self, name: str, wallet_address: str, agent_address: str, domain: str, test: bool ): """ Get the registration transaction for registering a name within a domain. @@ -336,6 +337,7 @@ def get_registration_tx( wallet_address (str): The wallet address initiating the registration. agent_address (str): The address of the agent. domain (str): The domain in which the name is registered. + test (bool): The agent type Returns: Optional[Transaction]: The registration transaction, or None if the name is not @@ -353,10 +355,11 @@ def get_registration_tx( } } + contract = TESTNET_CONTRACT_NAME_SERVICE if test else CONTRACT_NAME_SERVICE transaction = Transaction() transaction.add_message( create_cosmwasm_execute_msg( - wallet_address, CONTRACT_NAME_SERVICE, registration_msg + wallet_address, contract, registration_msg ) ) @@ -398,7 +401,7 @@ async def register( return transaction = self.get_registration_tx( - name, str(wallet.address()), agent_address, domain + name, str(wallet.address()), agent_address, domain, chain_id == "dorado-1", ) if transaction is None: @@ -414,15 +417,20 @@ async def register( _name_service_contract = NameServiceContract( - None, _testnet_ledger, CONTRACT_NAME_SERVICE + None, _ledger, CONTRACT_NAME_SERVICE +) +_testnet_name_service_contract = NameServiceContract( + None, _testnet_ledger, TESTNET_CONTRACT_NAME_SERVICE ) -def get_name_service_contract() -> NameServiceContract: +def get_name_service_contract(test: bool) -> NameServiceContract: """ Get the NameServiceContract instance. Returns: NameServiceContract: The NameServiceContract instance. """ + if test: + return _testnet_name_service_contract return _name_service_contract diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 2a34b2a6..75ce79c9 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -54,7 +54,7 @@ def query_record(agent_address: str, service: str, test: bool) -> dict: return result -def get_agent_address(name: str) -> str: +def get_agent_address(name: str, test: bool) -> str: """ Get the agent address associated with the provided name from the name service contract. @@ -65,7 +65,7 @@ def get_agent_address(name: str) -> str: Optional[str]: The associated agent address if found. """ query_msg = {"domain_record": {"domain": f"{name}"}} - result = get_name_service_contract().query(query_msg) + result = get_name_service_contract(test).query(query_msg) if result["record"] is not None: registered_address = result["record"]["records"][0]["agent_address"]["records"] if len(registered_address) > 0: @@ -210,7 +210,7 @@ async def resolve( Returns: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - address = get_agent_address(destination) + address = get_agent_address(destination, test) if address is not None: return await self._almanac_resolver.resolve(address, test) return None, [] From 96df1d9504dc0f0cbe6a0e13042bf99a4424d63c Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 06:32:16 -0600 Subject: [PATCH 20/26] fix: minor things --- python/examples/01-first-agent/main.py | 2 +- python/examples/02-interval-task/main.py | 2 +- python/examples/05-send-msg/main.py | 2 +- python/src/uagents/network.py | 21 +++++++++++++-------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/python/examples/01-first-agent/main.py b/python/examples/01-first-agent/main.py index 60737695..8b52ac74 100644 --- a/python/examples/01-first-agent/main.py +++ b/python/examples/01-first-agent/main.py @@ -5,7 +5,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}.") + ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.address}.") if __name__ == "__main__": diff --git a/python/examples/02-interval-task/main.py b/python/examples/02-interval-task/main.py index a7d04836..a52cfdd5 100644 --- a/python/examples/02-interval-task/main.py +++ b/python/examples/02-interval-task/main.py @@ -5,7 +5,7 @@ @agent.on_event("startup") async def introduce_agent(ctx: Context): - ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.identifier}.") + ctx.logger.info(f"Hello, I'm agent {ctx.name} and my address is {ctx.address}.") @agent.on_interval(period=2.0) diff --git a/python/examples/05-send-msg/main.py b/python/examples/05-send-msg/main.py index b11e1e61..775a6097 100644 --- a/python/examples/05-send-msg/main.py +++ b/python/examples/05-send-msg/main.py @@ -12,7 +12,7 @@ class Message(Model): @alice.on_interval(period=2.0) async def send_message(ctx: Context): msg = f"Hello there {bob.name} my name is {alice.name}." - await ctx.send(bob.identifier, Message(text=msg)) + await ctx.send(bob.address, Message(text=msg)) @bob.on_message(model=Message) diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index 26f1194a..36703c4f 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -327,7 +327,12 @@ def is_domain_public(self, domain: str): return res["is_public"] def get_registration_tx( - self, name: str, wallet_address: str, agent_address: str, domain: str, test: bool + self, + name: str, + wallet_address: str, + agent_address: str, + domain: str, + test: bool, ): """ Get the registration transaction for registering a name within a domain. @@ -358,9 +363,7 @@ def get_registration_tx( contract = TESTNET_CONTRACT_NAME_SERVICE if test else CONTRACT_NAME_SERVICE transaction = Transaction() transaction.add_message( - create_cosmwasm_execute_msg( - wallet_address, contract, registration_msg - ) + create_cosmwasm_execute_msg(wallet_address, contract, registration_msg) ) return transaction @@ -401,7 +404,11 @@ async def register( return transaction = self.get_registration_tx( - name, str(wallet.address()), agent_address, domain, chain_id == "dorado-1", + name, + str(wallet.address()), + agent_address, + domain, + chain_id == "dorado-1", ) if transaction is None: @@ -416,9 +423,7 @@ async def register( logger.info("Registering name...complete") -_name_service_contract = NameServiceContract( - None, _ledger, CONTRACT_NAME_SERVICE -) +_name_service_contract = NameServiceContract(None, _ledger, CONTRACT_NAME_SERVICE) _testnet_name_service_contract = NameServiceContract( None, _testnet_ledger, TESTNET_CONTRACT_NAME_SERVICE ) From 83418cadb326ebb0e7ac227b182d01a5a11e9f00 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 06:41:30 -0600 Subject: [PATCH 21/26] fix: tests --- python/tests/test_agent_registration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/tests/test_agent_registration.py b/python/tests/test_agent_registration.py index 90675a51..23df6fcc 100644 --- a/python/tests/test_agent_registration.py +++ b/python/tests/test_agent_registration.py @@ -35,7 +35,7 @@ def test_name_service_failed_ownership(self): domain = "agent" - name_service_contract = get_name_service_contract() + name_service_contract = get_name_service_contract(test=True) is_owner = name_service_contract.is_owner( agent.name, domain, str(agent.wallet.address()) @@ -58,7 +58,7 @@ async def test_name_service_registration(self): "Almanac registration failed", ) - name_service_contract = get_name_service_contract() + name_service_contract = get_name_service_contract(test=True) is_name_available = name_service_contract.is_name_available(agent.name, domain) self.assertEqual(is_name_available, True, "Agent name should be available") @@ -80,7 +80,7 @@ async def test_name_service_registration(self): ) self.assertEqual(is_owner, True, "Domain ownership failed") - query_address = get_agent_address(agent.name + "." + domain) + query_address = get_agent_address(agent.name + "." + domain, True) self.assertEqual( query_address == agent.address, True, "Service contract registration failed" From faa7577ffca67e973d2c2340f94258221aadfd13 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 10:36:34 -0600 Subject: [PATCH 22/26] feat: update resolver logic --- python/examples/06-send-tokens/main.py | 4 +- python/examples/07-msg-verification/main.py | 4 +- .../examples/09-booking-protocol-demo/user.py | 4 +- python/examples/10-cleaning-demo/user.py | 4 +- python/src/uagents/config.py | 4 +- python/src/uagents/context.py | 4 +- python/src/uagents/resolver.py | 109 ++++++++++-------- python/tests/test_agent_address.py | 31 +++-- 8 files changed, 88 insertions(+), 76 deletions(-) diff --git a/python/examples/06-send-tokens/main.py b/python/examples/06-send-tokens/main.py index 0ab63069..8988e515 100644 --- a/python/examples/06-send-tokens/main.py +++ b/python/examples/06-send-tokens/main.py @@ -26,7 +26,7 @@ class TransactionInfo(Model): @alice.on_interval(period=10.0) async def request_funds(ctx: Context): await ctx.send( - bob.identifier, + bob.address, PaymentRequest( wallet_address=str(ctx.wallet.address()), amount=AMOUNT, denom=DENOM ), @@ -56,7 +56,7 @@ async def send_payment(ctx: Context, sender: str, msg: PaymentRequest): ) # send the tx hash so alice can confirm - await ctx.send(alice.identifier, TransactionInfo(tx_hash=transaction.tx_hash)) + await ctx.send(alice.address, TransactionInfo(tx_hash=transaction.tx_hash)) bureau = Bureau() diff --git a/python/examples/07-msg-verification/main.py b/python/examples/07-msg-verification/main.py index d317a5b7..397eb0b0 100644 --- a/python/examples/07-msg-verification/main.py +++ b/python/examples/07-msg-verification/main.py @@ -24,7 +24,7 @@ async def send_message(ctx: Context): msg = "Hello there bob." digest = encode(msg) await ctx.send( - bob.identifier, + bob.address, Message(message=msg, digest=digest.hex(), signature=alice.sign_digest(digest)), ) @@ -53,7 +53,7 @@ async def bob_rx_message(ctx: Context, sender: str, msg: Message): # send the response await ctx.send( - alice.identifier, + alice.address, Message(message=msg, digest=digest.hex(), signature=bob.sign_digest(digest)), ) diff --git a/python/examples/09-booking-protocol-demo/user.py b/python/examples/09-booking-protocol-demo/user.py index fc09668a..192ec2f3 100644 --- a/python/examples/09-booking-protocol-demo/user.py +++ b/python/examples/09-booking-protocol-demo/user.py @@ -8,7 +8,9 @@ from uagents.setup import fund_agent_if_low -RESTAURANT_ADDRESS = "agent1qfpqn9jhvp9cg33f27q6jvmuv52dgyg9rfuu37rmxrletlqe7lewwjed5gy" +RESTAURANT_ADDRESS = ( + "test-agent://agent1qfpqn9jhvp9cg33f27q6jvmuv52dgyg9rfuu37rmxrletlqe7lewwjed5gy" +) user = Agent( name="user", diff --git a/python/examples/10-cleaning-demo/user.py b/python/examples/10-cleaning-demo/user.py index c0bc4cea..5c09768e 100644 --- a/python/examples/10-cleaning-demo/user.py +++ b/python/examples/10-cleaning-demo/user.py @@ -12,7 +12,9 @@ from uagents.setup import fund_agent_if_low -CLEANER_ADDRESS = "agent1qdfdx6952trs028fxyug7elgcktam9f896ays6u9art4uaf75hwy2j9m87w" +CLEANER_ADDRESS = ( + "test-agent://agent1qdfdx6952trs028fxyug7elgcktam9f896ays6u9art4uaf75hwy2j9m87w" +) user = Agent( name="user", diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index 6a3fde57..45192cd4 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -12,8 +12,8 @@ AGENT_PREFIX = "agent" LEDGER_PREFIX = "fetch" USER_PREFIX = "user" -TESTNET_PREFIX = "test-agent://" -MAINNET_PREFIX = "agent://" +TESTNET_PREFIX = "test-agent" +MAINNET_PREFIX = "agent" CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" TESTNET_CONTRACT_ALMANAC = ( diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index 5fa26546..73ee4230 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -34,7 +34,7 @@ from uagents.dispatch import JsonStr, dispatcher from uagents.envelope import Envelope from uagents.models import ErrorMessage, Model -from uagents.resolver import Resolver, extract_agent_address +from uagents.resolver import Resolver, split_destination from uagents.storage import KeyValueStore @@ -425,7 +425,7 @@ async def send_raw( ) # Destination without ledger prefix - destination_address = extract_agent_address(destination) + _, destination_address = split_destination(destination) if destination_address is not None: # Handle local dispatch of messages diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index 75ce79c9..e623c866 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -12,27 +12,55 @@ ) from uagents.network import get_almanac_contract, get_name_service_contract -# pylint: disable=arguments-differ +def is_valid_address(address: str) -> bool: + """ + Check if the given string is a valid address. + + Args: + address (str): The address to be checked. -def extract_agent_address(destination: str) -> str: + Returns: + bool: True if the address is valid; False otherwise. """ - Extract the agent address from the provided destination. + return len(address) == 65 and address.startswith(AGENT_PREFIX) + + +def is_valid_prefix(prefix: str) -> bool: + """ + Check if the given string is a valid prefix. Args: - destination (str): The destination address to check and extract. + prefix (str): The prefix to be checked. Returns: - str: The extracted agent address if valid, or None if not valid. + bool: True if the prefix is valid; False otherwise. """ + valid_prefixes = [TESTNET_PREFIX, MAINNET_PREFIX, ""] + return prefix in valid_prefixes - address = destination.split("://")[-1].split("/")[-1] - expected_length = 65 - if len(address) == expected_length and address.startswith(AGENT_PREFIX): - return address +def split_destination(destination: str) -> tuple: + """ + Split a destination string into prefix and remainder. - return None + If the destination contains "://", it splits the prefix and remainder based on that. + If not, it assumes an empty prefix and returns the entire destination as the remainder. + + Args: + destination (str): The destination string to be split. + + Returns: + tuple: A tuple containing the prefix and remainder as strings. + """ + + if "://" in destination: + prefix, remainder = destination.split("://", 1) + remainder = remainder.split("/", 1)[-1] + else: + return "", destination + + return prefix, remainder def query_record(agent_address: str, service: str, test: bool) -> dict: @@ -73,29 +101,6 @@ def get_agent_address(name: str, test: bool) -> str: return None -def is_agent_address(address) -> tuple: - """ - Check if the provided address is a valid agent address. - - Args: - address: The address to check. - - Returns: - bool: True if the address is a valid agent address, False otherwise. - """ - if not isinstance(address, str): - return False - - prefixes = [TESTNET_PREFIX, MAINNET_PREFIX, ""] - expected_length = 65 - - for prefix in prefixes: - if address.startswith(prefix) and len(address) == expected_length + len(prefix): - return (True, prefix) - - return (False, None) - - class Resolver(ABC): @abstractmethod # pylint: disable=unnecessary-pass @@ -136,14 +141,18 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Returns: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - is_address, prefix = is_agent_address(destination) - if is_address: - return await self._almanc_resolver.resolve( - destination[len(prefix) :], not prefix == MAINNET_PREFIX + + prefix, remainder = split_destination(destination) + + if is_valid_prefix(prefix): + resolver = ( + self._almanc_resolver + if is_valid_address(remainder) + else self._name_service_resolver ) - return await self._name_service_resolver.resolve( - destination, not prefix == MAINNET_PREFIX - ) + return await resolver.resolve(destination) + + return None, [] class AlmanacResolver(Resolver): @@ -156,9 +165,7 @@ def __init__(self, max_endpoints: Optional[int] = None): """ self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS - async def resolve( - self, destination: str, test: bool - ) -> Tuple[Optional[str], List[str]]: + async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the Almanac contract. @@ -168,7 +175,9 @@ async def resolve( Returns: Tuple[str, List[str]]: The address and resolved endpoints. """ - result = query_record(destination, "service", test) + prefix, address = split_destination(destination) + is_testnet = prefix != MAINNET_PREFIX + result = query_record(address, "service", is_testnet) if result is not None: record = result.get("record") or {} endpoint_list = ( @@ -178,7 +187,7 @@ async def resolve( if len(endpoint_list) > 0: endpoints = [val.get("url") for val in endpoint_list] weights = [val.get("weight") for val in endpoint_list] - return destination, random.choices( + return address, random.choices( endpoints, weights=weights, k=min(self._max_endpoints, len(endpoints)), @@ -198,9 +207,7 @@ def __init__(self, max_endpoints: Optional[int] = None): self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS self._almanac_resolver = AlmanacResolver(max_endpoints=self._max_endpoints) - async def resolve( - self, destination: str, test: bool - ) -> Tuple[Optional[str], List[str]]: + async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the NameService contract. @@ -210,9 +217,11 @@ async def resolve( Returns: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - address = get_agent_address(destination, test) + prefix, name = split_destination(destination) + is_testnet = prefix != MAINNET_PREFIX + address = get_agent_address(name, is_testnet) if address is not None: - return await self._almanac_resolver.resolve(address, test) + return await self._almanac_resolver.resolve(address) return None, [] diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index 505adc57..be469398 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -2,7 +2,7 @@ from uagents import Agent from uagents.crypto import Identity -from uagents.resolver import extract_agent_address +from uagents.resolver import split_destination, is_valid_address, is_valid_prefix class TestAgentAdress(unittest.TestCase): @@ -31,30 +31,29 @@ def test_agent_generate(self): def test_extract_valid_address(self): valid_addresses = [ "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "prefix://name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "agent_name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "test-agent://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "agent://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "test-agent://name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] for val in valid_addresses: - self.assertEqual( - extract_agent_address(val) - == "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - True, - ) + prefix, address = split_destination(val) + self.assertEqual(is_valid_address(address),True,) + self.assertEqual(is_valid_prefix(prefix),True,) def test_extract_invalid_address(self): invalid_addresses = [ - "other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "some-prefix:agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", - "other-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", - "some-prefix://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/name", - "some-prefix::agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "p://other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "prefix://myagent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", + "other-prefix://address1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", + "some-prefix://name/alice1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/name", + "some-prefix://bobqfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] for val in invalid_addresses: - self.assertEqual(extract_agent_address(val) is None, True) + prefix, address = split_destination(val) + self.assertEqual(is_valid_address(address), False) + self.assertEqual(is_valid_prefix(prefix), False) if __name__ == "__main__": From 1a2bf8c1286562b6647a025fd0a7936c7295d6c1 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 10:38:50 -0600 Subject: [PATCH 23/26] run black --- python/tests/test_agent_address.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index be469398..46921576 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -38,8 +38,14 @@ def test_extract_valid_address(self): for val in valid_addresses: prefix, address = split_destination(val) - self.assertEqual(is_valid_address(address),True,) - self.assertEqual(is_valid_prefix(prefix),True,) + self.assertEqual( + is_valid_address(address), + True, + ) + self.assertEqual( + is_valid_prefix(prefix), + True, + ) def test_extract_invalid_address(self): invalid_addresses = [ From 830e85c4a46bd9d1755ee952173b88ede93c9149 Mon Sep 17 00:00:00 2001 From: Alejandro-Morales Date: Wed, 4 Oct 2023 10:41:11 -0600 Subject: [PATCH 24/26] run pylint --- python/tests/test_agent_address.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index 46921576..74dae8a5 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -52,7 +52,7 @@ def test_extract_invalid_address(self): "p://other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "prefix://myagent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", "other-prefix://address1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skes", - "some-prefix://name/alice1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/name", + "prefix://name/alice1qfl32tdwlyjatc7f9t6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess/name", "some-prefix://bobqfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] From 23fe6f888a4e6e9a907c2e47a217eec8df195813 Mon Sep 17 00:00:00 2001 From: James Riehl Date: Thu, 5 Oct 2023 17:58:24 +0100 Subject: [PATCH 25/26] chore: update identifier parsing function and add name test --- python/src/uagents/config.py | 8 +++-- python/src/uagents/context.py | 8 ++--- python/src/uagents/network.py | 45 +++++++++++++++++---------- python/src/uagents/resolver.py | 49 ++++++++++++++++-------------- python/tests/test_agent_address.py | 28 +++++++++++++++-- 5 files changed, 89 insertions(+), 49 deletions(-) diff --git a/python/src/uagents/config.py b/python/src/uagents/config.py index 45192cd4..042f730a 100644 --- a/python/src/uagents/config.py +++ b/python/src/uagents/config.py @@ -15,12 +15,14 @@ TESTNET_PREFIX = "test-agent" MAINNET_PREFIX = "agent" -CONTRACT_ALMANAC = "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" +MAINNET_CONTRACT_ALMANAC = ( + "fetch1mezzhfj7qgveewzwzdk6lz5sae4dunpmmsjr9u7z0tpmdsae8zmquq3y0y" +) TESTNET_CONTRACT_ALMANAC = ( "fetch1tjagw8g8nn4cwuw00cf0m5tl4l6wfw9c0ue507fhx9e3yrsck8zs0l3q4w" ) -CONTRACT_NAME_SERVICE = ( - "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" +MAINNET_CONTRACT_NAME_SERVICE = ( + "fetch1479lwv5vy8skute5cycuz727e55spkhxut0valrcm38x9caa2x8q99ef0q" ) TESTNET_CONTRACT_NAME_SERVICE = ( "fetch1mxz8kn3l5ksaftx8a9pj9a6prpzk2uhxnqdkwuqvuh37tw80xu6qges77l" diff --git a/python/src/uagents/context.py b/python/src/uagents/context.py index 73ee4230..1b302f9e 100644 --- a/python/src/uagents/context.py +++ b/python/src/uagents/context.py @@ -34,7 +34,7 @@ from uagents.dispatch import JsonStr, dispatcher from uagents.envelope import Envelope from uagents.models import ErrorMessage, Model -from uagents.resolver import Resolver, split_destination +from uagents.resolver import Resolver, parse_identifier from uagents.storage import KeyValueStore @@ -424,10 +424,10 @@ async def send_raw( endpoint="", ) - # Destination without ledger prefix - _, destination_address = split_destination(destination) + # Extract address from destination agent identifier if present + _, _, destination_address = parse_identifier(destination) - if destination_address is not None: + if destination_address: # Handle local dispatch of messages if dispatcher.contains(destination_address): await dispatcher.dispatch( diff --git a/python/src/uagents/network.py b/python/src/uagents/network.py index 36703c4f..887892b1 100644 --- a/python/src/uagents/network.py +++ b/python/src/uagents/network.py @@ -20,9 +20,9 @@ from cosmpy.aerial.wallet import LocalWallet from uagents.config import ( - CONTRACT_ALMANAC, + MAINNET_CONTRACT_ALMANAC, TESTNET_CONTRACT_ALMANAC, - CONTRACT_NAME_SERVICE, + MAINNET_CONTRACT_NAME_SERVICE, TESTNET_CONTRACT_NAME_SERVICE, AVERAGE_BLOCK_INTERVAL, REGISTRATION_FEE, @@ -36,21 +36,22 @@ _faucet_api = FaucetApi(NetworkConfig.fetchai_stable_testnet()) _testnet_ledger = LedgerClient(NetworkConfig.fetchai_stable_testnet()) -_ledger = LedgerClient( - NetworkConfig.fetchai_stable_testnet() -) # LedgerClient(NetworkConfig.fetchai_mainnet()) +_mainnet_ledger = LedgerClient(NetworkConfig.fetchai_mainnet()) -def get_ledger(test: bool) -> LedgerClient: +def get_ledger(test: bool = True) -> LedgerClient: """ Get the Ledger client. + Args: + test (bool): Whether to use the testnet or mainnet. Defaults to True. + Returns: LedgerClient: The Ledger client instance. """ if test: return _testnet_ledger - return _ledger + return _mainnet_ledger def get_faucet() -> FaucetApi: @@ -74,10 +75,10 @@ async def wait_for_tx_to_complete( Args: tx_hash (str): The hash of the transaction to monitor. - timeout (Optional[timedelta], optional): The maximum time to wait for + ledger (LedgerClient): The Ledger client to poll. + timeout (Optional[timedelta], optional): The maximum time to wait. the transaction to complete. Defaults to None. poll_period (Optional[timedelta], optional): The time interval to poll - the Ledger for the transaction status. Defaults to None. Returns: TxResponse: The response object containing the transaction details. @@ -250,22 +251,27 @@ def get_sequence(self, address: str) -> int: return sequence -_almanac_contract = AlmanacContract(None, _ledger, CONTRACT_ALMANAC) +_mainnet_almanac_contract = AlmanacContract( + None, _mainnet_ledger, MAINNET_CONTRACT_ALMANAC +) _testnet_almanac_contract = AlmanacContract( None, _testnet_ledger, TESTNET_CONTRACT_ALMANAC ) -def get_almanac_contract(test: bool) -> AlmanacContract: +def get_almanac_contract(test: bool = True) -> AlmanacContract: """ Get the AlmanacContract instance. + Args: + test (bool): Whether to use the testnet or mainnet. Defaults to True. + Returns: AlmanacContract: The AlmanacContract instance. """ if test: return _testnet_almanac_contract - return _almanac_contract + return _mainnet_almanac_contract class NameServiceContract(LedgerContract): @@ -360,7 +366,9 @@ def get_registration_tx( } } - contract = TESTNET_CONTRACT_NAME_SERVICE if test else CONTRACT_NAME_SERVICE + contract = ( + TESTNET_CONTRACT_NAME_SERVICE if test else MAINNET_CONTRACT_NAME_SERVICE + ) transaction = Transaction() transaction.add_message( create_cosmwasm_execute_msg(wallet_address, contract, registration_msg) @@ -423,19 +431,24 @@ async def register( logger.info("Registering name...complete") -_name_service_contract = NameServiceContract(None, _ledger, CONTRACT_NAME_SERVICE) +_mainnet_name_service_contract = NameServiceContract( + None, _mainnet_ledger, MAINNET_CONTRACT_NAME_SERVICE +) _testnet_name_service_contract = NameServiceContract( None, _testnet_ledger, TESTNET_CONTRACT_NAME_SERVICE ) -def get_name_service_contract(test: bool) -> NameServiceContract: +def get_name_service_contract(test: bool = True) -> NameServiceContract: """ Get the NameServiceContract instance. + Args: + test (bool): Whether to use the testnet or mainnet. Defaults to True. + Returns: NameServiceContract: The NameServiceContract instance. """ if test: return _testnet_name_service_contract - return _name_service_contract + return _mainnet_name_service_contract diff --git a/python/src/uagents/resolver.py b/python/src/uagents/resolver.py index e623c866..16d4a602 100644 --- a/python/src/uagents/resolver.py +++ b/python/src/uagents/resolver.py @@ -40,27 +40,33 @@ def is_valid_prefix(prefix: str) -> bool: return prefix in valid_prefixes -def split_destination(destination: str) -> tuple: +def parse_identifier(identifier: str) -> Tuple[str, str, str]: """ - Split a destination string into prefix and remainder. - - If the destination contains "://", it splits the prefix and remainder based on that. - If not, it assumes an empty prefix and returns the entire destination as the remainder. + Parse an agent identifier string into prefix, name, and address. Args: - destination (str): The destination string to be split. + identifier (str): The identifier string to be parsed. Returns: - tuple: A tuple containing the prefix and remainder as strings. + Tuple[str, str, str]: A tuple containing the prefix, name, and address as strings. """ - if "://" in destination: - prefix, remainder = destination.split("://", 1) - remainder = remainder.split("/", 1)[-1] + prefix = "" + name = "" + address = "" + + if "://" in identifier: + prefix, identifier = identifier.split("://", 1) + + if "/" in identifier: + name, identifier = identifier.split("/", 1) + + if is_valid_address(identifier): + address = identifier else: - return "", destination + name = identifier - return prefix, remainder + return prefix, name, address def query_record(agent_address: str, service: str, test: bool) -> dict: @@ -88,6 +94,7 @@ def get_agent_address(name: str, test: bool) -> str: Args: name (str): The name to query. + test (bool): Whether to use the testnet or mainnet contract. Returns: Optional[str]: The associated agent address if found. @@ -142,14 +149,10 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - prefix, remainder = split_destination(destination) + prefix, _, address = parse_identifier(destination) if is_valid_prefix(prefix): - resolver = ( - self._almanc_resolver - if is_valid_address(remainder) - else self._name_service_resolver - ) + resolver = self._almanc_resolver if address else self._name_service_resolver return await resolver.resolve(destination) return None, [] @@ -175,7 +178,7 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Returns: Tuple[str, List[str]]: The address and resolved endpoints. """ - prefix, address = split_destination(destination) + prefix, _, address = parse_identifier(destination) is_testnet = prefix != MAINNET_PREFIX result = query_record(address, "service", is_testnet) if result is not None: @@ -217,9 +220,9 @@ async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: Returns: Tuple[Optional[str], List[str]]: The address (if available) and resolved endpoints. """ - prefix, name = split_destination(destination) - is_testnet = prefix != MAINNET_PREFIX - address = get_agent_address(name, is_testnet) + prefix, name, _ = parse_identifier(destination) + use_testnet = prefix != MAINNET_PREFIX + address = get_agent_address(name, use_testnet) if address is not None: return await self._almanac_resolver.resolve(address) return None, [] @@ -239,7 +242,7 @@ def __init__( self._rules = rules self._max_endpoints = max_endpoints or DEFAULT_MAX_ENDPOINTS - async def resolve(self, destination: str) -> Optional[str]: + async def resolve(self, destination: str) -> Tuple[Optional[str], List[str]]: """ Resolve the destination using the provided rules. diff --git a/python/tests/test_agent_address.py b/python/tests/test_agent_address.py index 74dae8a5..c6664430 100644 --- a/python/tests/test_agent_address.py +++ b/python/tests/test_agent_address.py @@ -2,7 +2,7 @@ from uagents import Agent from uagents.crypto import Identity -from uagents.resolver import split_destination, is_valid_address, is_valid_prefix +from uagents.resolver import parse_identifier, is_valid_address, is_valid_prefix class TestAgentAdress(unittest.TestCase): @@ -34,19 +34,41 @@ def test_extract_valid_address(self): "test-agent://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "agent://agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", "test-agent://name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "name/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", ] for val in valid_addresses: - prefix, address = split_destination(val) + prefix, name, address = parse_identifier(val) self.assertEqual( is_valid_address(address), True, ) + self.assertIn(name, {"name", ""}) self.assertEqual( is_valid_prefix(prefix), True, ) + def test_extract_valid_name(self): + valid_names = [ + "name.domain", + "test-agent://name.domain", + "agent://name.domain", + "agent://name.domain/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "name.domain/agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + ] + for val in valid_names: + prefix, name, address = parse_identifier(val) + self.assertEqual(name, "name.domain") + self.assertIn( + address, + { + "agent1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", + "", + }, + ) + self.assertEqual(is_valid_prefix(prefix), True) + def test_extract_invalid_address(self): invalid_addresses = [ "p://other1qfl32tdwlyjatc7f9tjng6sm9y7yzapy6awx4h9rrwenputzmnv5g6skess", @@ -57,7 +79,7 @@ def test_extract_invalid_address(self): ] for val in invalid_addresses: - prefix, address = split_destination(val) + prefix, _, address = parse_identifier(val) self.assertEqual(is_valid_address(address), False) self.assertEqual(is_valid_prefix(prefix), False) From d303b64f6012c84dce354611fae69dffb0d46de0 Mon Sep 17 00:00:00 2001 From: James Riehl Date: Fri, 6 Oct 2023 09:38:54 +0100 Subject: [PATCH 26/26] chore: update comments --- python/src/uagents/agent.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/src/uagents/agent.py b/python/src/uagents/agent.py index f0efd16d..972b6795 100644 --- a/python/src/uagents/agent.py +++ b/python/src/uagents/agent.py @@ -128,10 +128,12 @@ class Agent(Sink): protocols (Dict[str, Protocol]): Dictionary mapping all supported protocol digests to their corresponding protocols. _ctx (Context): The context for agent interactions. + _test (bool): True if the agent will register and transact on the testnet. Properties: name (str): The name of the agent. address (str): The address of the agent used for communication. + identifier (str): The Agent Identifier, including network prefix and address. wallet (LocalWallet): The agent's wallet for transacting on the ledger. storage (KeyValueStore): The key-value store for storage operations. mailbox (Dict[str, str]): The mailbox configuration for the agent (deprecated and replaced @@ -146,7 +148,6 @@ class Agent(Sink): def __init__( self, name: Optional[str] = None, - test: Optional[bool] = True, port: Optional[int] = None, seed: Optional[str] = None, endpoint: Optional[Union[str, List[str], Dict[str, dict]]] = None, @@ -155,6 +156,7 @@ def __init__( resolve: Optional[Resolver] = None, max_resolver_endpoints: Optional[int] = None, version: Optional[str] = None, + test: Optional[bool] = True, ): """ Initialize an Agent instance. @@ -171,7 +173,6 @@ def __init__( version (Optional[str]): The version of the agent. """ self._name = name - self._test = test self._port = port if port is not None else 8000 self._background_tasks: Set[asyncio.Task] = set() self._resolver = ( @@ -215,8 +216,8 @@ def __init__( else: self._mailbox_client = None - self._ledger = get_ledger(self._test) - self._almanac_contract = get_almanac_contract(self._test) + self._ledger = get_ledger(test) + self._almanac_contract = get_almanac_contract(test) self._storage = KeyValueStore(self.address[0:16]) self._interval_handlers: List[Tuple[IntervalCallback, float]] = [] self._interval_messages: Set[str] = set() @@ -229,6 +230,7 @@ def __init__( self._message_queue = asyncio.Queue() self._on_startup = [] self._on_shutdown = [] + self._test = test self._version = version or "0.1.0" # initialize the internal agent protocol @@ -317,10 +319,10 @@ def address(self) -> str: @property def identifier(self) -> str: """ - Get the address of the agent used for communication including the network prefix. + Get the Agent Identifier, including network prefix and address. Returns: - str: The agent's address and network prefix. + str: The agent's identifier. """ prefix = TESTNET_PREFIX if self._test else MAINNET_PREFIX return prefix + self._identity.address