diff --git a/fastlane_bot/events/utils.py b/fastlane_bot/events/utils.py index 4dfeb7f62..daa895ea6 100644 --- a/fastlane_bot/events/utils.py +++ b/fastlane_bot/events/utils.py @@ -33,6 +33,7 @@ from fastlane_bot.events.multicall_utils import encode_token_price from fastlane_bot.events.pools import CarbonV1Pool from fastlane_bot.helpers import TxHelpers +from fastlane_bot.utils import safe_int def filter_latest_events( @@ -1335,49 +1336,23 @@ def get_start_block( Returns ------- Tuple[int, int or None] - The starting block number. + The starting block number and the block number to replay from. """ - if replay_from_block: - return ( - replay_from_block - 1 - if last_block != 0 - else replay_from_block - reorg_delay - alchemy_max_block_fetch - ), replay_from_block - elif mgr.tenderly_fork_id: - # connect to the Tenderly fork and get the latest block number - from_block = mgr.w3_tenderly.eth.block_number - # Log all non-integer block numbers - non_int_values = [ - (index, block["last_updated_block"], type(block["last_updated_block"])) - for index, block in enumerate(mgr.pool_data) if type(block["last_updated_block"]) is not int - ] - if non_int_values: - mgr.cfg.logger.info(f"[events.utils.get_start_block] non_int_values: {non_int_values}") - return ( - max(block["last_updated_block"] for block in mgr.pool_data) - reorg_delay - if last_block != 0 - else from_block - reorg_delay - alchemy_max_block_fetch - ), from_block + if last_block == 0: + if replay_from_block: + return replay_from_block - reorg_delay - alchemy_max_block_fetch, replay_from_block + elif mgr.tenderly_fork_id: + return mgr.w3_tenderly.eth.block_number - reorg_delay - alchemy_max_block_fetch, mgr.w3_tenderly.eth.block_number + else: + return mgr.web3.eth.block_number - reorg_delay - alchemy_max_block_fetch, None else: - current_block = mgr.web3.eth.block_number - # Log all non-integer block numbers - non_int_values = [ - (index, block["last_updated_block"], type(block["last_updated_block"])) - for index, block in enumerate(mgr.pool_data) if type(block["last_updated_block"]) is not int - ] - if non_int_values: - mgr.cfg.logger.info(f"[events.utils.get_start_block] non_int_values: {non_int_values}") - return ( - ( - max(block["last_updated_block"] for block in mgr.pool_data) - - reorg_delay - if last_block != 0 - else current_block - reorg_delay - alchemy_max_block_fetch - ), - None, - ) - + if replay_from_block: + return replay_from_block - 1, replay_from_block + elif mgr.tenderly_fork_id: + return safe_int(max(block["last_updated_block"] for block in mgr.pool_data)) - reorg_delay, mgr.w3_tenderly.eth.block_number + else: + return safe_int(max(block["last_updated_block"] for block in mgr.pool_data)) - reorg_delay, None def get_tenderly_block_number(tenderly_fork_id: str) -> int: diff --git a/fastlane_bot/utils.py b/fastlane_bot/utils.py index 615d06731..31d5db307 100644 --- a/fastlane_bot/utils.py +++ b/fastlane_bot/utils.py @@ -23,6 +23,11 @@ from fastlane_bot.data.abi import * +def safe_int(value: int or float) -> int: + assert value == int(value), f"non-integer `float` value {value}" + return int(value) + + def int_prefix(string: str) -> int: return int(string[:-len(string.lstrip("0123456789"))]) diff --git a/run_blockchain_terraformer.py b/run_blockchain_terraformer.py index 1ace652fc..ff6ebdae1 100644 --- a/run_blockchain_terraformer.py +++ b/run_blockchain_terraformer.py @@ -13,6 +13,7 @@ from web3 import Web3 from fastlane_bot.data.abi import * +from fastlane_bot.utils import safe_int ETHEREUM = "ethereum" POLYGON = "polygon" @@ -1127,7 +1128,11 @@ def get_last_block_updated(df: pd.DataFrame, exchange: str) -> int: """ ex_df = df[df["exchange"] == exchange] - return ex_df["last_updated_block"].max() + + # if the `last_updated_block` column contains `None` values, then `max` returns a value of type `float` + # we should therefore verify that this value is nevertheless integer + # and only then can we safely convert it to type `int` + return safe_int(ex_df["last_updated_block"].max()) def save_token_data(token_dict: TokenManager, write_path: str): diff --git a/test_get_start_block.py b/test_get_start_block.py new file mode 100644 index 000000000..392b2ca72 --- /dev/null +++ b/test_get_start_block.py @@ -0,0 +1,74 @@ +from fastlane_bot.events.utils import get_start_block as new_get_start_block + +def old_get_start_block( + alchemy_max_block_fetch: int, + last_block: int, + mgr: any, + reorg_delay: int, + replay_from_block: int, +) -> (int, int or None): + if replay_from_block: + return ( + replay_from_block - 1 + if last_block != 0 + else replay_from_block - reorg_delay - alchemy_max_block_fetch + ), replay_from_block + elif mgr.tenderly_fork_id: + from_block = mgr.w3_tenderly.eth.block_number + return ( + max(block["last_updated_block"] for block in mgr.pool_data) - reorg_delay + if last_block != 0 + else from_block - reorg_delay - alchemy_max_block_fetch + ), from_block + else: + current_block = mgr.web3.eth.block_number + return ( + ( + max(block["last_updated_block"] for block in mgr.pool_data) + - reorg_delay + if last_block != 0 + else current_block - reorg_delay - alchemy_max_block_fetch + ), + None + ) + +class ETH: + def __init__(self, block_number: int): + self.block_number = block_number + +class Web3: + def __init__(self, block_number: int): + self.eth = ETH(block_number) + +class MGR: + def __init__(self, tenderly_fork_id: bool, w3_tenderly_block_number: int, web3_block_number: int, pool_block_numbers: list[int or float]): + self.tenderly_fork_id = tenderly_fork_id + self.w3_tenderly = Web3(w3_tenderly_block_number) + self.web3 = Web3(web3_block_number) + self.pool_data = [{"last_updated_block": pool_block_number} for pool_block_number in pool_block_numbers] + +for alchemy_max_block_fetch in range(10): + for last_block in [0, 1]: + for reorg_delay in range(10): + for replay_from_block in range(10): + for tenderly_fork_id in [False, True]: + for w3_tenderly_block_number in range(10): + for web3_block_number in range(10): + for pool_block_numbers in [[1, 2], [1, 2.0], [1.0, 2], [1.0, 2.0]]: + print( + f"alchemy_max_block_fetch = {alchemy_max_block_fetch }\n" + + f"last_block = {last_block }\n" + + f"reorg_delay = {reorg_delay }\n" + + f"replay_from_block = {replay_from_block }\n" + + f"tenderly_fork_id = {tenderly_fork_id }\n" + + f"web3_block_number = {web3_block_number }\n" + + f"pool_block_numbers = {pool_block_numbers }\n" + ) + mgr = MGR(tenderly_fork_id, w3_tenderly_block_number, web3_block_number, pool_block_numbers) + expected = old_get_start_block(alchemy_max_block_fetch, last_block, mgr, reorg_delay, replay_from_block) + actual = new_get_start_block(alchemy_max_block_fetch, last_block, mgr, reorg_delay, replay_from_block) + for e, a in zip(expected, actual): + if type(e) is float: + assert type(a) is int and a == e, f"expected value {e} of type int, got value {a} of type {type(a)}" + else: + assert type(a) is type(e) and a == e, f"expected value {e} of type {type(e)}, got value {a} of type {type(a)}"