chainqueue

Blockchain transaction queue control
Info | Log | Files | Refs | LICENSE

output.py (4587B)


      1 # standard imports
      2 import logging
      3 import enum
      4 
      5 # external imports
      6 from hexathon import add_0x
      7 
      8 # local imports
      9 from chainqueue.enum import (
     10         StatusBits,
     11         all_errors,
     12         is_alive,
     13         is_error_status,
     14         status_str,
     15         )
     16 
     17 logg = logging.getLogger(__name__)
     18 
     19 
     20 class OutputCol(enum.Enum):
     21     chainspec = 0
     22     hash = 1
     23     statustext = 2
     24     statuscode = 3
     25     signedtx = 4
     26 
     27 
     28 class Outputter:
     29     """Output helper for chainqueue cli listings tools.
     30 
     31     :param chain_spec: Chain spec to use as getter context
     32     :type chain_spec: chainlib.chain.ChainSpec
     33     :param writer: Writer to write output to. Will automatically flush.
     34     :type writer: Writer
     35     :param getter: Transaction getter
     36     :type getter: See chainqueue.sql.backend.get_otx 
     37     :param session_method: Backend session generator method
     38     :type session_method: varies
     39     :param decode_status: Print status bit details
     40     :type decode_status: bool
     41     """
     42 
     43     all_cols = [
     44             OutputCol.chainspec,
     45             OutputCol.hash,
     46             OutputCol.signedtx,
     47             OutputCol.statustext,
     48             OutputCol.statuscode,
     49             ]
     50     default_cols = [
     51             OutputCol.chainspec,
     52             OutputCol.hash,
     53             OutputCol.statustext,
     54             OutputCol.statuscode,
     55             ]
     56 
     57     def __init__(self, chain_spec, writer, getter, session_method=None, decode_status=True, cols=None):
     58         self.decode_status = decode_status
     59         self.writer = writer
     60         self.getter = getter
     61         self.chain_spec = chain_spec
     62         self.chain_spec_str = str(chain_spec)
     63         self.session = None
     64         if session_method != None:
     65             self.session = session_method()
     66         self.results = {
     67             'pending_error': 0,
     68             'final_error': 0,
     69             'pending': 0,
     70             'final': 0,
     71                 }
     72 
     73         debug_col_name = []
     74         if cols == None:
     75             self.cols = Outputter.default_cols
     76         else:
     77             self.cols = []
     78             for col in cols:
     79                 v = getattr(OutputCol, col)
     80                 self.cols.append(v) 
     81 
     82         for col in self.cols:
     83             debug_col_name.append(col.name)
     84         logg.debug('outputter initialized with cols: {}'.format(','.join(debug_col_name)))
     85 
     86 
     87     def __del__(self):
     88         if self.session != None:
     89             self.session.close()
     90 
     91 
     92     def add(self, tx_hash):
     93         """Retrieve a transaction by hash and add it for summary output generation.
     94 
     95         :param tx_hash: Transaction hash
     96         :type tx_hash: str
     97         """
     98         tx = self.getter(self.chain_spec, tx_hash, session=self.session)
     99         self.__add(tx)
    100 
    101     def __add(self, tx):
    102         category = None
    103         if is_alive(tx['status_code']):
    104             category = 'pending'
    105         else:
    106             category = 'final'
    107         self.results[category] += 1
    108         if is_error_status(tx['status_code']):
    109             logg.debug('registered {} as {} with error'.format(tx['tx_hash'], category))
    110             self.results[category + '_error'] += 1
    111         else:
    112             logg.debug('registered {} as {}'.format(tx['tx_hash'], category))
    113      
    114 
    115     def decode_summary(self):
    116         """Writes summary to the registered writer.
    117         """
    118         self.writer.write('pending\t{}\t{}\n'.format(self.results['pending'], self.results['pending_error']))
    119         self.writer.write('final\t{}\t{}\n'.format(self.results['final'], self.results['final_error']))
    120         self.writer.write('total\t{}\t{}\n'.format(self.results['final'] + self.results['pending'], self.results['final_error'] + self.results['pending_error']))
    121 
    122 
    123     def decode_single(self, tx_hash):
    124         """Retrieves the transaction with the given hash and writes the details to the underlying writer.
    125 
    126         Registers the transaction with the summary generator.
    127 
    128         :param tx_hash: Transaction hash
    129         :type tx_hash: str
    130         """
    131         tx = self.getter(self.chain_spec, tx_hash, session=self.session)
    132         self.__add(tx)
    133         status = tx['status']
    134         if self.decode_status:
    135             status = status_str(tx['status_code'], bits_only=True)
    136 
    137         vals = [
    138             self.chain_spec_str,
    139             add_0x(tx_hash),
    140             status,
    141             str(tx['status_code']),
    142             add_0x(tx['signed_tx']),
    143             ]
    144 
    145         i = 0
    146         l = len(self.cols)
    147         for col in self.cols:
    148             self.writer.write(vals[col.value])
    149             i += 1
    150             if i == l:
    151                 self.writer.write('\n')
    152             else:
    153                 self.writer.write('\t')