PKbK\^^iotapy/__init__.py"""A Pure-Python implementation of IOTA node""" import iotapy.storage __version__ = '0.1.2' PKqbK((iotapy/iota.py# -*- coding: utf-8 -*- class Iota: def __init__(self, **kwargs): self.configuration = kwargs self.testnet = kwargs.get('testnet') self.max_peers = kwargs.get('max_peers') self.udp_port = kwargs.get('udp_port') self.tcp_port = kwargs.get('tcp_port') PKpXKBw`BB iotapy/iri.py# -*- coding: utf-8 -*- class IRI: MAINNET_COORDINATOR = '' PKnbK-.VViotapy/storage/__init__.py# -*- coding: utf-8 -*- import iotapy.storage.tangle import iotapy.storage.converter PKbK,jIIiotapy/storage/converter.py# -*- coding: utf-8 -*- RADIX = 3 BYTE_RADIX = 256 MAX_TRIT_VALUE = (RADIX - 1) // 2 MIN_TRIT_VALUE = -MAX_TRIT_VALUE NUMBER_OF_TRITS_IN_A_BYTE = 5 NUMBER_OF_TRITS_IN_A_TRYTE = 3 HASH_LENGTH = 243 BYTE_TO_TRITS_MAPPINGS = [[]] * HASH_LENGTH TRYTE_TO_TRITS_MAPPINGS = [[]] * 27 HIGH_INTEGER_BITS = 0xFFFFFFFF HIGH_LONG_BITS = 0xFFFFFFFFFFFFFFFF TRYTE_ALPHABET = '9ABCDEFGHIJKLMNOPQRSTUVWXYZ' MIN_TRYTE_VALUE = -13 MAX_TRYTE_VALUE = 13 def increment(trits, length): for i in range(length): trits[i] += 1 if trits[i] > MAX_TRIT_VALUE: trits[i] = MIN_TRIT_VALUE else: break def init_converter(): global BYTE_TO_TRITS_MAPPINGS, TRYTE_TO_TRITS_MAPPINGS trits = [0] * NUMBER_OF_TRITS_IN_A_BYTE for i in range(HASH_LENGTH): BYTE_TO_TRITS_MAPPINGS[i] = trits[:NUMBER_OF_TRITS_IN_A_BYTE] increment(trits, NUMBER_OF_TRITS_IN_A_BYTE) for i in range(27): TRYTE_TO_TRITS_MAPPINGS[i] = trits[:NUMBER_OF_TRITS_IN_A_TRYTE] increment(trits, NUMBER_OF_TRITS_IN_A_TRYTE) def from_trits_to_binary(trits, offset=0, size=HASH_LENGTH): b = bytearray(b' ' * int((size + NUMBER_OF_TRITS_IN_A_BYTE - 1) / NUMBER_OF_TRITS_IN_A_BYTE)) for i in range(len(b)): value = 0 for j in range(size - i * NUMBER_OF_TRITS_IN_A_BYTE - 1 if (size - i * NUMBER_OF_TRITS_IN_A_BYTE) < NUMBER_OF_TRITS_IN_A_BYTE else 4, -1, -1): value = value * RADIX + trits[offset + i * NUMBER_OF_TRITS_IN_A_BYTE + j] b[i] = value % 256 return bytes(b) def from_binary_to_trits(bs, length): offset = 0 trits = [0] * length for i in range(min(len(bs), length)): # We must convert the binary data # because java using different range with Python index = bs[i] if bs[i] < 127 else bs[i] - 256 + HASH_LENGTH copy_len = length - offset if length - offset < NUMBER_OF_TRITS_IN_A_BYTE else NUMBER_OF_TRITS_IN_A_BYTE trits[offset: offset + copy_len] = BYTE_TO_TRITS_MAPPINGS[index][:copy_len] offset += NUMBER_OF_TRITS_IN_A_BYTE return trits init_converter() PKbKliotapy/storage/tangle.py# -*- coding: utf-8 -*- import iota from iotapy.storage.providers import rocksdb class Tangle: def __init__(self): self.provider = rocksdb.RocksDBProvider() self.provider.init() def get(self, key, column): return self.provider.get(key, column) PKhbK$iotapy/storage/providers/__init__.pyPKdbKRD#iotapy/storage/providers/rocksdb.py# -*- coding: utf-8 -*- import struct import iota import rocksdb_iota import iotapy.storage.providers.types from rocksdb_iota.merge_operators import StringAppendOperator from iotapy.storage import converter KB = 1024 MB = KB * 1024 class RocksDBProvider: BLOOM_FILTER_BITS_PER_KEY = 10 column_family_names = [ b'default', b'transaction', b'transaction-metadata', b'milestone', b'stateDiff', b'address', b'approvee', b'bundle', b'tag' ] column_family_python_mapping = { 'transaction_metadata': 'transaction-metadata', 'state_diff': 'stateDiff' } def __init__(self, db_path, db_log_path, cache_size=4096, read_only=True): self.db = None self.db_path = db_path self.db_log_path = db_log_path self.cache_size = cache_size self.read_only = read_only self.available = False def init(self): self.init_db(self.db_path, self.db_log_path) self.available = True def init_db(self, db_path, db_log_path): options = rocksdb_iota.Options( create_if_missing=True, db_log_dir=db_log_path, max_log_file_size=MB, max_manifest_file_size=MB, max_open_files=10000, max_background_compactions=1 ) options.allow_concurrent_memtable_write = True # XXX: How to use this? block_based_table_config = rocksdb_iota.BlockBasedTableFactory( filter_policy=rocksdb_iota.BloomFilterPolicy(self.BLOOM_FILTER_BITS_PER_KEY), block_size_deviation=10, block_restart_interval=16, block_cache=rocksdb_iota.LRUCache(self.cache_size * KB), block_cache_compressed=rocksdb_iota.LRUCache(32 * KB, shard_bits=10)) options.table_factory = block_based_table_config # XXX: How to use this? column_family_options = rocksdb_iota.ColumnFamilyOptions( merge_operator=StringAppendOperator(), table_factory=block_based_table_config, max_write_buffer_number=2, write_buffer_size=2 * MB) self.db = rocksdb_iota.DB(self.db_path, options, self.column_family_names, read_only=self.read_only) def _convert_column_to_handler(self, column): if not isinstance(column, str): raise TypeError('Column type should be str') db_column = self.column_family_python_mapping.get(column, column) ch = self.db.column_family_handles.get(bytes(db_column, 'ascii')) if ch is None: raise KeyError('Invalid column family name: %s' % (column)) return ch def _convert_key_column(self, key, column): # Convert column to column family handler ch = self._convert_column_to_handler(column) # Expand iota.Tag to iota.Hash if column == 'tag': if not isinstance(key, iota.Tag): raise TypeError('Tag key type should be iota.Tag') key = iota.Hash(str(key)) # Convert key into trits-binary if column == 'milestone': if not isinstance(key, int): raise TypeError('Milestone key type should be int') key = struct.pack('>l', key) else: if not isinstance(key, iota.TryteString): raise TypeError('Key type should be iota.TryteString') if len(key) != iota.Hash.LEN: raise ValueError('Key length must be 81 trytes') key = converter.from_trits_to_binary(key.as_trits()) return key, ch def _get(self, bytes_, column): # Convert value (bytes_) into data object return getattr(iotapy.storage.providers.types, column).get(bytes_) def _get_key(self, bytes_, column): return getattr(iotapy.storage.providers.types, column).get_key(bytes_) def get(self, key, column): key, ch = self._convert_key_column(key, column) # Get binary data from database bytes_ = self.db.get(key, ch) if not bytes_: return None return self._get(bytes_, column) def next(self, key, column): key, ch = self._convert_key_column(key, column) it = self.db.iteritems(ch) it.seek(key) next(it) # XXX: We will get segfault if this is NULL in database key, bytes_ = it.get() if not bytes_: return None # Convert into data object return self._get_key(key, column), self._get(bytes_, column) def first(self, column): ch = self._convert_column_to_handler(column) it = self.db.iteritems(ch) it.seek_to_first() # XXX: We will get segfault if this is NULL in database key, bytes_ = it.get() if not bytes_: return None # Convert into data object return self._get_key(key, column), self._get(bytes_, column) def latest(self, column): ch = self._convert_column_to_handler(column) it = self.db.iteritems(ch) it.seek_to_last() # XXX: We will get segfault if this is NULL in database key, bytes_ = it.get() if not bytes_: return None # Convert into data object return self._get_key(key, column), self._get(bytes_, column) def may_exist(self, key, column, fetch=False): key, ch = self._convert_key_column(key, column) # XXX: Not working...... return self.db.key_may_exist(key, ch)[0] PKbbKiotapy/storage/providers/zmq.pyPK5bKƬk*iotapy/storage/providers/types/__init__.py# -*- coding: utf-8 -*- import iotapy.storage.providers.types.address import iotapy.storage.providers.types.approvee import iotapy.storage.providers.types.bundle import iotapy.storage.providers.types.milestone import iotapy.storage.providers.types.state_diff import iotapy.storage.providers.types.tag import iotapy.storage.providers.types.transaction import iotapy.storage.providers.types.transaction_metadata __all__ = ['address', 'approvee', 'bundle', 'milestone', 'state_diff', 'tag',' transaction', 'transaction_metadata'] PKbKҘ)iotapy/storage/providers/types/address.py# -*- coding: utf-8 -*- import iota from iotapy.storage import converter HASH_TRITS_LENGTH = 243 HASH_BYTES_LENGTH = 49 def get_key(bytes_: bytes): # Convert key bytes to iota.Address if not isinstance(bytes_, bytes): raise TypeError key = iota.Address.from_trits(converter.from_binary_to_trits(bytes_, HASH_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError for i in range(0, len(bytes_), HASH_BYTES_LENGTH + 1): ti = converter.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH) yield iota.types.TransactionHash.from_trits(ti) PKbKQ*iotapy/storage/providers/types/approvee.py# -*- coding: utf-8 -*- import iota from iotapy.storage import converter HASH_TRITS_LENGTH = 243 HASH_BYTES_LENGTH = 49 def get_key(bytes_: bytes): # Convert key bytes to iota.TransactionHash if not isinstance(bytes_, bytes): raise TypeError key = iota.TransactionHash.from_trits(converter.from_binary_to_trits(bytes_, HASH_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError for i in range(0, len(bytes_), HASH_BYTES_LENGTH + 1): ti = converter.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH) yield iota.types.TransactionHash.from_trits(ti) PK}bK'v(iotapy/storage/providers/types/bundle.py# -*- coding: utf-8 -*- import iota from iotapy.storage import converter HASH_TRITS_LENGTH = 243 HASH_BYTES_LENGTH = 49 def get_key(bytes_: bytes): # Convert key bytes to key object if not isinstance(bytes_, bytes): raise TypeError key = iota.BundleHash.from_trits(converter.from_binary_to_trits(bytes_, HASH_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError for i in range(0, len(bytes_), HASH_BYTES_LENGTH + 1): ti = converter.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH) yield iota.types.TransactionHash.from_trits(ti) PKdzbK&ZLL+iotapy/storage/providers/types/milestone.py# -*- coding: utf-8 -*- import struct import iota from iotapy.storage import converter HASH_TRITS_LENGTH = 243 def get_key(bytes_: bytes): # Convert key bytes to key object if not isinstance(bytes_, bytes): raise TypeError key = struct.unpack('>l', bytes_)[0] return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError index = struct.unpack('>l', bytes_[:4])[0] milestone = iota.TransactionHash.from_trits( converter.from_binary_to_trits(bytes_[4:], HASH_TRITS_LENGTH)) return (index, milestone) PK{bK66,iotapy/storage/providers/types/state_diff.py import struct import iota from iotapy.storage import converter STATE_DIFF_TRITS_LENGTH = 243 STATE_DIFF_BYTES_LENGTH = 49 + 8 def get_key(bytes_: bytes): # Convert key bytes to iota.TransactionHash if not isinstance(bytes_, bytes): raise TypeError key = iota.TransactionHash.from_trits(converter.from_binary_to_trits(bytes_, STATE_DIFF_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError for i in range(0, len(bytes_), STATE_DIFF_BYTES_LENGTH): value = struct.unpack('>q', bytes_[i + STATE_DIFF_BYTES_LENGTH - 8:i + STATE_DIFF_BYTES_LENGTH])[0] ti = converter.from_binary_to_trits(bytes_[i:i + STATE_DIFF_BYTES_LENGTH - 8], STATE_DIFF_TRITS_LENGTH) yield (iota.TransactionHash.from_trits(ti), value) PKzbK8%iotapy/storage/providers/types/tag.py# -*- coding: utf-8 -*- import iota from iotapy.storage import converter TAG_TRITS_LENGTH = 81 TRANSACTION_TRITS_LENGTH = 243 TRANSACTION_BYTES_LENGTH = 49 def get_key(bytes_: bytes): # Convert key bytes to iota.Tag if not isinstance(bytes_, bytes): raise TypeError key = iota.Tag.from_trits(converter.from_binary_to_trits(bytes_, TAG_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError for i in range(0, len(bytes_), TRANSACTION_BYTES_LENGTH + 1): ti = converter.from_binary_to_trits(bytes_[i:i + TRANSACTION_BYTES_LENGTH], TRANSACTION_TRITS_LENGTH) yield iota.types.TransactionHash.from_trits(ti) PKybKpp-iotapy/storage/providers/types/transaction.py# -*- coding: utf-8 -*- import iota from iotapy.storage import converter HASH_TRITS_LENGTH = 243 TRANSACTION_TRITS_LENGTH = 8019 def get_key(bytes_: bytes): # Convert key bytes to iota.TransactionHash if not isinstance(bytes_, bytes): raise TypeError key = iota.TransactionHash.from_trits(converter.from_binary_to_trits(bytes_, 243)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError ti = converter.from_binary_to_trits(bytes_, TRANSACTION_TRITS_LENGTH) return iota.Transaction.from_tryte_string(iota.TryteString.from_trits(ti), bytes_) PKObKӐI/ / 6iotapy/storage/providers/types/transaction_metadata.py# -*- coding: utf-8 -*- import struct import iota from iotapy.storage import converter as conv TRANSACTION_METADATA_TRITS_LENGTH = 1604 HASH_BYTES_LENGTH = 49 HASH_TRITS_LENGTH = 243 def get_key(bytes_: bytes): # Convert key bytes to iota.TransactionHash if not isinstance(bytes_, bytes): raise TypeError key = iota.TransactionHash.from_trits(converter.from_binary_to_trits(bytes_, HASH_TRITS_LENGTH)) return key def get(bytes_: bytes): if not isinstance(bytes_, bytes): raise TypeError i = 0 address = iota.Address.from_trits(conv.from_binary_to_trits(bytes_[:HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH bundle = iota.BundleHash.from_trits(conv.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH trunk = iota.TransactionHash.from_trits(conv.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH branch = iota.TransactionHash.from_trits(conv.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH legacy_tag = iota.Hash.from_trits(conv.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH value = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 current_index = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 last_index = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 timestamp = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 tag = iota.Hash.from_trits(conv.from_binary_to_trits(bytes_[i:i + HASH_BYTES_LENGTH], HASH_TRITS_LENGTH)) i += HASH_BYTES_LENGTH attachment_timestamp = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 attachment_timestamp_lower_bound = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 attachment_timestamp_upper_bound = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 validity = struct.unpack('>l', bytes_[i:i + 4])[0] i += 4 type_ = struct.unpack('>l', bytes_[i:i + 4])[0] i += 4 arrival_time = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 height = struct.unpack('>q', bytes_[i:i + 8])[0] i += 8 # Is confirmed? solid = bytes_[i] == 1 i += 1 snapshot = struct.unpack('>l', bytes_[i:i + 4])[0] i += 4 sender = bytes_[i:].decode('ascii') return { 'address': address, 'bundle_hash': bundle, 'trunk_transaction_hash': trunk, 'branch_transaction_hash': branch, 'legacy_tag': legacy_tag, 'value': value, 'current_index': current_index, 'last_index': last_index, 'timestamp': timestamp, 'tag': tag, 'attachment_timestamp': attachment_timestamp, 'attachment_timestamp_lower_bound': attachment_timestamp_lower_bound, 'attachment_timestamp_upper_bound': attachment_timestamp_upper_bound, 'validity': validity, 'type': type_, 'arrival_time': arrival_time, 'height': height, 'solid': solid, 'snapshot': snapshot, 'sender': sender } PKhXKeiotapy-0.1.2.dist-info/LICENSECopyright 2017 Louie Lu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!H١Wdiotapy-0.1.2.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,Q0343 /, (-JLR()*M ILR(4KM̫#DPK!H@8iotapy-0.1.2.dist-info/METADATA;iwv+Գv`E;}wg $lub$%9o-Ix^err܀ﭵմϼ(|1 L*^`~٫<.^F8"=3^|g,*ϧ;$ȓyzCU-}V=ƽI>?UVٲF)$]dM5\A}1+,l_k< S i~[yʊl>=2f5%|4u[UY7t1lq+~:@m/ i)Τ,_"Ţz%qe'YZ UH9rdbRSmq92YY ?/z`YO,[C{z'Lvc| sRB_Ik"% aa([56Jag8ZI<ƧU }*M;c.a!|O^ 'Ⱥ-*U4%upDg^ǎ*Q"_(I%e\=X]:sQD6"NVPNwLdqT2TduF1!ݑZ@`Φs< 7[e r|#] p]>Y#l ~6Z} SIM ׵`Z޲ת2uc\XX-iNyGzm i:يYu||hoad:r7- #ymD-(Ujԫ|[n_TfȬgoTQCNk)"^(ѣQvW~xQ@$#wƑG;ƫE2KoT]і;lB(h-bqitCӊD:X.4FDq94 h"Fn;r;p@#m ŵ`Ģ`f8%iڧgX6h(4p$E 5>M3C|?ߟϷNazqy zX7=t6᝵} kz,y>K/n'nxxu;Bۣ˷yz'I0PO6o0"ChENd3Q -HKlxJ/EQ0`;&byyi'Ot(>ƳU YzO^na**X@`ؿ!˫a`lf$}:mg2~l  U*< j/Oiq;A=d1 B)OQ2oվlszIS/W.fYlHA(ar r֒Gmvm$/MV]o;rcgG F-M/"- 3?HӋ`8p>oďPMߣx (Ô TO&Mc DP[t@U12ybxu#^a=NP'TV4ХB% -1Y }DO']YuqZ)..e3 OUv %#Bw C exghMD'UޓxVieB fd3Rvd&kdi:to#5#)U$B}5iC7"|Y2-W@lCKiANŴU];k/x=Roh^u7Lsq}y-b N!bH* K))C6KӒg/8˺B:Mi1?m?.s7F$G$:c뱪M'oCWQ+*I0듊IxL 4mOVU~;q(Ѽ>>: e+v@||~Nw|y )y2ç)Bt%N.@wFBJCzAaĀ0+K\7tKw &b0@9d>3j<Ps]PI8 j i$5k ?3*#BXS }~ӥp JadZ.M?!Q~70CE27PLjBQ:N /|MA;#Ar}8UL\1HH{ h). C P>rMAcZ?76=ߟt(>|#ﻹ/bco9x-ML|~.Pt[Եw89Cy9vC&Bg)߻?e`f q냻|ЃTeU`p\] bJ &0x8$>'ۇ{_jϪa0~'fN7O>ΚszMՎKm"on"Ƈ@~Ef߅!Ӧ.+KiaqT.+hq}^XKwn88#>P3>mc%V 䇽 >F뽪:ኪP䫪k6ثP{?:=Z:]WK-c]IGxpǂoxeutVl3#SC%bxl ?6n+U%f,L+I\CW d [Ф h? dwxKˆ|uZ GC ߒ=–ݐ|-DAV42`=qx6TGu:!U6%WMEؐ)QH5C,M w cC4<xs xI)X&`TXddU`uV&xb|V?q4'bC vl鴪kR.馡b!-jKA>EF!{p߷2i`VN6{Ψ:˭cBݘ?)M>{RT(|Yn}~K$ -Am")w%Ο-!P  'iS$)=0FAwqJv&x)M3ܩ4z5^{_;US>6IL#ݩnN [R-[7uK)9MdU>[a4I Bd-"J+}̳~=;.M|u[>^IȒl2*aep"jtBڞrQbԂWo(iHf6xVOd16k[Es^@Ck56 hSؑDbطPKbK\^^iotapy/__init__.pyPKqbK((iotapy/iota.pyPKpXKBw`BB iotapy/iri.pyPKnbK-.VVOiotapy/storage/__init__.pyPKbK,jIIiotapy/storage/converter.pyPKbKl_ iotapy/storage/tangle.pyPKhbK$ iotapy/storage/providers/__init__.pyPKdbKRD# iotapy/storage/providers/rocksdb.pyPKbbK#iotapy/storage/providers/zmq.pyPK5bKƬk*>#iotapy/storage/providers/types/__init__.pyPKbKҘ)%iotapy/storage/providers/types/address.pyPKbKQ*(iotapy/storage/providers/types/approvee.pyPK}bK'v(q+iotapy/storage/providers/types/bundle.pyPKdzbK&ZLL+P.iotapy/storage/providers/types/milestone.pyPK{bK66,0iotapy/storage/providers/types/state_diff.pyPKzbK8%e4iotapy/storage/providers/types/tag.pyPKybKpp-p7iotapy/storage/providers/types/transaction.pyPKObKӐI/ / 6+:iotapy/storage/providers/types/transaction_metadata.pyPKhXKeFiotapy-0.1.2.dist-info/LICENSEPK!H١WdKiotapy-0.1.2.dist-info/WHEELPK!H@8Kiotapy-0.1.2.dist-info/METADATAPK!H/Bt``iotapy-0.1.2.dist-info/RECORDPKwd