runner workarounds for hardhat
This commit is contained in:
@@ -16,8 +16,9 @@ class Block(Base):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def timestamp(self) -> int:
|
def timestamp(self) -> int:
|
||||||
|
raw = self.data['timestamp']
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
return hexint(self.data['timestamp'])
|
return raw if type(raw) is int else hexint(raw)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.height}_{self.hash.hex()[:5]}'
|
return f'{self.height}_{self.hash.hex()[:5]}'
|
||||||
|
|||||||
@@ -150,11 +150,16 @@ class BlockStateRunner:
|
|||||||
|
|
||||||
while self.running:
|
while self.running:
|
||||||
try:
|
try:
|
||||||
new_blocks = await w3.eth.filter("latest")
|
# polling mode is used primarily because Hardhat fails to deliver newHeads events after about an hour
|
||||||
for head in await new_blocks.get_new_entries():
|
# unfortunately, hardhat also stops responding to eth_getBlockByHash. so instead, we use the standard (stupid)
|
||||||
|
# 'latest' polling for blocks, and we push the entire block to the queue since apparently this is the only
|
||||||
|
# rpc call Hardhat seems to consistently support. The worker must then detect the type of object pushed to the
|
||||||
|
# work queue and either use the block directly or query for the block if the queue object is a hashcode.
|
||||||
|
block = await w3.eth.get_block('latest')
|
||||||
|
head = block['hash']
|
||||||
if head != prev_blockhash:
|
if head != prev_blockhash:
|
||||||
prev_blockhash = head
|
prev_blockhash = head
|
||||||
await self.queue.put(head)
|
await self.queue.put(block)
|
||||||
log.debug(f'polled new block {hexstr(head)}')
|
log.debug(f'polled new block {hexstr(head)}')
|
||||||
if not self.running:
|
if not self.running:
|
||||||
break
|
break
|
||||||
@@ -187,7 +192,7 @@ class BlockStateRunner:
|
|||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
# 1 second has passed without a new head. Run the postprocess callbacks to check for activated time-based triggers
|
# 1 second has passed without a new head. Run the postprocess callbacks to check for activated time-based triggers
|
||||||
if prev_head is not None:
|
if prev_head is not None:
|
||||||
await self.handle_time_tick(head)
|
await self.handle_time_tick(prev_head)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
await self.handle_head(chain, head, w3)
|
await self.handle_head(chain, head, w3)
|
||||||
@@ -202,21 +207,26 @@ class BlockStateRunner:
|
|||||||
|
|
||||||
|
|
||||||
async def handle_head(self, chain, blockhash, w3):
|
async def handle_head(self, chain, blockhash, w3):
|
||||||
log.debug(f'processing block {hexstr(blockhash)}')
|
# check blockhash type and convert
|
||||||
|
try:
|
||||||
|
block_data = blockhash
|
||||||
|
blockhash = block_data['hash']
|
||||||
|
parent = block_data['parentHash']
|
||||||
|
height = block_data['number']
|
||||||
|
except TypeError:
|
||||||
|
response = await w3.provider.make_request('eth_getBlockByHash', [blockhash, False])
|
||||||
|
block_data:dict = response['result']
|
||||||
|
parent = bytes.fromhex(block_data['parentHash'][2:])
|
||||||
|
height = int(block_data['number'], 0)
|
||||||
|
log.debug(f'processing block {blockhash}')
|
||||||
chain_id = chain.chain_id
|
chain_id = chain.chain_id
|
||||||
session = None
|
session = None
|
||||||
try:
|
try:
|
||||||
blockhash = hexstr(blockhash)
|
|
||||||
if self.state is not None and blockhash in self.state.by_hash:
|
if self.state is not None and blockhash in self.state.by_hash:
|
||||||
|
log.debug(f'block {blockhash} was already processed')
|
||||||
return
|
return
|
||||||
# block_data = await w3.eth.get_block(head['hash'], True)
|
assert block_data is not None
|
||||||
response = await w3.provider.make_request('eth_getBlockByHash', [blockhash, False])
|
block = Block(chain=chain_id, height=height, hash=blockhash, parent=parent, data=block_data)
|
||||||
block_data = response['result']
|
|
||||||
if block_data is None:
|
|
||||||
log.warning(f'block data for {blockhash} was None')
|
|
||||||
return # todo get block when hardhat stops responding to getBlockByHash
|
|
||||||
block = Block(chain=chain_id, height=int(block_data['number'], 0),
|
|
||||||
hash=bytes.fromhex(block_data['hash'][2:]), parent=bytes.fromhex(block_data['parentHash'][2:]), data=block_data)
|
|
||||||
latest_block.set(block)
|
latest_block.set(block)
|
||||||
current_clock.get().set(block.timestamp)
|
current_clock.get().set(block.timestamp)
|
||||||
if self.state is None:
|
if self.state is None:
|
||||||
@@ -329,8 +339,16 @@ class BlockStateRunner:
|
|||||||
async def handle_time_tick(self, blockhash):
|
async def handle_time_tick(self, blockhash):
|
||||||
if current_blockstate.get() is None:
|
if current_blockstate.get() is None:
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
|
blockhash = blockhash['hash']
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
# similar to handle_head, but we only call the postprocess events, since there was only a time tick and no new block data
|
# similar to handle_head, but we only call the postprocess events, since there was only a time tick and no new block data
|
||||||
|
try:
|
||||||
block = self.state.by_hash[blockhash]
|
block = self.state.by_hash[blockhash]
|
||||||
|
except KeyError:
|
||||||
|
log.warning(f'No block data for {blockhash}. Aborting time tick.')
|
||||||
|
return
|
||||||
fork = self.state.fork(block)
|
fork = self.state.fork(block)
|
||||||
current_block.set(block)
|
current_block.set(block)
|
||||||
current_fork.set(fork)
|
current_fork.set(fork)
|
||||||
|
|||||||
Reference in New Issue
Block a user