Skip to content

Commit

Permalink
Merge pull request #320 from bancorprotocol/fix-non-integer-block-num…
Browse files Browse the repository at this point in the history
…ber-calculation

Fix the calculation of a non-integer block number
  • Loading branch information
mikewcasale authored Jan 24, 2024
2 parents 415e0f2 + c043c6c commit cab8872
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 41 deletions.
55 changes: 15 additions & 40 deletions fastlane_bot/events/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 5 additions & 0 deletions fastlane_bot/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"))])

Expand Down
7 changes: 6 additions & 1 deletion run_blockchain_terraformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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):
Expand Down
74 changes: 74 additions & 0 deletions test_get_start_block.py
Original file line number Diff line number Diff line change
@@ -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)}"

0 comments on commit cab8872

Please sign in to comment.