clicada/clicada/cli/user.py

229 lines
7.4 KiB
Python
Raw Normal View History

2021-11-06 06:29:45 +01:00
# standard imports
import sys
import logging
import datetime
from queue import SimpleQueue as Queue
2021-11-06 06:29:45 +01:00
# external imports
from cic_eth_registry import CICRegistry
from cic_eth_registry.lookup.tokenindex import TokenIndexLookup
from cic_types.models.person import Person
2021-11-06 06:29:45 +01:00
from chainlib.eth.address import to_checksum_address
from chainlib.encode import TxHexNormalizer
from hexathon import (
add_0x,
strip_0x,
)
2021-11-06 06:29:45 +01:00
# local imports
2022-01-23 15:55:56 +01:00
from clicada.tx import (
TxGetter,
FormattedTokenTx,
)
2021-11-06 06:29:45 +01:00
from clicada.user import FileUserStore
2022-01-23 13:43:25 +01:00
from clicada.token import FileTokenStore
2021-11-06 06:29:45 +01:00
from clicada.tx import ResolvedTokenTx
from clicada.tx.file import FileTxStore
2022-01-21 11:03:01 +01:00
from clicada.error import MetadataNotFoundError
2022-01-23 13:43:25 +01:00
from clicada.cli.worker import (
MetadataResolverWorker,
TxResolverWorker,
TokenResolverWorker,
)
2021-11-06 06:29:45 +01:00
logg = logging.getLogger(__name__)
tx_normalizer = TxHexNormalizer()
2021-11-06 06:29:45 +01:00
2021-11-05 07:21:33 +01:00
def process_args(argparser):
argparser.add_argument('-m', '--method', type=str, help='lookup method')
2021-11-06 04:42:18 +01:00
argparser.add_argument('--meta-url', dest='meta_url', type=str, help='Url to retrieve metadata from')
argparser.add_argument('-f', '--force-update', dest='force_update', action='store_true', help='Update records of mutable entries')
argparser.add_argument('-ff', '--force-update-all', dest='force_update_all', action='store_true', help='Update records of mutable entries and immutable entries')
2022-01-23 15:55:56 +01:00
argparser.add_argument('-N', '--no-resolve', dest='no_resolve', action='store_true', help='Resolve no metadata')
argparser.add_argument('--no-tx', dest='no_tx', action='store_true', help='Do not fetch transactions')
argparser.add_argument('--raw-tx', dest='raw_tx', action='store_true', help='Also cache raw transaction data')
2021-11-05 07:21:33 +01:00
argparser.add_argument('identifier', type=str, help='user identifier')
def extra_args():
return {
'raw_tx': '_RAW_TX',
2021-11-06 04:42:18 +01:00
'force_update': '_FORCE',
'force_update_all': '_FORCE_ALL',
'method': 'META_LOOKUP_METHOD',
'meta_url': 'META_URL',
'identifier': '_IDENTIFIER',
2022-01-23 15:55:56 +01:00
'no_resolve': '_NO_RESOLVE',
'no_tx': '_NO_TX',
}
2021-11-06 06:29:45 +01:00
def apply_args(config, args):
if config.get('META_LOOKUP_METHOD'):
raise NotImplementedError('Sorry, currently only "phone" lookup method is implemented')
if config.true('_FORCE_ALL'):
config.add(True, '_FORCE', exists_ok=True)
2021-11-05 07:21:33 +01:00
2021-11-06 06:29:45 +01:00
def validate(config, args):
2021-11-05 07:21:33 +01:00
pass
2021-11-06 06:29:45 +01:00
def execute(ctrl):
2022-01-23 11:48:02 +01:00
tx_getter = TxGetter(ctrl.get('TX_CACHE_URL'), 50)
2021-11-06 06:29:45 +01:00
store_path = '.clicada'
user_phone_file_label = 'phone'
user_phone_store = FileUserStore(ctrl.opener('meta'), ctrl.chain(), user_phone_file_label, store_path, int(ctrl.get('FILESTORE_TTL')), encrypter=ctrl.encrypter, notifier=ctrl)
2021-11-06 06:29:45 +01:00
2022-01-21 11:03:01 +01:00
ctrl.notify('resolving identifier {} to wallet address'.format(ctrl.get('_IDENTIFIER')))
user_address = user_phone_store.by_phone(ctrl.get('_IDENTIFIER'), update=ctrl.get('_FORCE'))
2021-11-06 06:29:45 +01:00
if user_address == None:
2022-01-21 11:03:01 +01:00
ctrl.ouch('unknown identifier: {}\n'.format(ctrl.get('_IDENTIFIER')))
2021-11-06 06:29:45 +01:00
sys.exit(1)
try:
user_address = to_checksum_address(user_address)
except ValueError:
2022-01-21 11:03:01 +01:00
ctrl.ouch('invalid response "{}" for {}\n'.format(user_address, ctrl.get('_IDENTIFIER')))
2021-11-06 06:29:45 +01:00
sys.exit(1)
logg.debug('loaded user address {} for {}'.format(user_address, ctrl.get('_IDENTIFIER')))
2021-11-06 06:29:45 +01:00
2022-01-21 11:03:01 +01:00
user_address_normal = tx_normalizer.wallet_address(user_address)
2022-01-23 15:55:56 +01:00
ctrl.write("""Results for lookup by phone {}:
2021-11-06 06:29:45 +01:00
2022-01-23 15:55:56 +01:00
Metadata:
Network address: {}""".format(
ctrl.get('_IDENTIFIER'),
add_0x(user_address),
)
)
2022-01-23 15:55:56 +01:00
if not ctrl.get('_NO_RESOLVE'):
token_store = FileTokenStore(ctrl.chain(), ctrl.conn(), 'token', store_path)
user_address_file_label = 'address'
user_address_store = FileUserStore(ctrl.opener('meta'), ctrl.chain(), user_address_file_label, store_path, int(ctrl.get('FILESTORE_TTL')), encrypter=ctrl.encrypter, notifier=ctrl)
ctrl.notify('resolving metadata for address {}'.format(user_address_normal))
try:
r = user_address_store.by_address(user_address_normal, update=ctrl.get('_FORCE'))
except MetadataNotFoundError as e:
ctrl.ouch('could not resolve metadata for user: {}'.format(e))
sys.exit(1)
ctrl.write(""" Chain: {}
Name: {}
Registered: {}
Gender: {}
Location: {}
Products: {}
Tags: {}""".format(
ctrl.chain().common_name(),
str(r),
datetime.datetime.fromtimestamp(r.date_registered).ctime(),
r.gender,
r.location['area_name'],
','.join(r.products),
','.join(r.tags),
)
)
2022-01-23 15:55:56 +01:00
if ctrl.get('_NO_TX'):
sys.exit(0)
raw_rpc = None
if ctrl.get('_RAW_TX'):
raw_rpc = ctrl.rpc
2022-01-23 15:55:56 +01:00
ctrl.notify('retrieving txs for address {}'.format(user_address_normal))
txs = tx_getter.get(user_address)
if ctrl.get('_NO_RESOLVE'):
for v in txs['data']:
tx = FormattedTokenTx.from_dict(v)
ctrl.write(tx)
sys.exit(0)
token_resolver_queue = Queue()
token_result_queue = Queue()
token_resolver_worker = TokenResolverWorker(user_address, ctrl, token_store, token_resolver_queue, token_result_queue)
token_resolver_worker.start()
wallets = []
for tx in txs['data']:
token_resolver_queue.put_nowait(tx['source_token'])
token_resolver_queue.put_nowait(tx['destination_token'])
if tx['sender'] not in wallets:
logg.info('adding wallet {} to metadata lookup'.format(tx['sender']))
wallets.append(tx['sender'])
if tx['recipient'] not in wallets:
wallets.append(tx['recipient'])
logg.info('registered wallet {} for metadata lookup'.format(tx['recipient']))
wallet_threads = []
for a in wallets:
thread_wallet = MetadataResolverWorker(a, ctrl, user_address_store)
thread_wallet.start()
wallet_threads.append(thread_wallet)
ctrl.notify('wait for metadata resolvers to finish work')
for t in wallet_threads:
t.join()
tx_store = FileTxStore(store_path, rpc=raw_rpc, notifier=ctrl)
tx_threads = []
tx_queue = Queue()
2022-01-23 11:48:02 +01:00
tx_n = 0
2021-11-06 06:29:45 +01:00
for tx_src in txs['data']:
tx_hash = strip_0x(tx_src['tx_hash'])
tx_worker = TxResolverWorker(tx_hash, tx_src, ctrl, tx_store, token_store, user_address_store, token_resolver_queue, tx_queue, show_decimals=True, update=ctrl.get('_FORCE'))
tx_thread = tx_worker.start()
tx_threads.append(tx_worker)
2022-01-23 11:48:02 +01:00
tx_n += 1
2022-01-23 11:48:02 +01:00
tx_buf = {}
2021-11-06 10:59:49 +01:00
2022-01-23 11:48:02 +01:00
for i in range(0, tx_n):
tx = tx_queue.get()
if tx == None:
break
2022-01-23 11:48:02 +01:00
# ugh, ugly
#k = float('{}.{}'.format(tx.block_number, tx.tx_index))
# tx_index is missing, this is temporary sort measure
k = str(tx.block_number) + '.' + tx.tx_hash
tx_buf[k] = tx
2022-01-23 11:48:02 +01:00
ctrl.notify('wait for transaction getters to finish work')
for tx_thread in tx_threads:
tx_thread.join()
2022-01-23 11:48:02 +01:00
token_resolver_queue.put_nowait(None)
token_buf = ''
while True:
l = token_result_queue.get()
if l == None:
break
2022-01-23 11:48:02 +01:00
token_buf += ' {} {}\n'.format(l[0], l[1])
2022-01-23 11:48:02 +01:00
ctrl.notify('wait for token resolver to finish work')
token_resolver_worker.join()
2022-01-23 15:55:56 +01:00
ctrl.write('')
2022-01-23 11:48:02 +01:00
ctrl.write("Balances:")
ctrl.write(token_buf)
ks = list(tx_buf.keys())
ks.sort()
ks.reverse()
for k in ks:
ctrl.write(tx_buf[k])
2022-01-23 13:43:25 +01:00