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 = cast( LedgerApiMessage, dialogue.reply( performative=LedgerApiMessage.Performative.RAW_TRANSACTION, target_message=message, raw_transaction=RawTransaction( message.terms.ledger_id, raw_transaction ), ), ) return response
def test_handle_tx_signing_ethereum(self): """Test tx signing for ethereum.""" tx = {"gasPrice": 30, "nonce": 1, "gas": 20000} signing_dialogues = SigningDialogues( str(PublicId("author", "a_skill", "0.1.0"))) signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues. new_self_initiated_dialogue_reference(), terms=Terms( ledger_id=ETHEREUM, sender_address="pk1", counterparty_address="pk2", amount_by_currency_id={"FET": -1}, is_sender_payable_tx_fee=True, quantities_by_good_id={"good_id": 10}, nonce="transaction nonce", ), raw_transaction=RawTransaction(ETHEREUM, tx), ) signing_dialogue = signing_dialogues.create_with_message( "decision_maker", signing_msg) assert signing_dialogue is not None self.decision_maker.message_in_queue.put_nowait(signing_msg) signing_msg_response = self.decision_maker.message_out_queue.get( timeout=2) recovered_dialogue = signing_dialogues.update(signing_msg_response) assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue assert (signing_msg_response.performative == SigningMessage.Performative.SIGNED_TRANSACTION) assert (type(signing_msg_response.signed_transaction.body) == eth_account.datastructures.SignedTransaction)
def test_handle_tx_signing_unknown(self): """Test tx signing for unknown.""" tx = {} signing_dialogues = SigningDialogues("agent") signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(), skill_callback_ids=(str(PublicId("author", "a_skill", "0.1.0")),), skill_callback_info={}, terms=Terms( ledger_id="unknown", sender_address="pk1", counterparty_address="pk2", amount_by_currency_id={"FET": -1}, is_sender_payable_tx_fee=True, quantities_by_good_id={"good_id": 10}, nonce="transaction nonce", ), raw_transaction=RawTransaction("unknown", tx), ) signing_msg.counterparty = "decision_maker" signing_dialogue = signing_dialogues.update(signing_msg) assert signing_dialogue is not None self.decision_maker.message_in_queue.put_nowait(signing_msg) signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2) signing_msg_response.counterparty = signing_msg.counterparty signing_msg_response.is_incoming = True recovered_dialogue = signing_dialogues.update(signing_msg_response) assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue assert signing_msg_response.performative == SigningMessage.Performative.ERROR assert signing_msg_response.skill_callback_ids == signing_msg.skill_callback_ids assert ( signing_msg_response.error_code == SigningMessage.ErrorCode.UNSUCCESSFUL_TRANSACTION_SIGNING )
def get_raw_transaction( self, api: LedgerApi, message: ContractApiMessage, dialogue: ContractApiDialogue, ) -> ContractApiMessage: """ Send the request 'get_raw_transaction'. :param api: the API object. :param message: the Ledger API message :param dialogue: the contract API dialogue :return: None """ contract = self.contract_registry.make(message.contract_id) method_to_call = getattr(contract, message.callable) try: tx = method_to_call(api, message.contract_address, **message.kwargs.body) response = ContractApiMessage( performative=ContractApiMessage.Performative.RAW_TRANSACTION, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, raw_transaction=RawTransaction(message.ledger_id, tx), ) response.counterparty = message.counterparty dialogue.update(response) except Exception as e: # pylint: disable=broad-except # pragma: nocover response = self.get_error_message(e, api, message, dialogue) return response
def test_handle_tx_signing_fetchai(self): """Test tx signing for fetchai.""" tx = TokenTxFactory.transfer( FetchaiAddress("v3sZs7gKKz9xmoTo9yzRkfHkjYuX42MzXaq4eVjGHxrX9qu3U"), FetchaiAddress("2bzQNV4TTjMAiKZe85EyLUttoFpHHuksRzUUBYB1brt98pMXKK"), 1, 1, [], ) signing_dialogues = SigningDialogues("agent1") signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues.new_self_initiated_dialogue_reference(), skill_callback_ids=(str(PublicId("author", "a_skill", "0.1.0")),), skill_callback_info={}, terms=Terms( ledger_id=FETCHAI, sender_address="pk1", counterparty_address="pk2", amount_by_currency_id={"FET": -1}, is_sender_payable_tx_fee=True, quantities_by_good_id={"good_id": 10}, nonce="transaction nonce", ), raw_transaction=RawTransaction(FETCHAI, tx), ) signing_msg.counterparty = "decision_maker" self.decision_maker.message_in_queue.put_nowait(signing_msg) signing_msg_response = self.decision_maker.message_out_queue.get(timeout=2) assert ( signing_msg_response.performative == SigningMessage.Performative.SIGNED_TRANSACTION ) assert signing_msg_response.skill_callback_ids == signing_msg.skill_callback_ids assert type(signing_msg_response.signed_transaction.body) == FetchaiTransaction
def test_handle_tx_signing_ethereum(self): """Test tx signing for ethereum.""" tx = {"gasPrice": 30, "nonce": 1, "gas": 20000} signing_dialogues = SigningDialogues("agent2") signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues. new_self_initiated_dialogue_reference(), skill_callback_ids=(str(PublicId("author", "a_skill", "0.1.0")), ), skill_callback_info={}, terms=Terms( ledger_id="ethereum", sender_address="pk1", counterparty_address="pk2", amount_by_currency_id={"FET": -1}, is_sender_payable_tx_fee=True, quantities_by_good_id={"good_id": 10}, nonce="transaction nonce", ), raw_transaction=RawTransaction("ethereum", tx), ) signing_msg.counterparty = "decision_maker" self.decision_maker.message_in_queue.put_nowait(signing_msg) signing_msg_response = self.decision_maker.message_out_queue.get( timeout=2) assert (signing_msg_response.performative == SigningMessage.Performative.SIGNED_TRANSACTION) assert signing_msg_response.skill_callback_ids == signing_msg.skill_callback_ids assert (type(signing_msg_response.signed_transaction.body) == eth_account.datastructures.AttributeDict)
def build_response(tx: bytes) -> ContractApiMessage: return ContractApiMessage( performative=ContractApiMessage.Performative.RAW_TRANSACTION, message_id=message.message_id + 1, target=message.message_id, dialogue_reference=dialogue.dialogue_label.dialogue_reference, raw_transaction=RawTransaction(message.ledger_id, tx), )
def test_init_raw_transaction(): """Test the raw_transaction object initialization.""" ledger_id = "some_ledger" body = "body" rt = RawTransaction(ledger_id, body) assert rt.ledger_id == ledger_id assert rt.body == body assert str(rt) == "RawTransaction: ledger_id=some_ledger, body=body" assert rt == rt
def build_response( tx: bytes, dialogue: ContractApiDialogue ) -> ContractApiMessage: return cast( ContractApiMessage, dialogue.reply( performative=ContractApiMessage.Performative.RAW_TRANSACTION, raw_transaction=RawTransaction(message.ledger_id, tx), ), )
def test_raw_transaction_encode_decode(): """Test encoding and decoding of terms.""" class RawTransactionProtobufObject: raw_transaction_bytes = b"" ledger_id = "some_ledger" body = {"body": "value"} rt = RawTransaction(ledger_id, body) RawTransaction.encode(RawTransactionProtobufObject, rt) recovered_rt = RawTransaction.decode(RawTransactionProtobufObject) assert rt == recovered_rt
def test_sign_transaction(self): """Test for an error for a sign transaction message.""" tx_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, terms=self.terms, raw_transaction=RawTransaction(self.ledger_id, "transaction"), ) assert tx_msg._is_consistent() encoded_tx_msg = tx_msg.encode() decoded_tx_msg = tx_msg.serializer.decode(encoded_tx_msg) assert tx_msg == decoded_tx_msg
def build_response( tx: Union[bytes, JSONLike], dialogue: ContractApiDialogue) -> ContractApiMessage: if isinstance(tx, bytes): raise ValueError( f"Invalid transaction type, got={type(tx)}, expected={JSONLike}." ) return cast( ContractApiMessage, dialogue.reply( performative=ContractApiMessage.Performative. RAW_TRANSACTION, raw_transaction=RawTransaction(message.ledger_id, tx), ), )
def test_message_consistency(self): """Test for an error in consistency of a message.""" tx_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, skill_callback_ids=self.skill_callback_ids, skill_callback_info=self.skill_callback_info, terms=self.terms, raw_transaction=RawTransaction(self.ledger_id, "transaction"), ) assert tx_msg._is_consistent() tx_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_MESSAGE, skill_callback_ids=self.skill_callback_ids, skill_callback_info=self.skill_callback_info, terms=self.terms, raw_message=RawMessage(self.ledger_id, "message"), ) assert tx_msg._is_consistent() tx_msg = SigningMessage( performative=SigningMessage.Performative.SIGNED_TRANSACTION, message_id=2, target=1, skill_callback_ids=self.skill_callback_ids, skill_callback_info=self.skill_callback_info, signed_transaction=SignedTransaction(self.ledger_id, "signature"), ) assert tx_msg._is_consistent() tx_msg = SigningMessage( performative=SigningMessage.Performative.SIGNED_MESSAGE, message_id=2, target=1, skill_callback_ids=self.skill_callback_ids, skill_callback_info=self.skill_callback_info, signed_message=SignedMessage(self.ledger_id, "message"), ) assert tx_msg._is_consistent() tx_msg = SigningMessage( performative=SigningMessage.Performative.ERROR, message_id=2, target=1, skill_callback_ids=self.skill_callback_ids, skill_callback_info=self.skill_callback_info, error_code=SigningMessage.ErrorCode.UNSUCCESSFUL_MESSAGE_SIGNING, ) assert tx_msg._is_consistent() assert str(tx_msg.performative) == "error" assert len(tx_msg.valid_performatives) == 5
def test_signing_dialogues(self): """Test the SigningDialogues class.""" _, dialogue = self.signing_dialogues.create( counterparty=COUNTERPARTY_ADDRESS, performative=SigningMessage.Performative.SIGN_TRANSACTION, terms=Terms( "some_ledger_id", "some_sender_address", "some_counterparty_address", dict(), dict(), "some_nonce", ), raw_transaction=RawTransaction("some_ledger_id", "some_body"), ) assert dialogue.role == SigningDialogue.Role.SKILL assert dialogue.self_address == str(self.skill.skill_context.skill_id)
def test_dialogues(): """Test intiaontiation of dialogues.""" signing_dialogues = SigningDialogues("agent_addr") msg, dialogue = signing_dialogues.create( counterparty="abc", performative=SigningMessage.Performative.SIGN_TRANSACTION, terms=Terms( ledger_id="ledger_id", sender_address="address1", counterparty_address="address2", amount_by_currency_id={"FET": -2}, quantities_by_good_id={"good_id": 10}, is_sender_payable_tx_fee=True, nonce="transaction nonce", ), raw_transaction=RawTransaction("ledger_id", "transaction"), ) assert dialogue is not None
def test_handle_tx_signing_fetchai(self): """Test tx signing for fetchai.""" fetchai_api = FetchAIApi(**FETCHAI_TESTNET_CONFIG) account = FetchAICrypto() fc2 = FetchAICrypto() amount = 10000 transfer_transaction = fetchai_api.get_transfer_transaction( sender_address=account.address, destination_address=fc2.address, amount=amount, tx_fee=1000, tx_nonce="something", ) signing_dialogues = SigningDialogues( str(PublicId("author", "a_skill", "0.1.0"))) signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues. new_self_initiated_dialogue_reference(), terms=Terms( ledger_id=FETCHAI, sender_address="pk1", counterparty_address="pk2", amount_by_currency_id={"FET": -1}, is_sender_payable_tx_fee=True, quantities_by_good_id={"good_id": 10}, nonce="transaction nonce", ), raw_transaction=RawTransaction(FETCHAI, transfer_transaction), ) signing_dialogue = signing_dialogues.create_with_message( "decision_maker", signing_msg) assert signing_dialogue is not None self.decision_maker.message_in_queue.put_nowait(signing_msg) signing_msg_response = self.decision_maker.message_out_queue.get( timeout=2) recovered_dialogue = signing_dialogues.update(signing_msg_response) assert recovered_dialogue is not None and recovered_dialogue == signing_dialogue assert (signing_msg_response.performative == SigningMessage.Performative.SIGNED_TRANSACTION) assert type(signing_msg_response.signed_transaction.body) == dict
def run(): # Create a private key create_private_key(CosmosCrypto.identifier, private_key_file=COSMOS_PRIVATE_KEY_FILE_1) # Instantiate the builder and build the AEA # By default, the default protocol, error skill and stub connection are added builder = AEABuilder() builder.set_name("my_aea") builder.add_private_key(CosmosCrypto.identifier, COSMOS_PRIVATE_KEY_FILE_1) # Create our AEA my_aea = builder.build() # add a simple skill with handler skill_context = SkillContext(my_aea.context) skill_config = SkillConfig(name="simple_skill", author="fetchai", version="0.1.0") signing_handler = SigningHandler(skill_context=skill_context, name="signing_handler") signing_dialogues_model = SigningDialogues(skill_context=skill_context, name="signing_dialogues") simple_skill = Skill( skill_config, skill_context, handlers={signing_handler.name: signing_handler}, models={signing_dialogues_model.name: signing_dialogues_model}, ) my_aea.resources.add_skill(simple_skill) # create a second identity create_private_key(CosmosCrypto.identifier, private_key_file=COSMOS_PRIVATE_KEY_FILE_2) counterparty_wallet = Wallet( {CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE_2}) counterparty_identity = Identity( name="counterparty_aea", addresses=counterparty_wallet.addresses, default_address_key=CosmosCrypto.identifier, ) # create signing message for decision maker to sign terms = Terms( ledger_id=CosmosCrypto.identifier, sender_address=my_aea.identity.address, counterparty_address=counterparty_identity.address, amount_by_currency_id={"FET": -1}, quantities_by_good_id={"some_service": 1}, nonce="some_nonce", fee_by_currency_id={"FET": 0}, ) signing_dialogues = cast(SigningDialogues, skill_context.signing_dialogues) stub_transaction = LedgerApis.get_transfer_transaction( terms.ledger_id, terms.sender_address, terms.counterparty_address, terms.sender_payable_amount, terms.sender_fee, terms.nonce, ) signing_msg = SigningMessage( performative=SigningMessage.Performative.SIGN_TRANSACTION, dialogue_reference=signing_dialogues. new_self_initiated_dialogue_reference(), skill_callback_ids=(str(skill_context.skill_id), ), raw_transaction=RawTransaction(CosmosCrypto.identifier, stub_transaction), terms=terms, skill_callback_info={"some_info_key": "some_info_value"}, ) signing_msg.counterparty = "decision_maker" signing_dialogue = cast(Optional[SigningDialogue], signing_dialogues.update(signing_msg)) assert signing_dialogue is not None my_aea.context.decision_maker_message_queue.put_nowait(signing_msg) # Set the AEA running in a different thread try: logger.info("STARTING AEA NOW!") t = Thread(target=my_aea.start) t.start() # Let it run long enough to interact with the decision maker time.sleep(1) finally: # Shut down the AEA logger.info("STOPPING AEA NOW!") my_aea.stop() t.join()
def setup(cls): """Setup the test class.""" super().setup() cls.ledger_api_handler = cast( LedgerApiHandler, cls._skill.skill_context.handlers.ledger_api) cls.ledger_api_dialogues = cast( LedgerApiDialogues, cls._skill.skill_context.ledger_api_dialogues) cls.signing_dialogues = cast( SigningDialogues, cls._skill.skill_context.signing_dialogues) cls.contract_api_dialogues = cast( ContractApiDialogues, cls._skill.skill_context.contract_api_dialogues) cls.parameters = cast(Parameters, cls._skill.skill_context.parameters) cls.game = cast(Game, cls._skill.skill_context.game) cls.logger = cls.ledger_api_handler.context.logger cls.ledger_id = "some_ledger_id" cls.contract_id = "some_contract_id" cls.callable = "some_callable" cls.kwargs = Kwargs({"some_key": "some_value"}) cls.body = {"some_key": "some_value"} cls.body_str = "some_body" cls.contract_address = "some_contract_address" cls.raw_transaction = RawTransaction(cls.ledger_id, cls.body) cls.signed_transaction = SignedTransaction(cls.ledger_id, cls.body) cls.transaction_digest = TransactionDigest(cls.ledger_id, cls.body_str) cls.receipt = {"contractAddress": cls.contract_address} cls.transaction_receipt = TransactionReceipt( cls.ledger_id, cls.receipt, {"transaction_key": "transaction_value"}) cls.terms = Terms( cls.ledger_id, cls._skill.skill_context.agent_address, "counterprty", {"currency_id": 50}, {"good_id": -10}, "some_nonce", ) cls.list_of_signing_messages = (DialogueMessage( SigningMessage.Performative.SIGN_TRANSACTION, { "terms": cls.terms, "raw_transaction": SigningMessage.RawTransaction(cls.ledger_id, cls.body), }, ), ) cls.list_of_contract_api_messages = (DialogueMessage( ContractApiMessage.Performative.GET_DEPLOY_TRANSACTION, { "ledger_id": cls.ledger_id, "contract_id": cls.contract_id, "callable": cls.callable, "kwargs": cls.kwargs, }, ), ) cls.list_of_ledger_api_messages = ( DialogueMessage(LedgerApiMessage.Performative.GET_RAW_TRANSACTION, {"terms": cls.terms}), DialogueMessage( LedgerApiMessage.Performative.RAW_TRANSACTION, {"raw_transaction": cls.raw_transaction}, ), DialogueMessage( LedgerApiMessage.Performative.SEND_SIGNED_TRANSACTION, {"signed_transaction": cls.signed_transaction}, ), DialogueMessage( LedgerApiMessage.Performative.TRANSACTION_DIGEST, {"transaction_digest": cls.transaction_digest}, ), DialogueMessage( LedgerApiMessage.Performative.GET_TRANSACTION_RECEIPT, {"transaction_digest": cls.transaction_digest}, ), )