block.py (4851B)
1 # standard imports 2 import logging 3 import datetime 4 5 # external imports 6 from chainlib.jsonrpc import JSONRPCRequest 7 from chainlib.block import Block as BaseBlock 8 from hexathon import ( 9 add_0x, 10 strip_0x, 11 compact, 12 to_int as hex_to_int, 13 ) 14 15 # local imports 16 from chainlib.eth.tx import Tx 17 from chainlib.eth.tx import eth_dialect_filter 18 from .src import Src 19 20 logg = logging.getLogger(__name__) 21 22 23 def block_latest(id_generator=None): 24 """Implements chainlib.interface.ChainInterface method 25 """ 26 j = JSONRPCRequest(id_generator) 27 o = j.template() 28 o['method'] = 'eth_blockNumber' 29 return j.finalize(o) 30 31 32 def block_by_hash(hsh, include_tx=True, id_generator=None): 33 """Implements chainlib.interface.ChainInterface method 34 """ 35 j = JSONRPCRequest(id_generator) 36 o = j.template() 37 o['method'] = 'eth_getBlockByHash' 38 o['params'].append(hsh) 39 o['params'].append(include_tx) 40 return j.finalize(o) 41 42 43 def block_by_number(n, include_tx=True, id_generator=None): 44 """Implements chainlib.interface.ChainInterface method 45 """ 46 hx = strip_0x(hex(n)) 47 nhx = add_0x(compact(hx), compact_value=True) 48 j = JSONRPCRequest(id_generator) 49 o = j.template() 50 o['method'] = 'eth_getBlockByNumber' 51 o['params'].append(nhx) 52 o['params'].append(include_tx) 53 return j.finalize(o) 54 55 56 def transaction_count(block_hash, id_generator=None): 57 """Generate json-rpc query to get transaction count of block 58 59 :param block_hash: Block hash, in hex 60 :type block_hash: str 61 :param id_generator: JSONRPC id generator 62 :type id_generator: JSONRPCIdGenerator 63 :rtype: dict 64 :returns: rpc query object 65 """ 66 j = JSONRPCRequest(id_generator) 67 o = j.template() 68 o['method'] = 'eth_getBlockTransactionCountByHash' 69 o['params'].append(block_hash) 70 return j.finalize(o) 71 72 73 def syncing(id_generator=None): 74 """Request the syncing state of the node 75 76 :param id_generator: JSONRPC id generator 77 :type id_generator: JSONRPCIdGenerator 78 :rtype: dict 79 :returns: rpc query object 80 """ 81 j = JSONRPCRequest(id_generator) 82 o = j.template() 83 o['method'] = 'eth_syncing' 84 return j.finalize(o) 85 86 87 class Block(BaseBlock, Src): 88 """Encapsulates an Ethereum block 89 90 :param src: Block representation data 91 :type src: dict 92 :todo: Add hex to number parse to normalize 93 """ 94 95 tx_generator = Tx 96 97 def __init__(self, src=None, dialect_filter=None): 98 super(Block, self).__init__(src=src, dialect_filter=dialect_filter) 99 100 101 def __parse_author(self, src): 102 author = None 103 try: 104 author = self.src['author'] 105 except KeyError: 106 pass 107 if author: 108 return author 109 110 try: 111 author = self.src['miner'] 112 except KeyError: 113 pass 114 if author: 115 return author 116 117 return self.src['coinbase'] 118 119 120 def load_src(self, dialect_filter=None): 121 if dialect_filter != None: 122 dialect_filter.apply_block(self) 123 124 self.set_hash(self.src['hash']) 125 try: 126 self.number = int(strip_0x(self.src['number']), 16) 127 except TypeError: 128 self.number = int(self.src['number']) 129 self.txs = self.src['transactions'] 130 self.block_src = self.src 131 try: 132 self.timestamp = int(strip_0x(self.src['timestamp']), 16) 133 except TypeError: 134 self.timestamp = int(self.src['timestamp']) 135 136 self.author = self.__parse_author(self.src) 137 138 139 def tx_by_index(self, idx, dialect_filter=eth_dialect_filter): 140 return super(Block, self).tx_by_index(idx, dialect_filter=dialect_filter) 141 142 143 def tx_index_by_hash(self, tx_hash): 144 i = 0 145 idx = -1 146 tx_hash = add_0x(tx_hash) 147 for tx in self.txs: 148 tx_hash_block = None 149 try: 150 tx_hash_block = add_0x(tx['hash']) 151 except TypeError: 152 tx_hash_block = add_0x(tx) 153 if tx_hash_block == tx_hash: 154 idx = i 155 break 156 i += 1 157 if idx == -1: 158 raise AttributeError('tx {} not found in block {}'.format(tx_hash, self.hash)) 159 return idx 160 161 162 def to_human(self): 163 try: 164 self.fee_limit = hex_to_int(self.fee_limit) 165 except TypeError: 166 pass 167 168 try: 169 self.fee_cost = hex_to_int(self.fee_cost) 170 except TypeError: 171 pass 172 173 s = """hash: {} 174 number: {} 175 parent: {} 176 timestamp: {} 177 time: {} 178 author: {} 179 gas_limit: {} 180 gas_used: {} 181 txs: {} 182 """.format( 183 self.hash, 184 self.number, 185 self.parent_hash, 186 self.timestamp, 187 datetime.datetime.fromtimestamp(self.timestamp), 188 self.author, 189 self.fee_limit, 190 self.fee_cost, 191 len(self.txs), 192 ) 193 194 return s 195