2021-11-06 06:29:45 +01:00
# standard imports
import sys
import logging
2021-11-06 10:34:40 +01:00
import datetime
2022-01-22 15:36:58 +01:00
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
2021-11-06 10:34:40 +01:00
from cic_types . models . person import Person
2021-11-06 06:29:45 +01:00
from chainlib . eth . address import to_checksum_address
2021-12-17 08:50:01 +01:00
from chainlib . encode import TxHexNormalizer
2022-01-22 09:44:36 +01:00
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
2022-01-22 09:44:36 +01:00
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__ )
2021-12-17 08:50:01 +01:00
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 ' )
2021-11-06 14:04:29 +01:00
argparser . add_argument ( ' -f ' , ' --force-update ' , dest = ' force_update ' , action = ' store_true ' , help = ' Update records of mutable entries ' )
2022-01-22 11:43:46 +01:00
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 ' )
2022-01-22 11:43:46 +01:00
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 ' )
2021-11-05 18:36:07 +01:00
def extra_args ( ) :
return {
2022-01-22 11:43:46 +01:00
' raw_tx ' : ' _RAW_TX ' ,
2021-11-06 04:42:18 +01:00
' force_update ' : ' _FORCE ' ,
2022-01-22 11:43:46 +01:00
' force_update_all ' : ' _FORCE_ALL ' ,
2021-11-05 18:36:07 +01:00
' method ' : ' META_LOOKUP_METHOD ' ,
' meta_url ' : ' META_URL ' ,
2021-11-06 10:34:40 +01:00
' identifier ' : ' _IDENTIFIER ' ,
2022-01-23 15:55:56 +01:00
' no_resolve ' : ' _NO_RESOLVE ' ,
' no_tx ' : ' _NO_TX ' ,
2021-11-05 18:36:07 +01:00
}
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 ' )
2022-01-23 13:36:23 +01:00
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 '
2022-01-22 11:43:46 +01:00
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 ' ) ) )
2021-11-06 10:34:40 +01:00
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 )
2021-11-06 10:34:40 +01:00
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 ) ,
)
)
2021-11-06 10:34:40 +01:00
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 ) ,
)
2021-11-06 10:34:40 +01:00
)
2022-01-23 15:55:56 +01:00
if ctrl . get ( ' _NO_TX ' ) :
sys . exit ( 0 )
2021-11-06 10:34:40 +01:00
2022-01-22 11:43:46 +01:00
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 )
2022-01-22 15:36:58 +01:00
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 ( )
2022-01-23 13:36:23 +01:00
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 ' ] :
2022-01-22 09:44:36 +01:00
tx_hash = strip_0x ( tx_src [ ' tx_hash ' ] )
2022-01-22 15:36:58 +01:00
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-22 15:36:58 +01:00
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 :
2022-01-22 15:36:58 +01:00
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-22 15:36:58 +01:00
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-22 15:36:58 +01:00
2022-01-23 11:48:02 +01:00
token_resolver_queue . put_nowait ( None )
token_buf = ' '
2022-01-22 15:36:58 +01:00
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-22 15:36:58 +01:00
2022-01-23 11:48:02 +01:00
ctrl . notify ( ' wait for token resolver to finish work ' )
token_resolver_worker . join ( )
2022-01-22 15:36:58 +01:00
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-22 15:36:58 +01:00
2022-01-23 13:43:25 +01:00