Skip to main content
deleted 1 character in body
Source Link
P i
  • 121
  • 4

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize well beyond a binary search.

This code typically requires 5 or fewer fetches to find the nearest block to a given unix timestamp, and benchmarks ~10x faster than a binary search:

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    if ipre == ipost:
        print('Got it')
        return ipre

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    # use the discrepancy to improve our guess
    est_nblocks_from_expected_to_target = int((tunix_s - texpected) / av_block_time)
    iexpected_adj = iexpected + est_nblocks_from_expected_to_target

    print()
    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} (t={t0}) to block# {ipost} (t={t1})')
    print(f'Expected block# assuming linearity: {iexpected} (t={texpected})')
    print('Expected nblocks required to reach target (again assuming linearity):', est_nblocks_from_expected_to_target)
    print('New guess at block #:', iexpected_adj)

    r = abs(est_nblocks_from_expected_to_target)

    return iblock_near(tunix_s, iexpected_adj - r, iexpected_adj + r)

Test:

import arrow

tunix_s = arrow.get('2021-03-11T12:34:56').timestamp()

block = iblock_near(tunix_s)

Output:

enter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize well beyond a binary search.

This code typically requires 5 or fewer fetches to find the nearest block to a given unix timestamp, and benchmarks ~10x faster than a binary search:

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    if ipre == ipost:
        print('Got it')
        return ipre

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    # use the discrepancy to improve our guess
    est_nblocks_from_expected_to_target = int((tunix_s - texpected) / av_block_time)
    iexpected_adj = iexpected + est_nblocks_from_expected_to_target

    print()
    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} (t={t0}) to block# {ipost} (t={t1})')
    print(f'Expected block# assuming linearity: {iexpected} (t={texpected})')
    print('Expected nblocks required to reach target (again assuming linearity):', est_nblocks_from_expected_to_target)
    print('New guess at block #:', iexpected_adj)

    r = abs(est_nblocks_from_expected_to_target)

    return iblock_near(tunix_s, iexpected_adj - r, iexpected_adj + r)

Test:

import arrow

tunix_s = arrow.get('2021-03-11T12:34:56').timestamp()

block = iblock_near(tunix_s)

Output:

enter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize well beyond a binary search.

This code typically requires 5 or fewer fetches to find the nearest block to a given unix timestamp, and benchmarks ~10x faster than a binary search:

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    if ipre == ipost:
        print('Got it')
        return ipre

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int(ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    # use the discrepancy to improve our guess
    est_nblocks_from_expected_to_target = int((tunix_s - texpected) / av_block_time)
    iexpected_adj = iexpected + est_nblocks_from_expected_to_target

    print()
    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} (t={t0}) to block# {ipost} (t={t1})')
    print(f'Expected block# assuming linearity: {iexpected} (t={texpected})')
    print('Expected nblocks required to reach target (again assuming linearity):', est_nblocks_from_expected_to_target)
    print('New guess at block #:', iexpected_adj)

    r = abs(est_nblocks_from_expected_to_target)

    return iblock_near(tunix_s, iexpected_adj - r, iexpected_adj + r)

Test:

import arrow

tunix_s = arrow.get('2021-03-11T12:34:56').timestamp()

block = iblock_near(tunix_s)

Output:

enter image description here

added 41 characters in body
Source Link
P i
  • 121
  • 4

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize farwell beyond a binary search.

This code typically findsrequires 5 or fewer fetches to find the closestnearest block with 3 or 4 callsto a given unix timestamp, and benchmarks ~10x faster than a binary search:

from web3 import Web3, WebsocketProvider

web3 = Web3(WebsocketProvider(f'wss://:{PROJECT_SECRET}@mainnet.infura.io/ws/v3/{PROJECT_ID}'))arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest, radii=[25000, 1000, 100, 8, 1]):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost) 

    if ipre == ipost:
        print('Got it')
        return ipre

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    print()
    print(f'Searching between blocks {ipre} ({t0}) and {ipost} ({t1})')

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    off_by_nblocks# use the discrepancy to improve our guess
    est_nblocks_from_expected_to_target = abs(int((texpectedtunix_s - tunix_stexpected) / av_block_time))
    iexpected_adj = iexpected + est_nblocks_from_expected_to_target

    print()
    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} (t={t0}) to block# {ipost} (t={t1})')
    print('Expectedf'Expected block# assuming linearity:', {iexpected} (t={texpected})')
    print('Actual'Expected timestampnblocks ofrequired expectedto blockreach target (again assuming linearity):', texpectedest_nblocks_from_expected_to_target)
    print('Off'New by',guess off_by_nblocksat block #:', 'blocks'iexpected_adj)

    if off_by_nblocks == 0:
      r = printabs('GOT IT'est_nblocks_from_expected_to_target)
    else:
        return iblock_near(tunix_s, iexpectediexpected_adj - off_by_nblocksr, iexpectediexpected_adj + off_by_nblocksr)
import arrow

tunix_s = arrow.get('2018'2021-0603-11T12:34:56').timestamp() 

block = iblock_near(tunix_s)

enter image description hereenter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize far beyond a binary search.

This code typically finds the closest block with 3 or 4 calls:

from web3 import Web3, WebsocketProvider

web3 = Web3(WebsocketProvider(f'wss://:{PROJECT_SECRET}@mainnet.infura.io/ws/v3/{PROJECT_ID}'))

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest, radii=[25000, 1000, 100, 8, 1]):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    print()
    print(f'Searching between blocks {ipre} ({t0}) and {ipost} ({t1})')

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    off_by_nblocks = abs(int((texpected - tunix_s) / av_block_time))

    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} ({t0}) to block# {ipost} ({t1})')
    print('Expected block#:', iexpected)
    print('Actual timestamp of expected block:', texpected)
    print('Off by', off_by_nblocks, 'blocks')

    if off_by_nblocks == 0:
        print('GOT IT')
    else:
        return iblock_near(tunix_s, iexpected - off_by_nblocks, iexpected + off_by_nblocks)
import arrow

tunix_s = arrow.get('2018-06-11T12:34:56').timestamp()
block = iblock_near(tunix_s)

enter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize well beyond a binary search.

This code typically requires 5 or fewer fetches to find the nearest block to a given unix timestamp, and benchmarks ~10x faster than a binary search:

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost) 

    if ipre == ipost:
        print('Got it')
        return ipre

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    # use the discrepancy to improve our guess
    est_nblocks_from_expected_to_target = int((tunix_s - texpected) / av_block_time)
    iexpected_adj = iexpected + est_nblocks_from_expected_to_target

    print()
    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} (t={t0}) to block# {ipost} (t={t1})')
    print(f'Expected block# assuming linearity: {iexpected} (t={texpected})')
    print('Expected nblocks required to reach target (again assuming linearity):', est_nblocks_from_expected_to_target)
    print('New guess at block #:', iexpected_adj)

    r = abs(est_nblocks_from_expected_to_target)

    return iblock_near(tunix_s, iexpected_adj - r, iexpected_adj + r)
import arrow

tunix_s = arrow.get('2021-03-11T12:34:56').timestamp() 

block = iblock_near(tunix_s)

enter image description here

deleted 7 characters in body
Source Link
P i
  • 121
  • 4

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize far beyond a binary search.

This code typically finds the closest block with 3 or 4 calls:

from web3 import Web3, WebsocketProvider

web3 = Web3(WebsocketProvider(f'wss://:{PROJECT_SECRET}@mainnet.infura.io/ws/v3/{PROJECT_ID}'))

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=web3.eth.get_block('latest')['number']ipost=ilatest, radii=[25000, 1000, 100, 8, 1]):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    print()
    print(f'Searching between blocks {ipre} ({t0}) and {ipost} ({t1})')

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    off_by_nblocks = abs(int((texpected - tunix_s) / av_block_time))

    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} ({t0}) to block# {ipost} ({t1})')
    print('Expected block#:', iexpected)
    print('Actual timestamp of expected block:', texpected)
    print('Off by', off_by_nblocks, 'blocks')

    if off_by_nblocks == 0:
        print('GOT IT')
    else:
        return iblock_near(tunix_s, iexpected - off_by_nblocks, iexpected + off_by_nblocks)

Test:

import arrow

tunix_s = arrow.get('2018-06-11T12:34:56').timestamp()
block = iblock_near(tunix_s)

Output:

enter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize far beyond a binary search.

This code typically finds the closest block with 3 or 4 calls:

from web3 import Web3, WebsocketProvider

web3 = Web3(WebsocketProvider(f'wss://:{PROJECT_SECRET}@mainnet.infura.io/ws/v3/{PROJECT_ID}'))

import  arrow

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=web3.eth.get_block('latest')['number'], radii=[25000, 1000, 100, 8, 1]):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    print()
    print(f'Searching between blocks {ipre} ({t0}) and {ipost} ({t1})')

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    off_by_nblocks = abs(int((texpected - tunix_s) / av_block_time))

    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} ({t0}) to block# {ipost} ({t1})')
    print('Expected block#:', iexpected)
    print('Actual timestamp of expected block:', texpected)
    print('Off by', off_by_nblocks, 'blocks')

    if off_by_nblocks == 0:
        print('GOT IT')
    else:
        return iblock_near(tunix_s, iexpected - off_by_nblocks, iexpected + off_by_nblocks)

tunix_s = arrow.get('2018-06-11T12:34:56').timestamp()
block = iblock_near(tunix_s)

Output:

enter image description here

It's actually possible to use the fact that block-times are locally roughly linearly separated to optimize far beyond a binary search.

This code typically finds the closest block with 3 or 4 calls:

from web3 import Web3, WebsocketProvider

web3 = Web3(WebsocketProvider(f'wss://:{PROJECT_SECRET}@mainnet.infura.io/ws/v3/{PROJECT_ID}'))

T = lambda i_block: web3.eth.getBlock(i_block).timestamp

ilatest = web3.eth.get_block('latest')['number']

def iblock_near(tunix_s, ipre=1, ipost=ilatest, radii=[25000, 1000, 100, 8, 1]):
    ipre = max(1, ipre)
    ipost = min(ilatest, ipost)

    t0, t1 = T(ipre), T(ipost)

    av_block_time = (t1 - t0) / (ipost-ipre)

    print()
    print(f'Searching between blocks {ipre} ({t0}) and {ipost} ({t1})')

    # if block-times were evenly-spaced, get expected block number
    k = (tunix_s - t0) / (t1-t0)
    iexpected = int( ipre + k * (ipost - ipre))

    # get the ACTUAL time for that block
    texpected = T(iexpected)

    off_by_nblocks = abs(int((texpected - tunix_s) / av_block_time))

    print(f'target timestamp ({tunix_s}) lies {k:.3f} of the way from block# {ipre} ({t0}) to block# {ipost} ({t1})')
    print('Expected block#:', iexpected)
    print('Actual timestamp of expected block:', texpected)
    print('Off by', off_by_nblocks, 'blocks')

    if off_by_nblocks == 0:
        print('GOT IT')
    else:
        return iblock_near(tunix_s, iexpected - off_by_nblocks, iexpected + off_by_nblocks)

Test:

import arrow

tunix_s = arrow.get('2018-06-11T12:34:56').timestamp()
block = iblock_near(tunix_s)

Output:

enter image description here

Source Link
P i
  • 121
  • 4
Loading