def test_sign_and_recover_message(): """Test the signing and the recovery function for the eth_crypto.""" account = EthereumCrypto(PRIVATE_KEY_PATH) sign_bytes = account.sign_message(message=b"hello") assert len(sign_bytes) > 0, "The len(signature) must not be 0" recovered_addr = account.recover_message(message=b"hello", signature=sign_bytes) assert recovered_addr == account.address, "Failed to recover the correct address."
def test_transfer(): """Test transfer of wealth.""" ethereum_api = EthereumApi(**ETHEREUM_TESTNET_CONFIG) ec1 = EthereumCrypto(private_key_path=ETHEREUM_PRIVATE_KEY_PATH) ec2 = EthereumCrypto() amount = 40000 fee = 30000 tx_nonce = ethereum_api.generate_tx_nonce(ec2.address, ec1.address) tx_digest = ethereum_api.transfer(ec1, ec2.address, amount, fee, tx_nonce, chain_id=3) assert tx_digest is not None, "Failed to submit transfer!" not_settled = True elapsed_time = 0 while not_settled and elapsed_time < 180: elapsed_time += 2 time.sleep(2) is_settled = ethereum_api.is_transaction_settled(tx_digest) not_settled = not is_settled assert is_settled, "Failed to complete tx!" is_valid = ethereum_api.is_transaction_valid(tx_digest, ec2.address, ec1.address, tx_nonce, amount) assert is_valid, "Failed to settle tx correctly!"
def test_get_balance(): """Test the balance is zero for a new account.""" ethereum_api = EthereumApi(**ETHEREUM_TESTNET_CONFIG) ec = EthereumCrypto() balance = ethereum_api.get_balance(ec.address) assert balance == 0, "New account has a positive balance." ec = EthereumCrypto(private_key_path=ETHEREUM_PRIVATE_KEY_PATH) balance = ethereum_api.get_balance(ec.address) assert balance > 0, "Existing account has no balance."
def test_sign_and_recover_message(): """Test the signing and the recovery function for the eth_crypto.""" account = EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH) sign_bytes = account.sign_message(message=b"hello") assert len(sign_bytes) > 0, "The len(signature) must not be 0" recovered_addresses = EthereumApi.recover_message(message=b"hello", signature=sign_bytes) assert len( recovered_addresses) == 1, "Wrong number of addresses recovered." assert (recovered_addresses[0] == account.address ), "Failed to recover the correct address."
def test_validate_ethereum_transaction(self): seller = EthereumCrypto() client = EthereumCrypto() ledger_apis = LedgerApis( {ETHEREUM: DEFAULT_ETHEREUM_CONFIG, FETCHAI: DEFAULT_FETCHAI_CONFIG}, FETCHAI, ) tx_nonce = ledger_apis.generate_tx_nonce( ETHEREUM, seller.address, client.address ) tx_digest = "0xbefa7768c313ff49bf274eefed001042a0ff9e3cfbe75ff1a9c2baf18001cec4" result = AttributeDict( { "blockHash": HexBytes( "0x0bfc237d2a17f719a3300a4822779391ec6e3a74832fe1b05b8c477902b0b59e" ), "blockNumber": 7161932, "from": client.address, "gas": 200000, "gasPrice": 50000000000, "hash": HexBytes( "0xbefa7768c313ff49bf274eefed001042a0ff9e3cfbe75ff1a9c2baf18001cec4" ), "input": tx_nonce, "nonce": 4, "r": HexBytes( "0xb54ce8b9fa1d1be7be316c068af59a125d511e8dd51202b1a7e3002dee432b52" ), "s": HexBytes( "0x4f44702b3812d3b4e4b76da0fd5b554b3ae76d1717db5b6b5faebd7b85ae0303" ), "to": seller.address, "transactionIndex": 0, "v": 42, "value": 2, } ) with mock.patch.object( ledger_apis.apis.get(ETHEREUM).api.eth, "getTransaction", return_value=result, ): assert ledger_apis.is_tx_valid( identifier=ETHEREUM, tx_digest=tx_digest, seller=seller.address, client=client.address, tx_nonce=tx_nonce, amount=2, )
def test_construct_sign_and_submit_transfer_transaction(): """Test the construction, signing and submitting of a transfer transaction.""" account = EthereumCrypto(private_key_path=ETHEREUM_PRIVATE_KEY_PATH) ec2 = EthereumCrypto() ethereum_api = EthereumApi(**ETHEREUM_TESTNET_CONFIG) amount = 40000 tx_nonce = ethereum_api.generate_tx_nonce(ec2.address, account.address) transfer_transaction = ethereum_api.get_transfer_transaction( sender_address=account.address, destination_address=ec2.address, amount=amount, tx_fee=30000, tx_nonce=tx_nonce, chain_id=3, ) assert (isinstance(transfer_transaction, dict) and len(transfer_transaction) == 7), "Incorrect transfer_transaction constructed." signed_transaction = account.sign_transaction(transfer_transaction) assert (isinstance(signed_transaction, eth_account.datastructures.AttributeDict) and len(signed_transaction) == 5), "Incorrect signed_transaction constructed." transaction_digest = ethereum_api.send_signed_transaction( signed_transaction) assert transaction_digest is not None, "Failed to submit transfer transaction!" not_settled = True elapsed_time = 0 while not_settled and elapsed_time < 20: elapsed_time += 1 time.sleep(2) transaction_receipt = ethereum_api.get_transaction_receipt( transaction_digest) if transaction_receipt is None: continue is_settled = ethereum_api.is_transaction_settled(transaction_receipt) not_settled = not is_settled assert transaction_receipt is not None, "Failed to retrieve transaction receipt." assert is_settled, "Failed to verify tx!" tx = ethereum_api.get_transaction(transaction_digest) is_valid = ethereum_api.is_transaction_valid(tx, ec2.address, account.address, tx_nonce, amount) assert is_valid, "Failed to settle tx correctly!" assert tx != transaction_receipt, "Should not be same!"
def test_sign_and_recover_message_deprecated(): """Test the signing and the recovery function for the eth_crypto.""" account = EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH) message = b"hello" message_hash = hashlib.sha256(message).digest() sign_bytes = account.sign_message(message=message_hash, is_deprecated_mode=True) assert len(sign_bytes) > 0, "The len(signature) must not be 0" recovered_addresses = EthereumApi.recover_message( message=message_hash, signature=sign_bytes, is_deprecated_mode=True ) assert len(recovered_addresses) == 1, "Wrong number of addresses recovered." assert ( recovered_addresses[0] == account.address ), "Failed to recover the correct address."
def test_initialization(): """Test the initialisation of the variables.""" account = EthereumCrypto() assert account.entity is not None, "The property must return the account." assert account.address is not None, "After creation the display address must not be None" assert account.public_key is not None, "After creation the public key must no be None" assert account.entity is not None, "After creation the entity must no be None"
def __init__(self, private_key_paths: Dict[str, str]): """ Instantiate a wallet object. :param private_key_paths: the private key paths """ crypto_objects = {} # type: Dict[str, Crypto] public_keys = {} # type: Dict[str, str] addresses = {} # type: Dict[str, str] for identifier, path in private_key_paths.items(): if identifier == DEFAULT: crypto_objects[identifier] = DefaultCrypto(path) elif identifier == FETCHAI: crypto_objects[identifier] = FetchAICrypto(path) elif identifier == ETHEREUM: crypto_objects[identifier] = EthereumCrypto(path) else: raise ValueError("Unsupported identifier in private key paths.") crypto = cast(Crypto, crypto_objects.get(identifier)) public_keys[identifier] = cast(str, crypto.public_key) addresses[identifier] = cast(str, crypto.address) self._crypto_objects = crypto_objects self._public_keys = public_keys self._addresses = addresses
def test_failed_transfer_ethereum(self): """Test the transfer function for ethereum token fails.""" private_key_path = os.path.join(CUR_PATH, "data", "eth_private_key.txt") eth_obj = EthereumCrypto(private_key_path=private_key_path) ledger_apis = LedgerApis( { ETHEREUM: DEFAULT_ETHEREUM_CONFIG, FETCHAI: DEFAULT_FETCHAI_CONFIG }, FETCHAI, ) with mock.patch.object( ledger_apis.apis.get(ETHEREUM).api.eth, "getTransactionCount", return_value=5, side_effect=Exception, ): tx_digest = ledger_apis.transfer( eth_obj, eth_address, amount=10, tx_fee=200000, tx_nonce="transaction nonce", ) assert tx_digest is None assert ledger_apis.last_tx_statuses[ETHEREUM] == "ERROR"
def generate_key(ctx: Context, type_): """Generate private keys.""" if type_ == DefaultCrypto.identifier or type_ == "all": DefaultCrypto().dump(open(DEFAULT_PRIVATE_KEY_FILE, "wb")) if type_ == FetchAICrypto.identifier or type_ == "all": FetchAICrypto().dump(open(FETCHAI_PRIVATE_KEY_FILE, "wb")) if type_ == EthereumCrypto.identifier or type_ == "all": EthereumCrypto().dump(open(ETHEREUM_PRIVATE_KEY_FILE, "wb"))
def test_get_wealth_positive(caplog): """Test the balance is zero for a new account.""" with caplog.at_level(logging.DEBUG, logger="aea.crypto.ethereum"): ethereum_faucet_api = EthereumFaucetApi() ec = EthereumCrypto() ethereum_faucet_api.get_wealth(ec.address) assert ( "Response: " in caplog.text), f"Cannot find message in output: {caplog.text}"
def test_ethereum(self): """Test that the fetch private key is created correctly.""" result = self.runner.invoke( cli, [*CLI_LOG_OPTION, "generate-key", "ethereum"]) assert result.exit_code == 0 assert Path(ETHEREUM_PRIVATE_KEY_FILE).exists() EthereumCrypto(ETHEREUM_PRIVATE_KEY_FILE) Path(ETHEREUM_PRIVATE_KEY_FILE).unlink()
def test_all(self): """Test that all the private keys are created correctly when running 'aea generate-key all'.""" result = self.runner.invoke(cli, [*CLI_LOG_OPTION, "generate-key", "all"]) assert result.exit_code == 0 assert Path(FETCHAI_PRIVATE_KEY_FILE).exists() assert Path(ETHEREUM_PRIVATE_KEY_FILE).exists() FetchAICrypto(FETCHAI_PRIVATE_KEY_FILE) EthereumCrypto(ETHEREUM_PRIVATE_KEY_FILE) Path(FETCHAI_PRIVATE_KEY_FILE).unlink() Path(ETHEREUM_PRIVATE_KEY_FILE).unlink()
def test_get_deploy_transaction(ethereum_testnet_config, ganache): """Test the get deploy transaction method.""" ethereum_api = EthereumApi(**ethereum_testnet_config) ec2 = EthereumCrypto() interface = {"abi": [], "bytecode": b""} deploy_tx = ethereum_api.get_deploy_transaction( contract_interface=interface, deployer_address=ec2.address, ) assert type(deploy_tx) == dict and len(deploy_tx) == 6 assert all( key in ["from", "value", "gas", "gasPrice", "nonce", "data"] for key in deploy_tx.keys() )
def test_transfer_ethereum(self): """Test the transfer function for ethereum token.""" private_key_path = os.path.join(CUR_PATH, "data", "eth_private_key.txt") eth_obj = EthereumCrypto(private_key_path=private_key_path) ledger_apis = LedgerApis({ETHEREUM: DEFAULT_ETHEREUM_CONFIG, FETCHAI: DEFAULT_FETCHAI_CONFIG}) with mock.patch.object(ledger_apis.apis.get(ETHEREUM).eth, 'getTransactionCount', return_value=5): with mock.patch.object(ledger_apis.apis.get(ETHEREUM).eth.account, 'signTransaction', return_value=mock.Mock()): result = HexBytes('0xf85f808082c35094d898d5e829717c72e7438bad593076686d7d164a80801ba005c2e99ecee98a12fbf28ab9577423f42e9e88f2291b3acc8228de743884c874a077d6bc77a47ad41ec85c96aac2ad27f05a039c4787fca8a1e5ee2d8c7ec1bb6a') with mock.patch.object(ledger_apis.apis.get(ETHEREUM).eth, 'sendRawTransaction', return_value=result): with mock.patch.object(ledger_apis.apis.get(ETHEREUM).eth, "getTransactionReceipt", return_value=b'0xa13f2f926233bc4638a20deeb8aaa7e8d6a96e487392fa55823f925220f6efed'): tx_digest = ledger_apis.transfer(ETHEREUM, eth_obj, eth_address, amount=10, tx_fee=200000) assert tx_digest is not None assert ledger_apis.last_tx_statuses[ETHEREUM] == 'OK'
async def test_p2plibp2pconnection_connect_disconnect_ethereum(self): """Test connect then disconnect.""" temp_dir = os.path.join(self.t, "temp_dir") os.mkdir(temp_dir) connection = _make_libp2p_connection(data_dir=temp_dir, agent_key=EthereumCrypto()) assert connection.is_connected is False try: await connection.connect() assert connection.is_connected is True except Exception as e: await connection.disconnect() raise e await connection.disconnect() assert connection.is_connected is False
def generate_key(click_context, type_): """Generate private keys.""" def _can_write(path) -> bool: if Path(path).exists(): value = click.confirm( "The file {} already exists. Do you want to overwrite it?". format(path), default=False, ) return value else: return True if type_ in (FetchAICrypto.identifier, "all"): if _can_write(FETCHAI_PRIVATE_KEY_FILE): FetchAICrypto().dump(open(FETCHAI_PRIVATE_KEY_FILE, "wb")) if type_ in (EthereumCrypto.identifier, "all"): if _can_write(ETHEREUM_PRIVATE_KEY_FILE): EthereumCrypto().dump(open(ETHEREUM_PRIVATE_KEY_FILE, "wb"))
def setup_class(cls): """Set the test up""" cls.cwd = os.getcwd() cls.t = tempfile.mkdtemp() os.chdir(cls.t) cls.log_files = [] cls.multiplexers = [] try: temp_dir_1 = os.path.join(cls.t, "temp_dir_1") os.mkdir(temp_dir_1) cls.connection1 = _make_libp2p_connection( data_dir=temp_dir_1, agent_key=FetchAICrypto(), port=DEFAULT_PORT + 1) cls.multiplexer1 = Multiplexer( [cls.connection1], protocols=[MockDefaultMessageProtocol]) cls.log_files.append(cls.connection1.node.log_file) cls.multiplexer1.connect() cls.multiplexers.append(cls.multiplexer1) genesis_peer = cls.connection1.node.multiaddrs[0] temp_dir_2 = os.path.join(cls.t, "temp_dir_2") os.mkdir(temp_dir_2) cls.connection2 = _make_libp2p_connection( data_dir=temp_dir_2, port=DEFAULT_PORT + 2, entry_peers=[genesis_peer], agent_key=EthereumCrypto(), ) cls.multiplexer2 = Multiplexer( [cls.connection2], protocols=[MockDefaultMessageProtocol]) cls.log_files.append(cls.connection2.node.log_file) cls.multiplexer2.connect() cls.multiplexers.append(cls.multiplexer2) except Exception as e: cls.teardown_class() raise e
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 test_dump_positive(): """Test dump.""" account = EthereumCrypto(ETHEREUM_PRIVATE_KEY_PATH) account.dump(MagicMock())
def test_derive_address(): """Test the get_address_from_public_key method""" account = EthereumCrypto() address = EthereumApi.get_address_from_public_key(account.public_key) assert account.address == address, "Address derivation incorrect"
def test_creation(): """Test the creation of the crypto_objects.""" assert EthereumCrypto(), "Managed to initialise the eth_account" assert EthereumCrypto( ETHEREUM_PRIVATE_KEY_PATH), "Managed to load the eth private key"
def test_sign_message(): """Test the signing function for the eth_crypto.""" account = EthereumCrypto(PRIVATE_KEY_PATH) sign_bytes = account.sign_message('Hello') assert len(sign_bytes) > 0, "The len(signature) must not be 0"
def test_validate_address(): """Test the is_valid_address functionality.""" account = EthereumCrypto() assert EthereumApi.is_valid_address(account.address) assert not EthereumApi.is_valid_address(account.address + "wrong")