def _handle_transaction_digest( self, ledger_api_msg: LedgerApiMessage, ledger_api_dialogue: LedgerApiDialogue) -> None: """ Handle a message of transaction_digest performative. :param ledger_api_message: the ledger api message :param ledger_api_dialogue: the ledger api dialogue """ self.context.logger.info( "[{}]: transaction was successfully submitted. Transaction digest={}" .format(self.context.agent_name, ledger_api_msg.transaction_digest)) msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT, message_id=ledger_api_msg.message_id + 1, dialogue_reference=ledger_api_dialogue.dialogue_label. dialogue_reference, target=ledger_api_msg.message_id, transaction_digest=ledger_api_msg.transaction_digest, ) msg.counterparty = ledger_api_msg.counterparty ledger_api_dialogue.update(msg) self.context.outbox.put_message(message=msg) self.context.logger.info( "[{}]: requesting transaction receipt.".format( self.context.agent_name))
def get_balance( self, api: LedgerApi, message: LedgerApiMessage, dialogue: LedgerApiDialogue, ) -> LedgerApiMessage: """ Send the request 'get_balance'. :param api: the API object. :param message: the Ledger API message :return: None """ balance = api.get_balance(message.address) if balance is None: response = self.get_error_message( ValueError("No balance returned"), api, message, dialogue ) else: response = LedgerApiMessage( performative=LedgerApiMessage.Performative.BALANCE, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, balance=balance, ledger_id=message.ledger_id, ) response.counterparty = message.counterparty dialogue.update(response) return response
def test_send_signed_transaction_serialization(): """Test the serialization for 'send_signed_transaction' speech-act works.""" msg = LedgerApiMessage( message_id=2, target=1, performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, signed_transaction=LedgerApiMessage.SignedTransaction( "some_ledger_id", b"some_body"), ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=LedgerApiMessage.protocol_id, message=msg, ) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope.to == actual_envelope.to assert expected_envelope.sender == actual_envelope.sender assert expected_envelope.protocol_id == actual_envelope.protocol_id assert expected_envelope.message != actual_envelope.message actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message) actual_msg.to = actual_envelope.to actual_msg.sender = actual_envelope.sender expected_msg = msg assert expected_msg == actual_msg
def send_signed_transaction( self, api: LedgerApi, message: LedgerApiMessage, dialogue: LedgerApiDialogue, ) -> LedgerApiMessage: """ Send the request 'send_signed_tx'. :param api: the API object. :param message: the Ledger API message :return: None """ transaction_digest = api.send_signed_transaction( message.signed_transaction.body ) if transaction_digest is None: # pragma: nocover response = self.get_error_message( ValueError("No transaction_digest returned"), api, message, dialogue ) else: response = LedgerApiMessage( performative=LedgerApiMessage.Performative.TRANSACTION_DIGEST, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, transaction_digest=TransactionDigest( message.signed_transaction.ledger_id, transaction_digest ), ) response.counterparty = message.counterparty dialogue.update(response) return response
def test_error_serialization(): """Test the serialization for 'error' speech-act works.""" msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.ERROR, code=7, message="some_error_message", data=b"some_error_data", ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=LedgerApiMessage.protocol_id, message=msg, ) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope.to == actual_envelope.to assert expected_envelope.sender == actual_envelope.sender assert expected_envelope.protocol_id == actual_envelope.protocol_id assert expected_envelope.message != actual_envelope.message actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message) actual_msg.to = actual_envelope.to actual_msg.sender = actual_envelope.sender expected_msg = msg assert expected_msg == actual_msg
def get_error_message( self, e: Exception, api: LedgerApi, message: Message, dialogue: BaseDialogue, ) -> LedgerApiMessage: """ Build an error message. :param e: the exception. :param api: the Ledger API. :param message: the request message. :return: an error message response. """ message = cast(LedgerApiMessage, message) dialogue = cast(LedgerApiDialogue, dialogue) response = LedgerApiMessage( performative=LedgerApiMessage.Performative.ERROR, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, code=500, message=str(e), data=b"", ) response.counterparty = message.counterparty dialogue.update(response) return response
def get_raw_transaction( self, api: LedgerApi, message: LedgerApiMessage, dialogue: LedgerApiDialogue, ) -> LedgerApiMessage: """ Send the request 'get_raw_transaction'. :param api: the API object. :param message: the Ledger API message :return: None """ raw_transaction = api.get_transfer_transaction( sender_address=message.terms.sender_address, destination_address=message.terms.counterparty_address, amount=message.terms.sender_payable_amount, tx_fee=message.terms.fee, tx_nonce=message.terms.nonce, **message.terms.kwargs, ) if raw_transaction is None: response = self.get_error_message( ValueError("No raw transaction returned"), api, message, dialogue ) else: response = LedgerApiMessage( performative=LedgerApiMessage.Performative.RAW_TRANSACTION, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, raw_transaction=RawTransaction( message.terms.ledger_id, raw_transaction ), ) response.counterparty = message.counterparty dialogue.update(response) return response
def _handle_signed_transaction(self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue) -> None: """ Handle an oef search message. :param signing_msg: the signing message :param signing_dialogue: the dialogue :return: None """ self.context.logger.info("transaction signing was successful.") fipa_dialogue = signing_dialogue.associated_fipa_dialogue ledger_api_dialogue = fipa_dialogue.associated_ledger_api_dialogue last_ledger_api_msg = ledger_api_dialogue.last_incoming_message assert (last_ledger_api_msg is not None ), "Could not retrieve last message in ledger api dialogue" ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, dialogue_reference=ledger_api_dialogue.dialogue_label. dialogue_reference, target=last_ledger_api_msg.message_id, message_id=last_ledger_api_msg.message_id + 1, signed_transaction=signing_msg.signed_transaction, ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogue.update(ledger_api_msg) self.context.outbox.put_message(message=ledger_api_msg) self.context.logger.info("sending transaction to ledger.")
def test_get_balance_serialization(): """Test the serialization for 'get_balance' speech-act works.""" msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, ledger_id="some_ledger_id", address="some_address", ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=LedgerApiMessage.protocol_id, message=msg, ) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope.to == actual_envelope.to assert expected_envelope.sender == actual_envelope.sender assert expected_envelope.protocol_id == actual_envelope.protocol_id assert expected_envelope.message != actual_envelope.message actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message) actual_msg.to = actual_envelope.to actual_msg.sender = actual_envelope.sender expected_msg = msg assert expected_msg == actual_msg
async def test_no_raw_tx(): """Test no raw tx returned.""" dispatcher = LedgerApiRequestDispatcher(ConnectionStatus()) mock_api = Mock() contract_api_dialogues = ContractApiDialogues() message = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION, dialogue_reference=contract_api_dialogues. new_self_initiated_dialogue_reference(), terms=Terms( ledger_id=EthereumCrypto.identifier, sender_address="1111", counterparty_address="22222", amount_by_currency_id={"ETH": -1}, quantities_by_good_id={"some_service_id": 1}, is_sender_payable_tx_fee=True, nonce="", fee_by_currency_id={"ETH": 10}, chain_id=3, ), ) message.counterparty = "test" dialogue = contract_api_dialogues.update(message) mock_api.get_transfer_transaction.return_value = None msg = dispatcher.get_raw_transaction(mock_api, message, dialogue) assert msg.performative == LedgerApiMessage.Performative.ERROR
def test_transaction_receipt_serialization(): """Test the serialization for 'transaction_receipt' speech-act works.""" msg = LedgerApiMessage( message_id=2, target=1, performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT, transaction_receipt=LedgerApiMessage.TransactionReceipt( "some_ledger_id", b"some_receit", b"some_transaction"), ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=LedgerApiMessage.protocol_id, message=msg, ) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope.to == actual_envelope.to assert expected_envelope.sender == actual_envelope.sender assert expected_envelope.protocol_id == actual_envelope.protocol_id assert expected_envelope.message != actual_envelope.message actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message) actual_msg.to = actual_envelope.to actual_msg.sender = actual_envelope.sender expected_msg = msg assert expected_msg == actual_msg
def _handle_signed_transaction(self, signing_msg: SigningMessage, signing_dialogue: SigningDialogue) -> None: """ Handle an oef search message. :param signing_msg: the signing message :param signing_dialogue: the dialogue :return: None """ self.context.logger.info( "[{}]: transaction signing was successful.".format( self.context.agent_name)) ledger_api_dialogues = cast(LedgerApiDialogues, self.context.ledger_api_dialogues) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), signed_transaction=signing_msg.signed_transaction, ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogue = cast(Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)) assert ledger_api_dialogue is not None, "Error when creating signing dialogue." ledger_api_dialogue.associated_signing_dialogue = signing_dialogue self.context.outbox.put_message(message=ledger_api_msg) self.context.logger.info("[{}]: sending transaction to ledger.".format( self.context.agent_name))
def get_transaction_receipt( self, api: LedgerApi, message: LedgerApiMessage, dialogue: LedgerApiDialogue, ) -> LedgerApiMessage: """ Send the request 'get_transaction_receipt'. :param api: the API object. :param message: the Ledger API message :return: None """ is_settled = False attempts = 0 while (not is_settled and attempts < self.MAX_ATTEMPTS and self.connection_state.get() == ConnectionStates.connected): time.sleep(self.TIMEOUT) transaction_receipt = api.get_transaction_receipt( message.transaction_digest.body) is_settled = api.is_transaction_settled(transaction_receipt) attempts += 1 attempts = 0 transaction = api.get_transaction(message.transaction_digest.body) while (transaction is None and attempts < self.MAX_ATTEMPTS and self.connection_state.get() == ConnectionStates.connected): time.sleep(self.TIMEOUT) transaction = api.get_transaction(message.transaction_digest.body) attempts += 1 if not is_settled: # pragma: nocover response = self.get_error_message( ValueError("Transaction not settled within timeout"), api, message, dialogue, ) elif transaction_receipt is None: # pragma: nocover response = self.get_error_message( ValueError("No transaction_receipt returned"), api, message, dialogue) elif transaction is None: # pragma: nocover response = self.get_error_message(ValueError("No tx returned"), api, message, dialogue) else: response = LedgerApiMessage( performative=LedgerApiMessage.Performative.TRANSACTION_RECEIPT, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, transaction_receipt=TransactionReceipt( message.transaction_digest.ledger_id, transaction_receipt, transaction, ), ) response.counterparty = message.counterparty dialogue.update(response) return response
def _handle_match_accept( self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue ) -> None: """ Handle the match accept. :param fipa_msg: the message :param fipa_dialogue: the dialogue object :return: None """ self.context.logger.info( "received MATCH_ACCEPT_W_INFORM from sender={} with info={}".format( fipa_msg.counterparty[-5:], fipa_msg.info ) ) strategy = cast(GenericStrategy, self.context.strategy) if strategy.is_ledger_tx: transfer_address = fipa_msg.info.get("address", None) if transfer_address is not None and isinstance(transfer_address, str): fipa_dialogue.terms.counterparty_address = transfer_address ledger_api_dialogues = cast( LedgerApiDialogues, self.context.ledger_api_dialogues ) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION, dialogue_reference=ledger_api_dialogues.new_self_initiated_dialogue_reference(), terms=fipa_dialogue.terms, ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogue = cast( Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg) ) assert ( ledger_api_dialogue is not None ), "Error when creating ledger api dialogue." ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue fipa_dialogue.associated_ledger_api_dialogue = ledger_api_dialogue self.context.outbox.put_message(message=ledger_api_msg) self.context.logger.info( "requesting transfer transaction from ledger api..." ) else: inform_msg = FipaMessage( message_id=fipa_msg.message_id + 1, dialogue_reference=fipa_dialogue.dialogue_label.dialogue_reference, target=fipa_msg.message_id, performative=FipaMessage.Performative.INFORM, info={"Done": "Sending payment via bank transfer"}, ) inform_msg.counterparty = fipa_msg.counterparty fipa_dialogue.update(inform_msg) self.context.outbox.put_message(message=inform_msg) self.context.logger.info( "informing counterparty={} of payment.".format( fipa_msg.counterparty[-5:] ) )
def setup(self) -> None: """Implement the setup for the behaviour.""" strategy = cast(Strategy, self.context.strategy) ledger_api_dialogues = cast( LedgerApiDialogues, self.context.ledger_api_dialogues ) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=ledger_api_dialogues.new_self_initiated_dialogue_reference(), ledger_id=strategy.ledger_id, address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)), ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogues.update(ledger_api_msg) self.context.outbox.put_message(message=ledger_api_msg)
async def test_no_balance(): """Test no balance.""" dispatcher = LedgerApiRequestDispatcher(AsyncState()) mock_api = Mock() message = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=dispatcher.dialogues. new_self_initiated_dialogue_reference(), ledger_id=ETHEREUM, address="test", ) message.counterparty = "test" dialogue = dispatcher.dialogues.update(message) mock_api.get_balance.return_value = None msg = dispatcher.get_balance(mock_api, message, dialogue) assert msg.performative == LedgerApiMessage.Performative.ERROR
async def test_no_balance(): """Test no balance.""" dispatcher = LedgerApiRequestDispatcher(ConnectionStatus()) mock_api = Mock() contract_api_dialogues = ContractApiDialogues() message = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=contract_api_dialogues. new_self_initiated_dialogue_reference(), ledger_id=EthereumCrypto.identifier, address="test", ) message.counterparty = "test" dialogue = contract_api_dialogues.update(message) mock_api.get_balance.return_value = None msg = dispatcher.get_balance(mock_api, message, dialogue) assert msg.performative == LedgerApiMessage.Performative.ERROR
def test_incorrect_message(mocked_enforce): """Test that we raise an exception when the message is incorrect.""" with mock.patch.object(ledger_api_message_logger, "error") as mock_logger: LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, ledger_id="some_ledger_id", address="some_address", ) mock_logger.assert_any_call("some error")
def test_get_raw_transaction_serialization(): """Test the serialization for 'get_raw_transaction' speech-act works.""" terms_arg = LedgerApiMessage.Terms( ledger_id="some_ledger_id", sender_address="some_sender_address", counterparty_address="some_counterparty_address", amount_by_currency_id={"currency_id_1": 1}, quantities_by_good_id={ "good_id_1": -1, "good_id_2": -2 }, nonce="some_nonce", is_sender_payable_tx_fee=False, fee_by_currency_id={"currency_id_1": 1}, is_strict=True, ) msg = LedgerApiMessage( message_id=2, target=1, performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION, terms=terms_arg, ) msg.to = "receiver" envelope = Envelope( to=msg.to, sender="sender", protocol_id=LedgerApiMessage.protocol_id, message=msg, ) envelope_bytes = envelope.encode() actual_envelope = Envelope.decode(envelope_bytes) expected_envelope = envelope assert expected_envelope.to == actual_envelope.to assert expected_envelope.sender == actual_envelope.sender assert expected_envelope.protocol_id == actual_envelope.protocol_id assert expected_envelope.message != actual_envelope.message actual_msg = LedgerApiMessage.serializer.decode(actual_envelope.message) actual_msg.to = actual_envelope.to actual_msg.sender = actual_envelope.sender expected_msg = msg assert expected_msg == actual_msg
def _request_balance(self) -> None: """ Request ledger balance. :return: None """ strategy = cast(Strategy, self.context.strategy) ledger_api_dialogues = cast( LedgerApiDialogues, self.context.ledger_api_dialogues ) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=ledger_api_dialogues.new_self_initiated_dialogue_reference(), ledger_id=strategy.ledger_id, address=cast(str, self.context.agent_addresses.get(strategy.ledger_id)), ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogues.update(ledger_api_msg) self.context.outbox.put_message(message=ledger_api_msg)
async def test_get_balance(ledger_id, address, config, ledger_apis_connection: Connection): """Test get balance.""" import aea # noqa # to load registries ledger_api_dialogues = LedgerApiDialogues(address) request = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), ledger_id=ledger_id, address=address, ) request.counterparty = str(ledger_apis_connection.connection_id) ledger_api_dialogue = ledger_api_dialogues.update(request) assert ledger_api_dialogue is not None envelope = Envelope( to=str(ledger_apis_connection.connection_id), sender=address, protocol_id=request.protocol_id, message=request, ) await ledger_apis_connection.send(envelope) await asyncio.sleep(0.01) response = await ledger_apis_connection.receive() assert response is not None assert type(response.message) == LedgerApiMessage response_msg_orig = cast(LedgerApiMessage, response.message) response_msg = copy.copy(response_msg_orig) response_msg.is_incoming = True response_msg.counterparty = response_msg_orig.sender response_dialogue = ledger_api_dialogues.update(response_msg) assert response_dialogue == ledger_api_dialogue assert response_msg.performative == LedgerApiMessage.Performative.BALANCE actual_balance_amount = response_msg.balance expected_balance_amount = make_ledger_api(ledger_id, **config).get_balance(address) assert actual_balance_amount == expected_balance_amount
async def test_attempts_get_transaction_receipt(): """Test retry and sleep.""" dispatcher = LedgerApiRequestDispatcher(ConnectionStatus()) dispatcher.connection_status.is_connected = True mock_api = Mock() contract_api_dialogues = ContractApiDialogues() message = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT, dialogue_reference=contract_api_dialogues. new_self_initiated_dialogue_reference(), transaction_digest=TransactionDigest("asdad", "sdfdsf"), ) message.counterparty = "test" dialogue = contract_api_dialogues.update(message) mock_api.get_transaction.return_value = None mock_api.is_transaction_settled.return_value = True with patch.object(dispatcher, "MAX_ATTEMPTS", 2): with patch.object(dispatcher, "TIMEOUT", 0.001): msg = dispatcher.get_transaction_receipt(mock_api, message, dialogue) assert msg.performative == LedgerApiMessage.Performative.ERROR
def test_encoding_unknown_performative(): """Test that we raise an exception when the performative is unknown during encoding.""" msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, ledger_id="some_ledger_id", address="some_address", ) with pytest.raises(ValueError, match="Performative not valid:"): with mock.patch.object(LedgerApiMessage.Performative, "__eq__", return_value=False): LedgerApiMessage.serializer.encode(msg)
def setup(self) -> None: """ Implement the setup. :return: None """ strategy = cast(GenericStrategy, self.context.strategy) if strategy.is_ledger_tx: ledger_api_dialogues = cast(LedgerApiDialogues, self.context.ledger_api_dialogues) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_BALANCE, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), ledger_id=strategy.ledger_id, address=cast( str, self.context.agent_addresses.get(strategy.ledger_id)), ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogues.update(ledger_api_msg) self.context.outbox.put_message(message=ledger_api_msg) self._register_agent() self._register_service()
def test__handle_invalid(self): """Test handling an invalid performative""" # setup dialogue = self.prepare_skill_dialogue( self.ledger_api_dialogues, self.list_of_ledger_api_messages[3:4]) incoming_message = self.build_incoming_message_for_skill_dialogue( dialogue=dialogue, performative=LedgerApiMessage.Performative.STATE, ledger_id=LEDGER_ID, state=LedgerApiMessage.State(LEDGER_ID, {}), ) # operation with patch.object(self.ledger_api_handler.context.logger, "log") as mock_logger: self.ledger_api_handler.handle(incoming_message) # after mock_logger.assert_any_call( logging.WARNING, f"cannot handle ledger_api message of performative={incoming_message.performative} in dialogue={dialogue}.", ) self.assert_quantity_in_outbox(0)
def decode(obj: bytes) -> Message: """ Decode bytes into a 'LedgerApi' message. :param obj: the bytes object. :return: the 'LedgerApi' message. """ ledger_api_pb = ledger_api_pb2.LedgerApiMessage() ledger_api_pb.ParseFromString(obj) message_id = ledger_api_pb.message_id dialogue_reference = ( ledger_api_pb.dialogue_starter_reference, ledger_api_pb.dialogue_responder_reference, ) target = ledger_api_pb.target performative = ledger_api_pb.WhichOneof("performative") performative_id = LedgerApiMessage.Performative(str(performative)) performative_content = dict() # type: Dict[str, Any] if performative_id == LedgerApiMessage.Performative.GET_BALANCE: ledger_id = ledger_api_pb.get_balance.ledger_id performative_content["ledger_id"] = ledger_id address = ledger_api_pb.get_balance.address performative_content["address"] = address elif performative_id == LedgerApiMessage.Performative.GET_RAW_TRANSACTION: pb2_terms = ledger_api_pb.get_raw_transaction.terms terms = Terms.decode(pb2_terms) performative_content["terms"] = terms elif performative_id == LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION: pb2_signed_transaction = ( ledger_api_pb.send_signed_transaction.signed_transaction) signed_transaction = SignedTransaction.decode( pb2_signed_transaction) performative_content["signed_transaction"] = signed_transaction elif performative_id == LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT: pb2_transaction_digest = ( ledger_api_pb.get_transaction_receipt.transaction_digest) transaction_digest = TransactionDigest.decode( pb2_transaction_digest) performative_content["transaction_digest"] = transaction_digest elif performative_id == LedgerApiMessage.Performative.BALANCE: ledger_id = ledger_api_pb.balance.ledger_id performative_content["ledger_id"] = ledger_id balance = ledger_api_pb.balance.balance performative_content["balance"] = balance elif performative_id == LedgerApiMessage.Performative.RAW_TRANSACTION: pb2_raw_transaction = ledger_api_pb.raw_transaction.raw_transaction raw_transaction = RawTransaction.decode(pb2_raw_transaction) performative_content["raw_transaction"] = raw_transaction elif performative_id == LedgerApiMessage.Performative.TRANSACTION_DIGEST: pb2_transaction_digest = ledger_api_pb.transaction_digest.transaction_digest transaction_digest = TransactionDigest.decode( pb2_transaction_digest) performative_content["transaction_digest"] = transaction_digest elif performative_id == LedgerApiMessage.Performative.TRANSACTION_RECEIPT: pb2_transaction_receipt = ( ledger_api_pb.transaction_receipt.transaction_receipt) transaction_receipt = TransactionReceipt.decode( pb2_transaction_receipt) performative_content["transaction_receipt"] = transaction_receipt elif performative_id == LedgerApiMessage.Performative.ERROR: code = ledger_api_pb.error.code performative_content["code"] = code if ledger_api_pb.error.message_is_set: message = ledger_api_pb.error.message performative_content["message"] = message if ledger_api_pb.error.data_is_set: data = ledger_api_pb.error.data performative_content["data"] = data else: raise ValueError( "Performative not valid: {}.".format(performative_id)) return LedgerApiMessage(message_id=message_id, dialogue_reference=dialogue_reference, target=target, performative=performative, **performative_content)
async def test_send_signed_transaction_ethereum( ledger_apis_connection: Connection): """Test send signed transaction with Ethereum APIs.""" import aea # noqa # to load registries crypto1 = EthereumCrypto(private_key_path=ETHEREUM_PRIVATE_KEY_PATH) crypto2 = EthereumCrypto() api = aea.crypto.registries.make_ledger_api(EthereumCrypto.identifier, **ETHEREUM_TESTNET_CONFIG) api = cast(EthereumApi, api) ledger_api_dialogues = LedgerApiDialogues() amount = 40000 fee = 30000 request = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), terms=Terms( ledger_id=EthereumCrypto.identifier, sender_address=crypto1.address, counterparty_address=crypto2.address, amount_by_currency_id={"ETH": -amount}, quantities_by_good_id={"some_service_id": 1}, is_sender_payable_tx_fee=True, nonce="", fee_by_currency_id={"ETH": fee}, chain_id=3, ), ) request.counterparty = str(ledger_apis_connection.connection_id) ledger_api_dialogue = ledger_api_dialogues.update(request) assert ledger_api_dialogue is not None envelope = Envelope( to=str(ledger_apis_connection.connection_id), sender=crypto1.address, protocol_id=request.protocol_id, message=request, ) await ledger_apis_connection.send(envelope) await asyncio.sleep(0.01) response = await ledger_apis_connection.receive() assert response is not None assert type(response.message) == LedgerApiMessage response_message = cast(LedgerApiMessage, response.message) assert (response_message.performative == LedgerApiMessage.Performative.RAW_TRANSACTION) response_dialogue = ledger_api_dialogues.update(response_message) assert response_dialogue == ledger_api_dialogue assert type(response_message.raw_transaction) == RawTransaction assert response_message.raw_transaction.ledger_id == request.terms.ledger_id # raw_tx = api.get_transfer_transaction( # sender_address=crypto1.address, # destination_address=crypto2.address, # amount=amount, # tx_fee=fee, # tx_nonce="", # chain_id=3, # ) signed_transaction = crypto1.sign_transaction( response_message.raw_transaction.body) request = LedgerApiMessage( performative=LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, dialogue_reference=ledger_api_dialogue.dialogue_label. dialogue_reference, signed_transaction=SignedTransaction(EthereumCrypto.identifier, signed_transaction), ) request.counterparty = str(ledger_apis_connection.connection_id) ledger_api_dialogue.update(request) envelope = Envelope( to=str(ledger_apis_connection.connection_id), sender=crypto1.address, protocol_id=request.protocol_id, message=request, ) await ledger_apis_connection.send(envelope) await asyncio.sleep(0.01) response = await ledger_apis_connection.receive() assert response is not None assert type(response.message) == LedgerApiMessage response_message = cast(LedgerApiMessage, response.message) assert (response_message.performative != LedgerApiMessage.Performative.ERROR ), f"Received error: {response_message.message}" assert (response_message.performative == LedgerApiMessage.Performative.TRANSACTION_DIGEST) response_dialogue = ledger_api_dialogues.update(response_message) assert response_dialogue == ledger_api_dialogue assert type(response_message.transaction_digest) == TransactionDigest assert type(response_message.transaction_digest.body) == str assert (response_message.transaction_digest.ledger_id == request.signed_transaction.ledger_id) assert type(response_message.transaction_digest.body.startswith("0x")) request = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT, dialogue_reference=ledger_api_dialogue.dialogue_label. dialogue_reference, transaction_digest=response_message.transaction_digest, ) request.counterparty = str(ledger_apis_connection.connection_id) ledger_api_dialogue.update(request) envelope = Envelope( to=str(ledger_apis_connection.connection_id), sender=crypto1.address, protocol_id=request.protocol_id, message=request, ) await ledger_apis_connection.send(envelope) await asyncio.sleep(0.01) response = await ledger_apis_connection.receive() assert response is not None assert type(response.message) == LedgerApiMessage response_message = cast(LedgerApiMessage, response.message) assert (response_message.performative == LedgerApiMessage.Performative.TRANSACTION_RECEIPT) response_dialogue = ledger_api_dialogues.update(response_message) assert response_dialogue == ledger_api_dialogue assert type(response_message.transaction_receipt) == TransactionReceipt assert response_message.transaction_receipt.receipt is not None assert response_message.transaction_receipt.transaction is not None assert (response_message.transaction_receipt.ledger_id == request.transaction_digest.ledger_id)
def setup(cls, **kwargs): """Setup the test class.""" super().setup(**kwargs) cls.ledger_api_handler = cast( LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api) cls.logger = cls._skill.skill_context.logger cls.simple_oracle_behaviour = cast( SimpleOracleBehaviour, cls._skill.skill_context.behaviours.simple_oracle_behaviour, ) cls.ledger_api_dialogues = cast( LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues) cls.contract_api_dialogues = cast( ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues) cls.signing_dialogues = cast( SigningDialogues, cls._skill.skill_context.signing_dialogues) cls.list_of_ledger_api_messages = ( DialogueMessage( LedgerApiMessage.Performative.GET_BALANCE, { "ledger_id": LEDGER_ID, "address": "some_eth_address" }, ), DialogueMessage( LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, { "signed_transaction": SignedTransaction( LEDGER_ID, DEFAULT_TX) }, ), DialogueMessage( LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT, { "transaction_digest": TransactionDigest(LEDGER_ID, "some_digest") }, ), DialogueMessage( LedgerApiMessage.Performative.GET_STATE, { "ledger_id": LEDGER_ID, "callable": "some_callable", "args": (), "kwargs": LedgerApiMessage.Kwargs({}), }, ), ) cls.list_of_contract_api_messages = (DialogueMessage( ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION, { "ledger_id": LEDGER_ID, "contract_id": "some_contract_id", "callable": "some_callable", "kwargs": ContractApiKwargs({"some_key": "some_value"}), }, ), ) cls.list_of_signing_messages = (DialogueMessage( SigningMessage.Performative.SIGN_TRANSACTION, { "terms": Terms(*DEFAULT_TERMS), "raw_transaction": RawTransaction(LEDGER_ID, DEFAULT_TX), }, ), )
def _handle_inform(self, fipa_msg: FipaMessage, fipa_dialogue: FipaDialogue) -> None: """ Handle the INFORM. If the INFORM message contains the transaction_digest then verify that it is settled, otherwise do nothing. If the transaction is settled, send the data, otherwise do nothing. :param fipa_msg: the message :param fipa_dialogue: the dialogue object :return: None """ new_message_id = fipa_msg.message_id + 1 new_target = fipa_msg.message_id self.context.logger.info("[{}]: received INFORM from sender={}".format( self.context.agent_name, fipa_msg.counterparty[-5:])) strategy = cast(GenericStrategy, self.context.strategy) if strategy.is_ledger_tx and "transaction_digest" in fipa_msg.info.keys( ): self.context.logger.info( "[{}]: checking whether transaction={} has been received ...". format(self.context.agent_name, fipa_msg.info["transaction_digest"])) ledger_api_dialogues = cast(LedgerApiDialogues, self.context.ledger_api_dialogues) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative. GET_TRANSACTION_RECEIPT, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), transaction_digest=TransactionDigest( fipa_dialogue.terms.ledger_id, fipa_msg.info["transaction_digest"]), ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogue = cast( Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)) assert (ledger_api_dialogue is not None), "LedgerApiDialogue construction failed." ledger_api_dialogue.associated_fipa_dialogue = fipa_dialogue self.context.outbox.put_message(message=ledger_api_msg) elif strategy.is_ledger_tx: self.context.logger.warning( "[{}]: did not receive transaction digest from sender={}.". format(self.context.agent_name, fipa_msg.counterparty[-5:])) elif not strategy.is_ledger_tx and "Done" in fipa_msg.info.keys(): inform_msg = FipaMessage( message_id=new_message_id, dialogue_reference=fipa_dialogue.dialogue_label. dialogue_reference, target=new_target, performative=FipaMessage.Performative.INFORM, info=fipa_dialogue.data_for_sale, ) inform_msg.counterparty = fipa_msg.counterparty fipa_dialogue.update(inform_msg) self.context.outbox.put_message(message=inform_msg) fipa_dialogues = cast(FipaDialogues, self.context.fipa_dialogues) fipa_dialogues.dialogue_stats.add_dialogue_endstate( FipaDialogue.EndState.SUCCESSFUL, fipa_dialogue.is_self_initiated) self.context.logger.info( "[{}]: transaction confirmed, sending data={} to buyer={}.". format( self.context.agent_name, fipa_dialogue.data_for_sale, fipa_msg.counterparty[-5:], )) else: self.context.logger.warning( "[{}]: did not receive transaction confirmation from sender={}." .format(self.context.agent_name, fipa_msg.counterparty[-5:]))
def _handle_terms(self, ml_trade_msg: MlTradeMessage, ml_trade_dialogue: MlTradeDialogue) -> None: """ Handle the terms of the request. :param ml_trade_msg: the ml trade message :param ml_trade_dialogue: the dialogue object :return: None """ terms = ml_trade_msg.terms self.context.logger.info( "received terms message from {}: terms={}".format( ml_trade_msg.counterparty[-5:], terms.values)) strategy = cast(Strategy, self.context.strategy) acceptable = strategy.is_acceptable_terms(terms) affordable = strategy.is_affordable_terms(terms) if not acceptable and affordable: self.context.logger.info( "rejecting, terms are not acceptable and/or affordable") return if strategy.is_ledger_tx: # construct a tx for settlement on the ledger ledger_api_dialogues = cast(LedgerApiDialogues, self.context.ledger_api_dialogues) ledger_api_msg = LedgerApiMessage( performative=LedgerApiMessage.Performative.GET_RAW_TRANSACTION, dialogue_reference=ledger_api_dialogues. new_self_initiated_dialogue_reference(), terms=Terms( ledger_id=terms.values["ledger_id"], sender_address=self.context.agent_addresses[ terms.values["ledger_id"]], counterparty_address=terms.values["address"], amount_by_currency_id={ terms.values["currency_id"]: -terms.values["price"] }, is_sender_payable_tx_fee=True, quantities_by_good_id={"ml_training_data": 1}, nonce=uuid.uuid4().hex, fee_by_currency_id={terms.values["currency_id"]: 1}, ), ) ledger_api_msg.counterparty = LEDGER_API_ADDRESS ledger_api_dialogue = cast( Optional[LedgerApiDialogue], ledger_api_dialogues.update(ledger_api_msg)) assert (ledger_api_dialogue is not None), "Error when creating ledger api dialogue." ledger_api_dialogue.associated_ml_trade_dialogue = ml_trade_dialogue self.context.outbox.put_message(message=ledger_api_msg) self.context.logger.info( "requesting transfer transaction from ledger api...") else: # accept directly with a dummy transaction digest, no settlement ml_accept = MlTradeMessage( performative=MlTradeMessage.Performative.ACCEPT, dialogue_reference=ml_trade_dialogue.dialogue_label. dialogue_reference, message_id=ml_trade_msg.message_id + 1, target=ml_trade_msg.message_id, tx_digest=DUMMY_DIGEST, terms=terms, ) ml_accept.counterparty = ml_trade_msg.counterparty ml_trade_dialogue.update(ml_accept) self.context.outbox.put_message(message=ml_accept) self.context.logger.info("sending dummy transaction digest ...")