def deserialize_transaction_from_etherscan( data: Dict[str, Any], internal: bool, ) -> EthereumTransaction: """Reads dict data of a transaction from etherscan and deserializes it Can raise DeserializationError if something is wrong """ try: # internal tx list contains no gasprice gas_price = -1 if internal else read_integer(data, 'gasPrice') tx_hash = read_hash(data, 'hash') input_data = read_hash(data, 'input') timestamp = deserialize_timestamp(data['timeStamp']) block_number = read_integer(data, 'blockNumber') nonce = -1 if internal else read_integer(data, 'nonce') return EthereumTransaction( timestamp=timestamp, block_number=block_number, tx_hash=tx_hash, from_address=to_checksum_address(data['from']), to_address=to_checksum_address(data['to']) if data['to'] != '' else None, value=read_integer(data, 'value'), gas=read_integer(data, 'gas'), gas_price=gas_price, gas_used=read_integer(data, 'gasUsed'), input_data=input_data, nonce=nonce, ) except KeyError as e: raise DeserializationError(f'Etherscan ethereum transaction missing expected key {str(e)}')
def test_purge_ethereum_transaction_data(rotkehlchen_api_server): rotki = rotkehlchen_api_server.rest_api.rotkehlchen db = rotki.data.db db.add_ethereum_transactions( [EthereumTransaction( tx_hash=bytes(), timestamp=1, block_number=1, from_address=make_ethereum_address(), to_address=make_ethereum_address(), value=FVal(1), gas=FVal(1), gas_price=FVal(1), gas_used=FVal(1), input_data=bytes(), nonce=1, )], from_etherscan=True, ) assert len(db.get_ethereum_transactions()) == 1 response = requests.delete( api_url_for( rotkehlchen_api_server, "ethereumtransactionsresource", ), ) assert_simple_ok_response(response) assert len(db.get_ethereum_transactions()) == 0
def test_get_transaction_by_hash(ethereum_manager, call_order, ethereum_manager_connect_at_start): wait_until_all_nodes_connected( ethereum_manager_connect_at_start=ethereum_manager_connect_at_start, ethereum=ethereum_manager, ) result = ethereum_manager.get_transaction_by_hash( '0x5b180e3dcc19cd29c918b98c876f19393e07b74c07fd728102eb6241db3c2d5c', call_order=call_order, ) expected_tx = EthereumTransaction( tx_hash= b'[\x18\x0e=\xcc\x19\xcd)\xc9\x18\xb9\x8c\x87o\x199>\x07\xb7L\x07\xfdr\x81\x02\xebbA\xdb<-\\', # noqa: E501 timestamp=1633128954, block_number=13336285, from_address='0x2F6789A208A05C762cA8d142A3df95d29C18b065', to_address='0x7Be8076f4EA4A4AD08075C2508e481d6C946D12b', value=33000000000000000, gas=294144, gas_price=66936353558, gas_used=218523, input_data= b"\xab\x83K\xab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\xe8\x07oN\xa4\xa4\xad\x08\x07\\%\x08\xe4\x81\xd6\xc9F\xd1+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g\x89\xa2\x08\xa0\\v,\xa8\xd1B\xa3\xdf\x95\xd2\x9c\x18\xb0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x8d\xfa\x06\xdfX\x9a\x1e\x19W9\x1b\x86.\x02\xf7\x17X$\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00I_\x94rvt\x9c\xe6F\xf6\x8a\xc8\xc2HB\x00E\xcb{^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\xe8\x07oN\xa4\xa4\xad\x08\x07\\%\x08\xe4\x81\xd6\xc9F\xd1+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x8d\xfa\x06\xdfX\x9a\x1e\x19W9\x1b\x86.\x02\xf7\x17X$\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[2V\x96^|<\xf2n\x11\xfc\xaf)m\xfc\x88\x07\xc0\x10s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00I_\x94rvt\x9c\xe6F\xf6\x8a\xc8\xc2HB\x00E\xcb{^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xe2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u=S=\x96\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00aW\x91\x84\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x96\x18\xf8\xa6p,\x86\xbd?\xcf\x83\x8c3\xd3 \x89\x9f1\xffaX\x1a\r|\xa0\xcb\x12\xad\xbeY\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xe2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u=S=\x96\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00aU\xa9E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00bDI$\x9d\xc420bKZ\xb5v\x96\xf6\xef\xa0hg\x993\x00\x07y\x07]\x83\xc6\xd2I\x1c\x87\x19\x13\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x02\xe0\x9f\xaa\xce\x1aZ\xaf\\'\xb7&\x99l\x10\xe7u4\x11\xc6V\x17\xb3\xb5)z\xd5\x04/7\xd8\x04\x07y\xb1\xa8\xfe\x0c\x1c\xa5\xc9\xc4{e\x07\xa2:\xee\x0f\xb3&\xcf_3[{\xcc\x13]~o\xe9\xd1\xd8\x02\xe0\x9f\xaa\xce\x1aZ\xaf\\'\xb7&\x99l\x10\xe7u4\x11\xc6V\x17\xb3\xb5)z\xd5\x04/7\xd8\x04\x07y\xb1\xa8\xfe\x0c\x1c\xa5\xc9\xc4{e\x07\xa2:\xee\x0f\xb3&\xcf_3[{\xcc\x13]~o\xe9\xd1\xd8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\xf2BC*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g\x89\xa2\x08\xa0\\v,\xa8\xd1B\xa3\xdf\x95\xd2\x9c\x18\xb0ep\x8d\xfa\x06\xdfX\x9a\x1e\x19W9\x1b\x86.\x02\xf7\x17X$\xe9\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\xf2BC*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x8d\xfa\x06\xdfX\x9a\x1e\x19W9\x1b\x86.\x02\xf7\x17X$\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x8d\xfa\x06\xdfX\x9a\x1e\x19W9\x1b\x86.\x02\xf7\x17X$\xe9\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", # noqa: E501 nonce=204, ) assert result == expected_tx
def test_purge_ethereum_transaction_data(rotkehlchen_api_server): rotki = rotkehlchen_api_server.rest_api.rotkehlchen db = DBEthTx(rotki.data.db) db.add_ethereum_transactions([ EthereumTransaction( tx_hash=bytes(), timestamp=1, block_number=1, from_address=make_ethereum_address(), to_address=make_ethereum_address(), value=FVal(1), gas=FVal(1), gas_price=FVal(1), gas_used=FVal(1), input_data=bytes(), nonce=1, ) ], ) filter_ = ETHTransactionsFilterQuery.make() result, filter_count = db.get_ethereum_transactions(filter_) assert len(result) == 1 assert filter_count == 1 response = requests.delete( api_url_for( rotkehlchen_api_server, "ethereumtransactionsresource", ), ) assert_simple_ok_response(response) result, filter_count = db.get_ethereum_transactions(filter_) assert len(result) == 0 assert filter_count == 0
def transactions_from_dictlist( given_transactions: Dict, start_ts: Timestamp, end_ts: Timestamp, ) -> List[EthereumTransaction]: """ Gets a list of transaction, most probably read from the json files and a time period. Returns it as a list of the transaction tuples that are inside the time period """ returned_transactions = list() for given_tx in given_transactions: if given_tx['timestamp'] < start_ts: continue if given_tx['timestamp'] > end_ts: break returned_transactions.append( EthereumTransaction( timestamp=convert_to_int(given_tx['timestamp']), block_number=convert_to_int(given_tx['block_number']), hash=given_tx['hash'], from_address=given_tx['from_address'], to_address=given_tx['to_address'], value=FVal(given_tx['value']), gas=FVal(given_tx['gas']), gas_price=FVal(given_tx['gas_price']), gas_used=FVal(given_tx['gas_used']), )) return returned_transactions
def deserialize_ethereum_transaction( data: Dict[str, Any], ethereum: Optional['EthereumManager'] = None, ) -> EthereumTransaction: """Reads dict data of a transaction and deserializes it. If the transaction is not from etherscan then it's missing some data so ethereum manager is used to fetch it. Can raise DeserializationError if something is wrong """ source = 'etherscan' if ethereum is None else 'web3' try: gas_price = read_integer(data=data, key='gasPrice', api=source) tx_hash = read_hash(data=data, key='hash', api=source) input_data = read_hash(data, 'input', source) block_number = read_integer(data, 'blockNumber', source) if 'timeStamp' not in data: if ethereum is None: raise DeserializationError( 'Got in deserialize ethereum transaction without timestamp and without ethereum manager' ) # noqa: E501 block_data = ethereum.get_block_by_number(block_number) timestamp = Timestamp(read_integer(block_data, 'timestamp', source)) else: timestamp = deserialize_timestamp(data['timeStamp']) if 'gasUsed' not in data: if ethereum is None: raise DeserializationError( 'Got in deserialize ethereum transaction without gasUsed and without ethereum manager' ) # noqa: E501 receipt_data = ethereum.get_transaction_receipt(data['hash']) gas_used = read_integer(receipt_data, 'gasUsed', source) else: gas_used = read_integer(data, 'gasUsed', source) nonce = read_integer(data, 'nonce', source) return EthereumTransaction( timestamp=timestamp, block_number=block_number, tx_hash=tx_hash, from_address=deserialize_ethereum_address(data['from']), to_address=deserialize_ethereum_address(data['to']) if data['to'] != '' else None, value=read_integer(data, 'value', source), gas=read_integer(data, 'gas', source), gas_price=gas_price, gas_used=gas_used, input_data=input_data, nonce=nonce, ) except KeyError as e: raise DeserializationError( f'ethereum transaction from {source} missing expected key {str(e)}', ) from e
def get_ethereum_transactions( self, filter_: ETHTransactionsFilterQuery, ) -> Tuple[List[EthereumTransaction], int]: """Returns a tuple with 2 entries. First entry is a list of ethereum transactions optionally filtered by time and/or from address and pagination. Second is the number of entries found for the current filter ignoring pagination. This function can raise: - pysqlcipher3.dbapi2.OperationalError if the SQL query fails due to invalid filtering arguments. """ cursor = self.db.conn.cursor() query, bindings = filter_.prepare() query = 'SELECT * FROM ethereum_transactions ' + query results = cursor.execute(query, bindings) ethereum_transactions = [] for result in results: try: tx = EthereumTransaction( tx_hash=result[0], timestamp=deserialize_timestamp(result[1]), block_number=result[2], from_address=result[3], to_address=result[4], value=int(result[5]), gas=int(result[6]), gas_price=int(result[7]), gas_used=int(result[8]), input_data=result[9], nonce=result[10], ) except DeserializationError as e: self.db.msg_aggregator.add_error( f'Error deserializing ethereum transaction from the DB. ' f'Skipping it. Error was: {str(e)}', ) continue ethereum_transactions.append(tx) if filter_.pagination is not None: no_pagination_filter = deepcopy(filter_) no_pagination_filter.pagination = None query, bindings = no_pagination_filter.prepare() query = 'SELECT COUNT(*) FROM ethereum_transactions ' + query results = cursor.execute(query, bindings).fetchone() total_filter_count = results[0] else: total_filter_count = len(ethereum_transactions) return ethereum_transactions, total_filter_count
def transactions_from_dictlist( given_transactions: List[Dict[str, Any]], start_ts: Timestamp, end_ts: Timestamp, ) -> List[EthereumTransaction]: """ Gets a list of transaction, most probably read from the json files and a time period. Returns it as a list of the transaction tuples that are inside the time period May raise: - KeyError: If the given_transactions contain data in an unexpected format """ returned_transactions = list() for given_tx in given_transactions: if given_tx['timestamp'] < start_ts: continue if given_tx['timestamp'] > end_ts: break timestamp = Timestamp(convert_to_int(given_tx['timestamp'])) tx_hash = given_tx['hash'] from_address = given_tx['from_address'] to_address = given_tx['to_address'] value = FVal(given_tx['value']) gas = FVal(given_tx['gas']) gas_price = FVal(given_tx['gas_price']) gas_used = FVal(given_tx['gas_used']) log.debug( 'Processing eth transaction', sensitive_log=True, timestamp=timestamp, eth_tx_hash=tx_hash, from_eth_address=from_address, to_eth_address=to_address, tx_value=value, gas=gas, gas_price=gas_price, gas_used=gas_used, ) returned_transactions.append( EthereumTransaction( timestamp=timestamp, block_number=convert_to_int(given_tx['block_number']), hash=tx_hash, from_address=from_address, to_address=to_address, value=value, gas=gas, gas_price=gas_price, gas_used=gas_used, )) return returned_transactions
def test_not_include_gas_costs(accountant): """ Added ignored assets here only to have a test for https://github.com/rotki/rotki/issues/399 """ history = [{ 'timestamp': 1476979735, 'base_asset': 'BTC', 'quote_asset': 'EUR', 'trade_type': 'buy', 'rate': 578.505, 'fee': 0.0012, 'fee_currency': 'BTC', 'amount': 5, 'location': 'kraken', }, { 'timestamp': 1496979735, 'base_asset': 'BTC', 'quote_asset': 'EUR', 'trade_type': 'sell', 'rate': 2519.62, 'fee': 0.02, 'fee_currency': 'EUR', 'amount': 1, 'location': 'kraken', }] eth_tx_list = [ EthereumTransaction( timestamp=1491062063, # 01/04/2017 block_number=3458409, tx_hash=DUMMY_HASH, from_address=DUMMY_ADDRESS, to_address=DUMMY_ADDRESS, value=FVal('12323'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('1000000'), input_data=DUMMY_HASH, nonce=0, ), ] result = accounting_history_process( accountant, 1436979735, 1519693374, history, eth_transaction_list=eth_tx_list, ) assert FVal(result['overview']['total_taxable_profit_loss']).is_close( '1940.9561588')
def query_ethereum_txlist( address: EthAddress, internal: bool, from_block: int = None, to_block: int = None, ) -> List[EthereumTransaction]: result = list() if internal: reqstring = ('https://api.etherscan.io/api?module=account&action=' 'txlistinternal&address={}'.format(address)) else: reqstring = ('https://api.etherscan.io/api?module=account&action=' 'txlist&address={}'.format(address)) if from_block: reqstring += '&startblock={}'.format(from_block) if to_block: reqstring += '&endblock={}'.format(to_block) resp = request_get(reqstring) if 'status' not in resp or convert_to_int(resp['status']) != 1: status = convert_to_int(resp['status']) if status == 0 and resp['message'] == 'No transactions found': return list() # else unknown error raise ValueError( 'Failed to query txlist from etherscan with query: {} . ' 'Response was: {}'.format(reqstring, resp)) for v in resp['result']: # internal tx list contains no gasprice gas_price = FVal(-1) if internal else FVal(v['gasPrice']) result.append( EthereumTransaction( timestamp=convert_to_int(v['timeStamp']), block_number=convert_to_int(v['blockNumber']), hash=v['hash'], from_address=v['from'], to_address=v['to'], value=FVal(v['value']), gas=FVal(v['gas']), gas_price=gas_price, gas_used=FVal(v['gasUsed']), )) return result
def test_deserialize_transaction_from_etherscan(): # Make sure that a missing to address due to contract creation is handled data = {'blockNumber': 54092, 'timeStamp': 1439048640, 'hash': '0x9c81f44c29ff0226f835cd0a8a2f2a7eca6db52a711f8211b566fd15d3e0e8d4', 'nonce': 0, 'blockHash': '0xd3cabad6adab0b52ea632c386ea19403680571e682c62cb589b5abcd76de2159', 'transactionIndex': 0, 'from': '0x5153493bB1E1642A63A098A65dD3913daBB6AE24', 'to': '', 'value': 11901464239480000000000000, 'gas': 2000000, 'gasPrice': 10000000000000, 'isError': 0, 'txreceipt_status': '', 'input': '0x313233', 'contractAddress': '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae', 'cumulativeGasUsed': 1436963, 'gasUsed': 1436963, 'confirmations': 8569454} # noqa: E501 transaction = deserialize_transaction_from_etherscan(data, internal=False) assert transaction == EthereumTransaction( tx_hash=bytes.fromhex(data['hash'][2:]), timestamp=1439048640, block_number=54092, from_address='0x5153493bB1E1642A63A098A65dD3913daBB6AE24', to_address=None, value=11901464239480000000000000, gas=2000000, gas_price=10000000000000, gas_used=1436963, input_data=bytes.fromhex(data['input'][2:]), nonce=0, )
def test_query_transactions_from_to_address( rotkehlchen_api_server, ethereum_accounts, ): """Make sure that if a transaction is just being sent to an address it's also returned.""" start_ts = 0 end_ts = 1598453214 rotki = rotkehlchen_api_server.rest_api.rotkehlchen db = rotki.data.db transactions = [ EthereumTransaction( tx_hash=b'1', timestamp=0, block_number=0, from_address=ethereum_accounts[0], to_address=make_ethereum_address(), value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=0, ), EthereumTransaction( tx_hash=b'2', timestamp=0, block_number=0, from_address=ethereum_accounts[0], to_address=ethereum_accounts[1], value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=1, ), EthereumTransaction( tx_hash=b'3', timestamp=0, block_number=0, from_address=make_ethereum_address(), to_address=ethereum_accounts[0], value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=55, ) ] dbethtx = DBEthTx(db) dbethtx.add_ethereum_transactions(transactions) # Also make sure to update query ranges so as not to query etherscan at all for address in ethereum_accounts: DBQueryRanges(db).update_used_query_range( location_string=f'ethtxs_{address}', start_ts=start_ts, end_ts=end_ts, ranges_to_query=[], ) expected_entries = {ethereum_accounts[0]: 3, ethereum_accounts[1]: 1} # Check that we get all transactions correctly even if we query two times for _ in range(2): for address in ethereum_accounts: response = requests.get( api_url_for( rotkehlchen_api_server, 'ethereumtransactionsresource', ), json={ 'from_timestamp': start_ts, 'to_timestamp': end_ts, 'address': address }, ) result = assert_proper_response_with_result(response) assert len(result['entries']) == expected_entries[address] assert result['entries_limit'] == FREE_ETH_TX_LIMIT assert result['entries_found'] == expected_entries[address] assert result['entries_total'] == 3
def test_query_transactions_over_limit( rotkehlchen_api_server, ethereum_accounts, start_with_valid_premium, ): start_ts = 0 end_ts = 1598453214 rotki = rotkehlchen_api_server.rest_api.rotkehlchen db = rotki.data.db all_transactions_num = FREE_ETH_TX_LIMIT + 50 transactions = [ EthereumTransaction( tx_hash=x.to_bytes(2, byteorder='little'), timestamp=x, block_number=x, from_address=ethereum_accounts[0], to_address=make_ethereum_address(), value=x, gas=x, gas_price=x, gas_used=x, input_data=x.to_bytes(2, byteorder='little'), nonce=x, ) for x in range(FREE_ETH_TX_LIMIT - 10) ] transactions.extend([ EthereumTransaction( tx_hash=(x + 500).to_bytes(2, byteorder='little'), timestamp=x, block_number=x, from_address=ethereum_accounts[1], to_address=make_ethereum_address(), value=x, gas=x, gas_price=x, gas_used=x, input_data=x.to_bytes(2, byteorder='little'), nonce=x, ) for x in range(60) ]) dbethtx = DBEthTx(db) dbethtx.add_ethereum_transactions(transactions) # Also make sure to update query ranges so as not to query etherscan at all for address in ethereum_accounts: DBQueryRanges(db).update_used_query_range( location_string=f'ethtxs_{address}', start_ts=start_ts, end_ts=end_ts, ranges_to_query=[], ) free_expected_entries_total = [FREE_ETH_TX_LIMIT - 10, 10] free_expected_entries_found = [FREE_ETH_TX_LIMIT - 10, 60] premium_expected_entries = [FREE_ETH_TX_LIMIT - 10, 60] # Check that we get all transactions correctly even if we query two times for _ in range(2): response = requests.post( api_url_for( rotkehlchen_api_server, 'limitscounterresetresource', location='ethereum_transactions', ), ) assert_simple_ok_response(response) for idx, address in enumerate(ethereum_accounts): response = requests.get( api_url_for( rotkehlchen_api_server, 'ethereumtransactionsresource', ), json={ 'from_timestamp': start_ts, 'to_timestamp': end_ts, 'address': address }, ) result = assert_proper_response_with_result(response) if start_with_valid_premium: assert len(result['entries']) == premium_expected_entries[idx] assert result['entries_total'] == all_transactions_num assert result['entries_found'] == premium_expected_entries[idx] assert result['entries_limit'] == -1 else: assert len( result['entries']) == free_expected_entries_total[idx] assert result['entries_total'] == all_transactions_num assert result['entries_found'] == free_expected_entries_found[ idx] assert result['entries_limit'] == FREE_ETH_TX_LIMIT
def test_get_transaction_receipt( ethereum_manager, call_order, ethereum_manager_connect_at_start, database, ): wait_until_all_nodes_connected( ethereum_manager_connect_at_start=ethereum_manager_connect_at_start, ethereum=ethereum_manager, ) tx_hash = '0x12d474b6cbba04fd1a14e55ef45b1eb175985612244631b4b70450c888962a89' result = ethereum_manager.get_transaction_receipt(tx_hash, call_order=call_order) block_hash = '0x6f3a7838a8788c3371b88df170c3643d19bad896c915a7368681292882b6ad61' assert result['blockHash'] == block_hash assert len(result['logs']) == 2 assert result['gasUsed'] == 144046 assert result['blockNumber'] == 10840714 assert result['logs'][0]['blockNumber'] == 10840714 assert result['logs'][1]['blockNumber'] == 10840714 assert result['status'] == 1 assert result['transactionIndex'] == 110 assert result['logs'][0]['transactionIndex'] == 110 assert result['logs'][1]['transactionIndex'] == 110 assert result['logs'][0]['logIndex'] == 235 assert result['logs'][1]['logIndex'] == 236 tx_hash_bytes = hexstring_to_bytes(tx_hash) db = DBEthTx(database) db.add_ethereum_transactions([ EthereumTransaction( # need to add the tx first tx_hash=tx_hash_bytes, timestamp=1, # all other fields don't matter for this test block_number=1, from_address='0x0', to_address='0x0', value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=1, ) ]) # also test receipt can be stored and retrieved from the DB. # This tests that all node types (say openethereum) are processed properly db.add_receipt_data(result) receipt = db.get_receipt(tx_hash_bytes) assert receipt == EthereumTxReceipt( tx_hash=tx_hash_bytes, contract_address=None, status=True, type=0, logs=[ EthereumTxReceiptLog( log_index=235, data= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00', # noqa: E501 address='0x5bEaBAEBB3146685Dd74176f68a0721F91297D37', removed=False, topics=[ b'\xdd\xf2R\xad\x1b\xe2\xc8\x9bi\xc2\xb0h\xfc7\x8d\xaa\x95+\xa7\xf1c\xc4\xa1\x16(\xf5ZM\xf5#\xb3\xef', # noqa: E501 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s(*c\xf0\xe3\xd7\xe9`EuB\x0fwsa\xec\xa3\xc8j', # noqa: E501 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5', # noqa: E501 ]), EthereumTxReceiptLog( log_index=236, data= b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6 \xf1\x93ME\x84\xdd\xa6\x99\x9e\xdc\xad\xd3)\x81)dj\xa5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\xea\xba\xeb\xb3\x14f\x85\xddt\x17oh\xa0r\x1f\x91)}7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02T\x0b\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\xe0\xb6\xb3\xa7d\x00\x00', # noqa: E501 address='0x73282A63F0e3D7e9604575420F777361ecA3C86A', removed=False, topics=[ b'\xd6\xd4\xf5h\x1c$l\x9fB\xc2\x03\xe2\x87\x97Z\xf1`\x1f\x8d\xf8\x03Z\x92Q\xf7\x9a\xab\\\x8f\t\xe2\xf8' ], # noqa: E501 ), ])
def test_add_ethereum_transactions(data_dir, username): """Test that adding and retrieving ethereum transactions from the DB works fine. Also duplicates should be ignored and an error returned """ msg_aggregator = MessagesAggregator() data = DataHandler(data_dir, msg_aggregator) data.unlock(username, '123', create_new=True) tx1 = EthereumTransaction( tx_hash=b'1', timestamp=Timestamp(1451606400), block_number=1, from_address=ETH_ADDRESS1, to_address=ETH_ADDRESS3, value=FVal('2000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=1, ) tx2 = EthereumTransaction( tx_hash=b'2', timestamp=Timestamp(1451706400), block_number=3, from_address=ETH_ADDRESS2, to_address=ETH_ADDRESS3, value=FVal('4000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=1, ) tx3 = EthereumTransaction( tx_hash=b'3', timestamp=Timestamp(1452806400), block_number=5, from_address=ETH_ADDRESS3, to_address=ETH_ADDRESS1, value=FVal('1000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=3, ) # Add and retrieve the first 2 margins. All should be fine. data.db.add_ethereum_transactions([tx1, tx2], from_etherscan=True) errors = msg_aggregator.consume_errors() warnings = msg_aggregator.consume_warnings() assert len(errors) == 0 assert len(warnings) == 0 returned_transactions = data.db.get_ethereum_transactions() assert returned_transactions == [tx1, tx2] # Add the last 2 transactions. Since tx2 already exists in the DB it should be # ignored (no errors shown for attempting to add already existing transaction) data.db.add_ethereum_transactions([tx2, tx3], from_etherscan=True) errors = msg_aggregator.consume_errors() warnings = msg_aggregator.consume_warnings() assert len(errors) == 0 assert len(warnings) == 0 returned_transactions = data.db.get_ethereum_transactions() assert returned_transactions == [tx1, tx2, tx3]
def setup_ethereum_transactions_test( database: DBHandler, transaction_already_queried: bool, one_receipt_in_db: bool = False, ) -> Tuple[List[EthereumTransaction], List[EthereumTxReceipt]]: dbethtx = DBEthTx(database) tx_hash1 = '0x692f9a6083e905bdeca4f0293f3473d7a287260547f8cbccc38c5cb01591fcda' tx_hash1_b = hexstring_to_bytes(tx_hash1) transaction1 = EthereumTransaction( tx_hash=tx_hash1_b, timestamp=Timestamp(1630532276), block_number=13142218, from_address=string_to_ethereum_address( '0x443E1f9b1c866E54e914822B7d3d7165EdB6e9Ea'), to_address=string_to_ethereum_address( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'), value=int(10 * 10**18), gas=194928, gas_price=int(0.000000204 * 10**18), gas_used=136675, input_data=hexstring_to_bytes( '0x7ff36ab5000000000000000000000000000000000000000000000367469995d0723279510000000000000000000000000000000000000000000000000000000000000080000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea00000000000000000000000000000000000000000000000000000000612ff9b50000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000002a3bff78b79a009976eea096a51a948a3dc00e34' ), # noqa: E501 nonce=13, ) tx_hash2 = '0x6beab9409a8f3bd11f82081e99e856466a7daf5f04cca173192f79e78ed53a77' tx_hash2_b = hexstring_to_bytes(tx_hash2) transaction2 = EthereumTransaction( tx_hash=tx_hash2_b, timestamp=Timestamp(1631013757), block_number=13178342, from_address=string_to_ethereum_address( '0x442068F934BE670aDAb81242C87144a851d56d16'), to_address=string_to_ethereum_address( '0xEaDD9B69F96140283F9fF75DA5FD33bcF54E6296'), value=0, gas=77373, gas_price=int(0.000000100314697497 * 10**18), gas_used=46782, input_data=hexstring_to_bytes( '0xa9059cbb00000000000000000000000020c8032d4f7d4a380385f87aeadf05bed84504cb000000000000000000000000000000000000000000000000000000003b9deec6' ), # noqa: E501 nonce=3, ) transactions = [transaction1, transaction2] if transaction_already_queried is True: dbethtx.add_ethereum_transactions(ethereum_transactions=transactions) result, _ = dbethtx.get_ethereum_transactions( ETHTransactionsFilterQuery.make()) assert result == transactions expected_receipt1 = EthereumTxReceipt( tx_hash=tx_hash1_b, contract_address=None, status=True, type=0, logs=[ EthereumTxReceiptLog( log_index=295, data=hexstring_to_bytes( '0x0000000000000000000000000000000000000000000000008ac7230489e80000' ), # noqa: E501 address=string_to_ethereum_address( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), removed=False, topics=[ hexstring_to_bytes( '0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=296, data=hexstring_to_bytes( '0x0000000000000000000000000000000000000000000000008ac7230489e80000' ), # noqa: E501 address=string_to_ethereum_address( '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000caa004418eb42cdf00cb057b7c9e28f0ffd840a5' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=297, data=hexstring_to_bytes( '0x00000000000000000000000000000000000000000000036ba1d53baeeda5ed20' ), # noqa: E501 address=string_to_ethereum_address( '0x2a3bFF78B79A009976EeA096a51A948a3dC00e34'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000caa004418eb42cdf00cb057b7c9e28f0ffd840a5' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea' ), # noqa: E501 ], ), EthereumTxReceiptLog( log_index=298, data=hexstring_to_bytes( '0x000000000000000000000000000000000000000000007b6ea033189ba7d047e30000000000000000000000000000000000000000000000140bc8194dd0f5e4be' ), # noqa: E501 address=string_to_ethereum_address( '0xcaA004418eB42cdf00cB057b7C9E28f0FfD840a5'), removed=False, topics=[ hexstring_to_bytes( '0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1' ) ], # noqa: E501 ), EthereumTxReceiptLog( log_index=299, data=hexstring_to_bytes( '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000036ba1d53baeeda5ed200000000000000000000000000000000000000000000000000000000000000000' ), # noqa: E501 address=string_to_ethereum_address( '0xcaA004418eB42cdf00cB057b7C9E28f0FfD840a5'), removed=False, topics=[ hexstring_to_bytes( '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822' ), # noqa: E501 hexstring_to_bytes( '0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000443e1f9b1c866e54e914822b7d3d7165edb6e9ea' ), # noqa: E501 ], ), ], ) expected_receipt2 = EthereumTxReceipt( tx_hash=tx_hash2_b, contract_address=None, status=True, type=2, logs=[ EthereumTxReceiptLog( log_index=438, data=hexstring_to_bytes( '0x000000000000000000000000000000000000000000000000000000003b9deec6' ), # noqa: E501 address=string_to_ethereum_address( '0xEaDD9B69F96140283F9fF75DA5FD33bcF54E6296'), removed=False, topics=[ hexstring_to_bytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ), # noqa: E501 hexstring_to_bytes( '0x000000000000000000000000442068f934be670adab81242c87144a851d56d16' ), # noqa: E501 hexstring_to_bytes( '0x00000000000000000000000020c8032d4f7d4a380385f87aeadf05bed84504cb' ), # noqa: E501 ], ), ], ) if one_receipt_in_db: dbethtx.add_receipt_data(txreceipt_to_data(expected_receipt1)) return transactions, [expected_receipt1, expected_receipt2]
def test_query_transactions_removed_address( rotkehlchen_api_server, ethereum_accounts, ): """Make sure that if an address is removed so are the transactions from the DB""" start_ts = 0 end_ts = 1598453214 rotki = rotkehlchen_api_server.rest_api.rotkehlchen db = rotki.data.db transactions = [ EthereumTransaction( tx_hash=b'1', timestamp=0, block_number=0, from_address=ethereum_accounts[0], to_address=make_ethereum_address(), value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=0, ), EthereumTransaction( tx_hash=b'2', timestamp=0, block_number=0, from_address=ethereum_accounts[0], to_address=make_ethereum_address(), value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=1, ), EthereumTransaction( # should remain after deletining account[0] tx_hash=b'3', timestamp=0, block_number=0, from_address=make_ethereum_address(), to_address=ethereum_accounts[1], value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=55, ), EthereumTransaction( # should remain after deletining account[0] tx_hash=b'4', timestamp=0, block_number=0, from_address=ethereum_accounts[1], to_address=ethereum_accounts[0], value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=0, ), EthereumTransaction( # should remain after deletining account[0] tx_hash=b'5', timestamp=0, block_number=0, from_address=ethereum_accounts[0], to_address=ethereum_accounts[1], value=1, gas=1, gas_price=1, gas_used=1, input_data=b'', nonce=0, ) ] dbethtx = DBEthTx(db) dbethtx.add_ethereum_transactions(transactions) # Also make sure to update query ranges so as not to query etherscan at all for address in ethereum_accounts: DBQueryRanges(db).update_used_query_range( location_string=f'ethtxs_{address}', start_ts=start_ts, end_ts=end_ts, ranges_to_query=[], ) # Now remove the first account (do the mocking to not query etherscan for balances) setup = setup_balances( rotki, ethereum_accounts=ethereum_accounts, btc_accounts=[], eth_balances=['10000', '10000'], ) with ExitStack() as stack: setup.enter_ethereum_patches(stack) response = requests.delete(api_url_for( rotkehlchen_api_server, "blockchainsaccountsresource", blockchain='ETH', ), json={'accounts': [ethereum_accounts[0]]}) assert_proper_response_with_result(response) # Check that only the 3 remanining transactions from the other account is returned response = requests.get( api_url_for( rotkehlchen_api_server, 'ethereumtransactionsresource', ), ) result = assert_proper_response_with_result(response) assert len(result['entries']) == 3 assert result['entries_found'] == 3
amount=FVal('120'), fee_asset=A_ETH, fee=Fee(FVal('0.001')), link='bittrexid1', ) ] eth_tx_list = [ # before query period: ((2000000000 * 25000000) / (10 ** 18)) * 9.185 = 0.45925 EthereumTransaction( timestamp=Timestamp(1463184190), # 14/05/2016 block_number=1512689, # cryptocompare hourtly ETH/EUR: 9.186 tx_hash=b'1', from_address=ETH_ADDRESS1, to_address=ETH_ADDRESS3, value=FVal('12323'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=DUMMY_HASH, nonce=0, ), EthereumTransaction( # ((2000000000 * 1000000) / (10 ** 18)) * 47.5 = 0.095 timestamp=Timestamp(1491062063), # 01/04/2017 block_number=3458409, # cryptocompare hourly ETH/EUR: 47.5 tx_hash=b'2', from_address=ETH_ADDRESS2, to_address=ETH_ADDRESS3, value=FVal('12323'), gas=FVal('5000000'), gas_price=FVal('2000000000'),
def test_add_ethereum_transactions(data_dir, username): """Test that adding and retrieving ethereum transactions from the DB works fine. Also duplicates should be ignored and an error returned """ msg_aggregator = MessagesAggregator() data = DataHandler(data_dir, msg_aggregator) data.unlock(username, '123', create_new=True) tx2_hash_b = b'.h\xdd\x82\x85\x94\xeaq\xfe\n\xfc\xcf\xadwH\xc9\x0f\xfc\xd0\xf1\xad\xd4M\r$\x9b\xf7\x98\x87\xda\x93\x18' # noqa: E501 tx2_hash = '0x2e68dd828594ea71fe0afccfad7748c90ffcd0f1add44d0d249bf79887da9318' tx1 = EthereumTransaction( tx_hash=b'1', timestamp=Timestamp(1451606400), block_number=1, from_address=ETH_ADDRESS1, to_address=ETH_ADDRESS3, value=FVal('2000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=1, ) tx2 = EthereumTransaction( tx_hash=tx2_hash_b, timestamp=Timestamp(1451706400), block_number=3, from_address=ETH_ADDRESS2, to_address=ETH_ADDRESS3, value=FVal('4000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=1, ) tx3 = EthereumTransaction( tx_hash=b'3', timestamp=Timestamp(1452806400), block_number=5, from_address=ETH_ADDRESS3, to_address=ETH_ADDRESS1, value=FVal('1000000'), gas=FVal('5000000'), gas_price=FVal('2000000000'), gas_used=FVal('25000000'), input_data=MOCK_INPUT_DATA, nonce=3, ) # Add and retrieve the first 2 margins. All should be fine. dbethtx = DBEthTx(data.db) dbethtx.add_ethereum_transactions([tx1, tx2]) errors = msg_aggregator.consume_errors() warnings = msg_aggregator.consume_warnings() assert len(errors) == 0 assert len(warnings) == 0 filter_query = ETHTransactionsFilterQuery.make() returned_transactions, _ = dbethtx.get_ethereum_transactions(filter_query) assert returned_transactions == [tx1, tx2] # Add the last 2 transactions. Since tx2 already exists in the DB it should be # ignored (no errors shown for attempting to add already existing transaction) dbethtx.add_ethereum_transactions([tx2, tx3]) errors = msg_aggregator.consume_errors() warnings = msg_aggregator.consume_warnings() assert len(errors) == 0 assert len(warnings) == 0 returned_transactions, _ = dbethtx.get_ethereum_transactions(filter_query) assert returned_transactions == [tx1, tx2, tx3] # try transaction query by tx_hash result, _ = dbethtx.get_ethereum_transactions( ETHTransactionsFilterQuery.make(tx_hash=tx2_hash_b)) # noqa: E501 assert result == [tx2], 'querying transaction by hash in bytes failed' result, _ = dbethtx.get_ethereum_transactions( ETHTransactionsFilterQuery.make(tx_hash=tx2_hash)) # noqa: E501 assert result == [tx2], 'querying transaction by hash string failed' result, _ = dbethtx.get_ethereum_transactions( ETHTransactionsFilterQuery.make(tx_hash=b'dsadsad')) # noqa: E501 assert result == []