2022-05-12 10:20:06 +02:00
|
|
|
# standard imports
|
|
|
|
import logging
|
|
|
|
import datetime
|
|
|
|
|
2021-08-21 09:27:40 +02:00
|
|
|
# external imports
|
2021-06-28 07:48:36 +02:00
|
|
|
from chainlib.jsonrpc import JSONRPCRequest
|
2021-08-21 09:27:40 +02:00
|
|
|
from chainlib.block import Block as BaseBlock
|
2021-06-28 07:48:36 +02:00
|
|
|
from hexathon import (
|
|
|
|
add_0x,
|
|
|
|
strip_0x,
|
2022-02-12 13:30:13 +01:00
|
|
|
compact,
|
2022-05-12 20:05:13 +02:00
|
|
|
to_int as hex_to_int,
|
2021-06-28 07:48:36 +02:00
|
|
|
)
|
|
|
|
|
2021-08-21 09:27:40 +02:00
|
|
|
# local imports
|
|
|
|
from chainlib.eth.tx import Tx
|
2022-05-09 20:46:10 +02:00
|
|
|
from .src import Src
|
2021-08-21 09:27:40 +02:00
|
|
|
|
2022-05-12 10:20:06 +02:00
|
|
|
logg = logging.getLogger(__name__)
|
|
|
|
|
2021-06-28 07:48:36 +02:00
|
|
|
|
|
|
|
def block_latest(id_generator=None):
|
2021-08-21 09:27:40 +02:00
|
|
|
"""Implements chainlib.interface.ChainInterface method
|
|
|
|
"""
|
2021-06-28 07:48:36 +02:00
|
|
|
j = JSONRPCRequest(id_generator)
|
|
|
|
o = j.template()
|
|
|
|
o['method'] = 'eth_blockNumber'
|
|
|
|
return j.finalize(o)
|
|
|
|
|
|
|
|
|
|
|
|
def block_by_hash(hsh, include_tx=True, id_generator=None):
|
2021-08-21 09:27:40 +02:00
|
|
|
"""Implements chainlib.interface.ChainInterface method
|
|
|
|
"""
|
2021-06-28 07:48:36 +02:00
|
|
|
j = JSONRPCRequest(id_generator)
|
|
|
|
o = j.template()
|
|
|
|
o['method'] = 'eth_getBlockByHash'
|
|
|
|
o['params'].append(hsh)
|
|
|
|
o['params'].append(include_tx)
|
|
|
|
return j.finalize(o)
|
|
|
|
|
|
|
|
|
|
|
|
def block_by_number(n, include_tx=True, id_generator=None):
|
2021-08-21 09:27:40 +02:00
|
|
|
"""Implements chainlib.interface.ChainInterface method
|
|
|
|
"""
|
2022-02-12 13:30:13 +01:00
|
|
|
hx = strip_0x(hex(n))
|
|
|
|
nhx = add_0x(compact(hx), compact_value=True)
|
2021-06-28 07:48:36 +02:00
|
|
|
j = JSONRPCRequest(id_generator)
|
|
|
|
o = j.template()
|
|
|
|
o['method'] = 'eth_getBlockByNumber'
|
|
|
|
o['params'].append(nhx)
|
|
|
|
o['params'].append(include_tx)
|
|
|
|
return j.finalize(o)
|
|
|
|
|
|
|
|
|
|
|
|
def transaction_count(block_hash, id_generator=None):
|
2021-08-21 09:27:40 +02:00
|
|
|
"""Generate json-rpc query to get transaction count of block
|
|
|
|
|
|
|
|
:param block_hash: Block hash, in hex
|
|
|
|
:type block_hash: str
|
|
|
|
:param id_generator: JSONRPC id generator
|
|
|
|
:type id_generator: JSONRPCIdGenerator
|
|
|
|
:rtype: dict
|
|
|
|
:returns: rpc query object
|
|
|
|
"""
|
2021-06-28 07:48:36 +02:00
|
|
|
j = JSONRPCRequest(id_generator)
|
|
|
|
o = j.template()
|
|
|
|
o['method'] = 'eth_getBlockTransactionCountByHash'
|
|
|
|
o['params'].append(block_hash)
|
|
|
|
return j.finalize(o)
|
|
|
|
|
|
|
|
|
2021-10-25 11:24:55 +02:00
|
|
|
def syncing(id_generator=None):
|
|
|
|
"""Request the syncing state of the node
|
|
|
|
|
|
|
|
:param id_generator: JSONRPC id generator
|
|
|
|
:type id_generator: JSONRPCIdGenerator
|
|
|
|
:rtype: dict
|
|
|
|
:returns: rpc query object
|
|
|
|
"""
|
|
|
|
j = JSONRPCRequest(id_generator)
|
|
|
|
o = j.template()
|
|
|
|
o['method'] = 'eth_syncing'
|
|
|
|
return j.finalize(o)
|
|
|
|
|
|
|
|
|
2022-05-09 20:46:10 +02:00
|
|
|
class Block(BaseBlock, Src):
|
2021-08-21 09:27:40 +02:00
|
|
|
"""Encapsulates an Ethereum block
|
|
|
|
|
|
|
|
:param src: Block representation data
|
|
|
|
:type src: dict
|
|
|
|
:todo: Add hex to number parse to normalize
|
|
|
|
"""
|
2021-08-24 19:11:53 +02:00
|
|
|
|
|
|
|
tx_generator = Tx
|
|
|
|
|
2022-05-12 10:20:06 +02:00
|
|
|
def __init__(self, src=None):
|
|
|
|
super(Block, self).__init__(src=src)
|
|
|
|
|
|
|
|
self.set_hash(self.src['hash'])
|
2021-06-28 07:48:36 +02:00
|
|
|
try:
|
2022-05-12 10:20:06 +02:00
|
|
|
self.number = int(strip_0x(self.src['number']), 16)
|
2021-06-28 07:48:36 +02:00
|
|
|
except TypeError:
|
2022-05-12 10:20:06 +02:00
|
|
|
self.number = int(self.src['number'])
|
|
|
|
self.txs = self.src['transactions']
|
|
|
|
self.block_src = self.src
|
2021-06-28 07:48:36 +02:00
|
|
|
try:
|
2022-05-12 10:20:06 +02:00
|
|
|
self.timestamp = int(strip_0x(self.src['timestamp']), 16)
|
2021-06-28 07:48:36 +02:00
|
|
|
except TypeError:
|
2022-05-12 10:20:06 +02:00
|
|
|
self.timestamp = int(self.src['timestamp'])
|
|
|
|
|
|
|
|
try:
|
|
|
|
self.author = self.src['author']
|
|
|
|
except KeyError:
|
|
|
|
self.author = self.src['miner']
|
|
|
|
|
|
|
|
self.fee_limit = self.src['gas_limit']
|
|
|
|
self.fee_cost = self.src['gas_used']
|
|
|
|
self.parent_hash = self.src['parent_hash']
|
2021-06-28 07:48:36 +02:00
|
|
|
|
|
|
|
|
2022-05-09 12:00:29 +02:00
|
|
|
def tx_index_by_hash(self, tx_hash):
|
2021-08-21 09:27:40 +02:00
|
|
|
i = 0
|
|
|
|
idx = -1
|
|
|
|
tx_hash = add_0x(tx_hash)
|
|
|
|
for tx in self.txs:
|
|
|
|
tx_hash_block = None
|
|
|
|
try:
|
|
|
|
tx_hash_block = add_0x(tx['hash'])
|
|
|
|
except TypeError:
|
|
|
|
tx_hash_block = add_0x(tx)
|
|
|
|
if tx_hash_block == tx_hash:
|
|
|
|
idx = i
|
|
|
|
break
|
|
|
|
i += 1
|
|
|
|
if idx == -1:
|
|
|
|
raise AttributeError('tx {} not found in block {}'.format(tx_hash, self.hash))
|
|
|
|
return idx
|
2022-05-12 10:20:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
def to_human(self):
|
|
|
|
s = """hash: {}
|
|
|
|
number: {}
|
|
|
|
parent: {}
|
|
|
|
timestamp: {}
|
|
|
|
time: {}
|
|
|
|
author: {}
|
|
|
|
gas_limit: {}
|
|
|
|
gas_used: {}
|
|
|
|
txs: {}
|
|
|
|
""".format(
|
|
|
|
self.hash,
|
|
|
|
self.number,
|
|
|
|
self.parent_hash,
|
|
|
|
self.timestamp,
|
|
|
|
datetime.datetime.fromtimestamp(self.timestamp),
|
|
|
|
self.author,
|
2022-05-12 20:05:13 +02:00
|
|
|
hex_to_int(self.fee_limit),
|
|
|
|
hex_to_int(self.fee_cost),
|
2022-05-12 10:20:06 +02:00
|
|
|
len(self.txs),
|
|
|
|
)
|
|
|
|
|
|
|
|
return s
|
|
|
|
|