Allow partial results from the db

This commit is contained in:
Luke Van Seters 2022-01-12 20:16:31 -05:00
parent 72433ece39
commit 93c7998e22

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import logging import logging
from typing import List, Optional from collections.abc import Awaitable
from typing import Callable, List, Optional, TypeVar
from sqlalchemy import orm from sqlalchemy import orm
from web3 import Web3 from web3 import Web3
@ -12,6 +13,7 @@ from mev_inspect.schemas.traces import Trace, TraceType
from mev_inspect.utils import hex_to_int from mev_inspect.utils import hex_to_int
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
T = TypeVar("T")
async def get_latest_block_number(base_provider) -> int: async def get_latest_block_number(base_provider) -> int:
@ -28,62 +30,33 @@ async def create_from_block_number(
block_number: int, block_number: int,
trace_db_session: Optional[orm.Session], trace_db_session: Optional[orm.Session],
) -> Block: ) -> Block:
block: Optional[Block] = None existing_block_timestamp = None
existing_base_fee_per_gas = None
existing_traces = None
existing_receipts = None
if trace_db_session is not None: if trace_db_session is not None:
block = _find_block(trace_db_session, block_number) existing_block_timestamp = _find_block_timestamp(trace_db_session, block_number)
existing_base_fee_per_gas = _find_base_fee(trace_db_session, block_number)
existing_traces = _find_traces(trace_db_session, block_number)
existing_receipts = _find_receipts(trace_db_session, block_number)
if block is None: block_timestamp, receipts, traces, base_fee_per_gas = await asyncio.gather(
block = await _fetch_block(w3, block_number) _await_if_absent(
return block lambda: _fetch_block_timestamp(w3, block_number), existing_block_timestamp
else: ),
return block _await_if_absent(
lambda: _fetch_block_receipts(w3, block_number), existing_receipts
),
async def _fetch_block(w3, block_number: int) -> Block: _await_if_absent(
block_json, receipts_json, traces_json, base_fee_per_gas = await asyncio.gather( lambda: _fetch_block_traces(w3, block_number), existing_traces
w3.eth.get_block(block_number), ),
w3.eth.get_block_receipts(block_number), _await_if_absent(
w3.eth.trace_block(block_number), lambda: fetch_base_fee_per_gas(w3, block_number), existing_base_fee_per_gas
fetch_base_fee_per_gas(w3, block_number), ),
) )
receipts: List[Receipt] = [Receipt(**receipt) for receipt in receipts_json]
traces = [Trace(**trace_json) for trace_json in traces_json]
return Block(
block_number=block_number,
block_timestamp=block_json["timestamp"],
miner=block_json["miner"],
base_fee_per_gas=base_fee_per_gas,
traces=traces,
receipts=receipts,
)
def _find_block(
trace_db_session: orm.Session,
block_number: int,
) -> Optional[Block]:
block_timestamp = _find_block_timestamp(trace_db_session, block_number)
if block_timestamp is None:
return None
base_fee_per_gas = _find_base_fee(trace_db_session, block_number)
if base_fee_per_gas is None:
return None
traces = _find_traces(trace_db_session, block_number)
if traces is None:
return None
receipts = _find_receipts(trace_db_session, block_number)
if receipts is None:
return None
miner_address = _get_miner_address_from_traces(traces) miner_address = _get_miner_address_from_traces(traces)
if miner_address is None:
return None
return Block( return Block(
block_number=block_number, block_number=block_number,
@ -95,6 +68,30 @@ def _find_block(
) )
async def _fetch_block_timestamp(w3, block_number: int) -> int:
block_json = await w3.eth.get_block(block_number)
return block_json["timestamp"]
async def _fetch_block_receipts(w3, block_number: int) -> List[Receipt]:
receipts_json = await w3.eth.get_block_receipts(block_number)
return [Receipt(**receipt) for receipt in receipts_json]
async def _fetch_block_traces(w3, block_number: int) -> List[Trace]:
traces_json = await w3.eth.trace_block(block_number)
return [Trace(**trace_json) for trace_json in traces_json]
async def _await_if_absent(
awaitable: Callable[[], Awaitable[T]], existing: Optional[T]
) -> T:
if existing is not None:
return existing
else:
return await awaitable()
def _find_block_timestamp( def _find_block_timestamp(
trace_db_session: orm.Session, trace_db_session: orm.Session,
block_number: int, block_number: int,
@ -116,7 +113,7 @@ def _find_traces(
block_number: int, block_number: int,
) -> Optional[List[Trace]]: ) -> Optional[List[Trace]]:
result = trace_db_session.execute( result = trace_db_session.execute(
"SELECT raw_traces FROM block_traces WHERE block_number = :block_number", "SELECT raw_traces FROM block_traces WHERE block_number = :block_number LIMIT 1",
params={"block_number": block_number}, params={"block_number": block_number},
).one_or_none() ).one_or_none()