From dee2b09ebe4ec67699dfe5735c7f2420b70600e6 Mon Sep 17 00:00:00 2001 From: cyan Date: Mon, 13 Apr 2026 23:42:32 +0200 Subject: [PATCH] fix: get height by date for monero (#3158) --- cw_core/lib/get_height_by_date.dart | 171 +--------- cw_core/lib/get_height_by_date_xmr.dart | 422 ++++++++++++++++++++++++ 2 files changed, 434 insertions(+), 159 deletions(-) create mode 100644 cw_core/lib/get_height_by_date_xmr.dart diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 4786336af..58155a7fb 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -1,163 +1,12 @@ import 'package:cw_core/utils/proxy_wrapper.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:intl/intl.dart'; +import 'package:cw_core/get_height_by_date_xmr.dart'; import 'dart:convert'; // FIXME: Hardcoded values; Works only for monero -final dateFormat = DateFormat('yyyy-MM'); -final dates = { - "2014-5": 18844, - "2014-6": 65406, - "2014-7": 108882, - "2014-8": 153594, - "2014-9": 198072, - "2014-10": 241088, - "2014-11": 285305, - "2014-12": 328069, - "2015-1": 372369, - "2015-2": 416505, - "2015-3": 456631, - "2015-4": 501084, - "2015-5": 543973, - "2015-6": 588326, - "2015-7": 631187, - "2015-8": 675484, - "2015-9": 719725, - "2015-10": 762463, - "2015-11": 806528, - "2015-12": 849041, - "2016-1": 892866, - "2016-2": 936736, - "2016-3": 977691, - "2016-4": 1015848, - "2016-5": 1037417, - "2016-6": 1059651, - "2016-7": 1081269, - "2016-8": 1103630, - "2016-9": 1125983, - "2016-10": 1147617, - "2016-11": 1169779, - "2016-12": 1191402, - "2017-1": 1213861, - "2017-2": 1236197, - "2017-3": 1256358, - "2017-4": 1278622, - "2017-5": 1300239, - "2017-6": 1322564, - "2017-7": 1344225, - "2017-8": 1366664, - "2017-9": 1389113, - "2017-10": 1410738, - "2017-11": 1433039, - "2017-12": 1454639, - "2018-1": 1477201, - "2018-2": 1499599, - "2018-3": 1519796, - "2018-4": 1542067, - "2018-5": 1562861, - "2018-6": 1585135, - "2018-7": 1606715, - "2018-8": 1629017, - "2018-9": 1651347, - "2018-10": 1673031, - "2018-11": 1695128, - "2018-12": 1716687, - "2019-1": 1738923, - "2019-2": 1761435, - "2019-3": 1781681, - "2019-4": 1803081, - "2019-5": 1824671, - "2019-6": 1847005, - "2019-7": 1868590, - "2019-8": 1890552, - "2019-9": 1912212, - "2019-10": 1932200, - "2019-11": 1957040, - "2019-12": 1978090, - "2020-1": 2001290, - "2020-2": 2022688, - "2020-3": 2043987, - "2020-4": 2066536, - "2020-5": 2090797, - "2020-6": 2111633, - "2020-7": 2131433, - "2020-8": 2153983, - "2020-9": 2176466, - "2020-10": 2198453, - "2020-11": 2220000, - "2020-12": 2242240, - "2021-1": 2264584, - "2021-2": 2286892, - "2021-3": 2307079, - "2021-4": 2329385, - "2021-5": 2351004, - "2021-6": 2373306, - "2021-7": 2394882, - "2021-8": 2417162, - "2021-9": 2439490, - "2021-10": 2461020, - "2021-11": 2483377, - "2021-12": 2504932, - "2022-1": 2527316, - "2022-2": 2549605, - "2022-3": 2569711, - "2022-4": 2591995, - "2022-5": 2613603, - "2022-6": 2635840, - "2022-7": 2657395, - "2022-8": 2679705, - "2022-9": 2701991, - "2022-10": 2723607, - "2022-11": 2745899, - "2022-12": 2767427, - "2023-1": 2789763, - "2023-2": 2811996, - "2023-3": 2832118, - "2023-4": 2854365, - "2023-5": 2875972, - "2023-6": 2898234, - "2023-7": 2919771, - "2023-8": 2942045, - "2023-9": 2964280, - "2023-10": 2985937, - "2023-11": 3008178, - "2023-12": 3029759 -}; - -int getMoneroHeigthByDate({required DateTime date}) { - final raw = '${date.year}' + '-' + '${date.month}'; - final lastHeight = dates.values.last; - int startHeight; - int endHeight; - int height = 0; - - try { - if ((dates[raw] == null) || (dates[raw] == lastHeight)) { - startHeight = dates.values.toList()[dates.length - 2]; - endHeight = dates.values.toList()[dates.length - 1]; - final heightPerDay = (endHeight - startHeight) / 31; - final endDateRaw = dates.keys.toList()[dates.length - 1].split('-'); - final endYear = int.parse(endDateRaw[0]); - final endMonth = int.parse(endDateRaw[1]); - final endDate = DateTime(endYear, endMonth); - final differenceInDays = date.difference(endDate).inDays; - final daysHeight = (differenceInDays * heightPerDay).round(); - height = endHeight + daysHeight; - } else { - startHeight = dates[raw]!; - final index = dates.values.toList().indexOf(startHeight); - endHeight = dates.values.toList()[index + 1]; - final heightPerDay = ((endHeight - startHeight) / 31).round(); - final daysHeight = (date.day - 1) * heightPerDay; - height = startHeight + daysHeight - heightPerDay; - } - } catch (e) { - printV(e.toString()); - } - - return height; -} +int getMoneroHeigthByDate({required DateTime date}) => MoneroHeight.getBlockHeightByTime(date..subtract(Duration(days: 1))); const havenDates = { "2023-05": 1352995, @@ -223,6 +72,7 @@ const havenDates = { "2018-04": 32000, "2018-03": 8500 }; +final dateFormat = DateFormat('yyyy-MM'); DateTime formatMapKey(String key) => dateFormat.parse(key); @@ -234,9 +84,10 @@ int getHavenHeightByDate({required DateTime date}) { } Future getHavenCurrentHeight() async { - final req = await ProxyWrapper().getHttpClient() - .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo')) - .timeout(Duration(seconds: 15)); + final req = await ProxyWrapper() + .getHttpClient() + .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo')) + .timeout(Duration(seconds: 15)); final response = await req.close(); final stringResponse = await response.transform(utf8.decoder).join(); @@ -273,9 +124,11 @@ const bitcoinDates = { }; Future getBitcoinHeightByDateAPI({required DateTime date}) async { - final req = await ProxyWrapper().getHttpClient() - .getUrl(Uri.parse("https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}")) - .timeout(Duration(seconds: 15)); + final req = await ProxyWrapper() + .getHttpClient() + .getUrl(Uri.parse( + "https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}")) + .timeout(Duration(seconds: 15)); final response = await req.close(); final stringResponse = await response.transform(utf8.decoder).join(); diff --git a/cw_core/lib/get_height_by_date_xmr.dart b/cw_core/lib/get_height_by_date_xmr.dart new file mode 100644 index 000000000..16a1b2002 --- /dev/null +++ b/cw_core/lib/get_height_by_date_xmr.dart @@ -0,0 +1,422 @@ + +class MoneroHeight { + // for i in $(seq 1 364); do echo "_Checkpoint(_t($(curl https://xmrchain.net/block/${i}0000 | grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | xargs | sed 's/ /\n/g' | head -5 | tail -1 | tr '()' ' ' | sed 's/ /\n/g' | head -2 | xargs)), ${i}0000),"; done > points.txt + static final List<_Checkpoint> _points = [ + _Checkpoint(1398386790, 10000), + _Checkpoint(1398970097, 20000), + _Checkpoint(1399529049, 30000), + _Checkpoint(1400107914, 40000), + _Checkpoint(1400673084, 50000), + _Checkpoint(1401259431, 60000), + _Checkpoint(1401861514, 70000), + _Checkpoint(1402455081, 80000), + _Checkpoint(1403051337, 90000), + _Checkpoint(1403639801, 100000), + _Checkpoint(1404238831, 110000), + _Checkpoint(1404841666, 120000), + _Checkpoint(1405444927, 130000), + _Checkpoint(1406035044, 140000), + _Checkpoint(1406634825, 150000), + _Checkpoint(1407238604, 160000), + _Checkpoint(1407838442, 170000), + _Checkpoint(1408443936, 180000), + _Checkpoint(1409041095, 190000), + _Checkpoint(1409644412, 200000), + _Checkpoint(1410247699, 210000), + _Checkpoint(1410851018, 220000), + _Checkpoint(1411455976, 230000), + _Checkpoint(1412059180, 240000), + _Checkpoint(1412661506, 250000), + _Checkpoint(1413267445, 260000), + _Checkpoint(1413873271, 270000), + _Checkpoint(1414480925, 280000), + _Checkpoint(1415086077, 290000), + _Checkpoint(1415690591, 300000), + _Checkpoint(1416296909, 310000), + _Checkpoint(1416902704, 320000), + _Checkpoint(1417507901, 330000), + _Checkpoint(1418109054, 340000), + _Checkpoint(1418722232, 350000), + _Checkpoint(1419326271, 360000), + _Checkpoint(1419928389, 370000), + _Checkpoint(1420541216, 380000), + _Checkpoint(1421145579, 390000), + _Checkpoint(1421749732, 400000), + _Checkpoint(1422354623, 410000), + _Checkpoint(1422956207, 420000), + _Checkpoint(1423562393, 430000), + _Checkpoint(1424166115, 440000), + _Checkpoint(1424767351, 450000), + _Checkpoint(1425371690, 460000), + _Checkpoint(1425975620, 470000), + _Checkpoint(1426579077, 480000), + _Checkpoint(1427182546, 490000), + _Checkpoint(1427785048, 500000), + _Checkpoint(1428385900, 510000), + _Checkpoint(1428990297, 520000), + _Checkpoint(1429593770, 530000), + _Checkpoint(1430197340, 540000), + _Checkpoint(1430803986, 550000), + _Checkpoint(1431408119, 560000), + _Checkpoint(1432011390, 570000), + _Checkpoint(1432613317, 580000), + _Checkpoint(1433222583, 590000), + _Checkpoint(1433825715, 600000), + _Checkpoint(1434431094, 610000), + _Checkpoint(1435033265, 620000), + _Checkpoint(1435636924, 630000), + _Checkpoint(1436243604, 640000), + _Checkpoint(1436848163, 650000), + _Checkpoint(1437455928, 660000), + _Checkpoint(1438056769, 670000), + _Checkpoint(1438662194, 680000), + _Checkpoint(1439267688, 690000), + _Checkpoint(1439872751, 700000), + _Checkpoint(1440479855, 710000), + _Checkpoint(1441084930, 720000), + _Checkpoint(1441690778, 730000), + _Checkpoint(1442300128, 740000), + _Checkpoint(1442902966, 750000), + _Checkpoint(1443510081, 760000), + _Checkpoint(1444120229, 770000), + _Checkpoint(1444725863, 780000), + _Checkpoint(1445334248, 790000), + _Checkpoint(1445938467, 800000), + _Checkpoint(1446548650, 810000), + _Checkpoint(1447157167, 820000), + _Checkpoint(1447766950, 830000), + _Checkpoint(1448375042, 840000), + _Checkpoint(1448982313, 850000), + _Checkpoint(1449591976, 860000), + _Checkpoint(1450206082, 870000), + _Checkpoint(1450817995, 880000), + _Checkpoint(1451431001, 890000), + _Checkpoint(1452044620, 900000), + _Checkpoint(1452654325, 910000), + _Checkpoint(1453271464, 920000), + _Checkpoint(1453874045, 930000), + _Checkpoint(1454490333, 940000), + _Checkpoint(1455096906, 950000), + _Checkpoint(1455704830, 960000), + _Checkpoint(1456315340, 970000), + _Checkpoint(1456926968, 980000), + _Checkpoint(1457536684, 990000), + _Checkpoint(1458145453, 1000000), + _Checkpoint(1458780543, 1010000), + _Checkpoint(1459961331, 1020000), + _Checkpoint(1461174469, 1030000), + _Checkpoint(1462375809, 1040000), + _Checkpoint(1463578591, 1050000), + _Checkpoint(1464785682, 1060000), + _Checkpoint(1465981307, 1070000), + _Checkpoint(1467185150, 1080000), + _Checkpoint(1468365704, 1090000), + _Checkpoint(1469573151, 1100000), + _Checkpoint(1470777161, 1110000), + _Checkpoint(1471975662, 1120000), + _Checkpoint(1473164186, 1130000), + _Checkpoint(1474374066, 1140000), + _Checkpoint(1475577458, 1150000), + _Checkpoint(1476776898, 1160000), + _Checkpoint(1477990372, 1170000), + _Checkpoint(1479187102, 1180000), + _Checkpoint(1480378008, 1190000), + _Checkpoint(1481575804, 1200000), + _Checkpoint(1482772399, 1210000), + _Checkpoint(1483965031, 1220000), + _Checkpoint(1485170094, 1230000), + _Checkpoint(1486369447, 1240000), + _Checkpoint(1487569956, 1250000), + _Checkpoint(1488775148, 1260000), + _Checkpoint(1489970122, 1270000), + _Checkpoint(1491168799, 1280000), + _Checkpoint(1492371569, 1290000), + _Checkpoint(1493568547, 1300000), + _Checkpoint(1494770503, 1310000), + _Checkpoint(1495965162, 1320000), + _Checkpoint(1497168519, 1330000), + _Checkpoint(1498361038, 1340000), + _Checkpoint(1499552117, 1350000), + _Checkpoint(1500747868, 1360000), + _Checkpoint(1501946180, 1370000), + _Checkpoint(1503149952, 1380000), + _Checkpoint(1504330700, 1390000), + _Checkpoint(1505525706, 1400000), + _Checkpoint(1506725266, 1410000), + _Checkpoint(1507924408, 1420000), + _Checkpoint(1509129536, 1430000), + _Checkpoint(1510332372, 1440000), + _Checkpoint(1511529796, 1450000), + _Checkpoint(1512713363, 1460000), + _Checkpoint(1513909535, 1470000), + _Checkpoint(1515100139, 1480000), + _Checkpoint(1516298977, 1490000), + _Checkpoint(1517489351, 1500000), + _Checkpoint(1518688093, 1510000), + _Checkpoint(1519885580, 1520000), + _Checkpoint(1521088410, 1530000), + _Checkpoint(1522289764, 1540000), + _Checkpoint(1523589333, 1550000), + _Checkpoint(1524783179, 1560000), + _Checkpoint(1525991638, 1570000), + _Checkpoint(1527194575, 1580000), + _Checkpoint(1528395704, 1590000), + _Checkpoint(1529603343, 1600000), + _Checkpoint(1530796888, 1610000), + _Checkpoint(1531995687, 1620000), + _Checkpoint(1533197982, 1630000), + _Checkpoint(1534403578, 1640000), + _Checkpoint(1535600184, 1650000), + _Checkpoint(1536793547, 1660000), + _Checkpoint(1537992755, 1670000), + _Checkpoint(1539198355, 1680000), + _Checkpoint(1540414062, 1690000), + _Checkpoint(1541612717, 1700000), + _Checkpoint(1542815406, 1710000), + _Checkpoint(1544019553, 1720000), + _Checkpoint(1545229810, 1730000), + _Checkpoint(1546431793, 1740000), + _Checkpoint(1547615007, 1750000), + _Checkpoint(1548812515, 1760000), + _Checkpoint(1549998027, 1770000), + _Checkpoint(1551198085, 1780000), + _Checkpoint(1552503513, 1790000), + _Checkpoint(1553698458, 1800000), + _Checkpoint(1554900519, 1810000), + _Checkpoint(1556102453, 1820000), + _Checkpoint(1557301054, 1830000), + _Checkpoint(1558508921, 1840000), + _Checkpoint(1559706132, 1850000), + _Checkpoint(1560908667, 1860000), + _Checkpoint(1562106679, 1870000), + _Checkpoint(1563311957, 1880000), + _Checkpoint(1564511944, 1890000), + _Checkpoint(1565709489, 1900000), + _Checkpoint(1566910782, 1910000), + _Checkpoint(1568109052, 1920000), + _Checkpoint(1569319349, 1930000), + _Checkpoint(1570518236, 1940000), + _Checkpoint(1571718656, 1950000), + _Checkpoint(1572919811, 1960000), + _Checkpoint(1574128184, 1970000), + _Checkpoint(1575292812, 1980000), + _Checkpoint(1576479575, 1990000), + _Checkpoint(1577680194, 2000000), + _Checkpoint(1578876107, 2010000), + _Checkpoint(1580075963, 2020000), + _Checkpoint(1581273916, 2030000), + _Checkpoint(1582472927, 2040000), + _Checkpoint(1583679893, 2050000), + _Checkpoint(1584883948, 2060000), + _Checkpoint(1586084634, 2070000), + _Checkpoint(1587287479, 2080000), + _Checkpoint(1588480325, 2090000), + _Checkpoint(1589683808, 2100000), + _Checkpoint(1590881378, 2110000), + _Checkpoint(1592087857, 2120000), + _Checkpoint(1593277684, 2130000), + _Checkpoint(1594490084, 2140000), + _Checkpoint(1595692597, 2150000), + _Checkpoint(1596887172, 2160000), + _Checkpoint(1598105106, 2170000), + _Checkpoint(1599306018, 2180000), + _Checkpoint(1600510218, 2190000), + _Checkpoint(1601703776, 2200000), + _Checkpoint(1602893696, 2210000), + _Checkpoint(1604112554, 2220000), + _Checkpoint(1605313298, 2230000), + _Checkpoint(1606513918, 2240000), + _Checkpoint(1607716100, 2250000), + _Checkpoint(1608912594, 2260000), + _Checkpoint(1610111416, 2270000), + _Checkpoint(1611312080, 2280000), + _Checkpoint(1612512703, 2290000), + _Checkpoint(1613707976, 2300000), + _Checkpoint(1614906615, 2310000), + _Checkpoint(1616110597, 2320000), + _Checkpoint(1617306552, 2330000), + _Checkpoint(1618511460, 2340000), + _Checkpoint(1619709663, 2350000), + _Checkpoint(1620910784, 2360000), + _Checkpoint(1622108971, 2370000), + _Checkpoint(1623312679, 2380000), + _Checkpoint(1624516914, 2390000), + _Checkpoint(1625715884, 2400000), + _Checkpoint(1626915471, 2410000), + _Checkpoint(1628116823, 2420000), + _Checkpoint(1629318052, 2430000), + _Checkpoint(1630517187, 2440000), + _Checkpoint(1631717800, 2450000), + _Checkpoint(1632918546, 2460000), + _Checkpoint(1634124541, 2470000), + _Checkpoint(1635324499, 2480000), + _Checkpoint(1636519414, 2490000), + _Checkpoint(1637720692, 2500000), + _Checkpoint(1638925683, 2510000), + _Checkpoint(1640127154, 2520000), + _Checkpoint(1641321384, 2530000), + _Checkpoint(1642524155, 2540000), + _Checkpoint(1643722767, 2550000), + _Checkpoint(1644923112, 2560000), + _Checkpoint(1646128603, 2570000), + _Checkpoint(1647331058, 2580000), + _Checkpoint(1648530154, 2590000), + _Checkpoint(1649731449, 2600000), + _Checkpoint(1650930600, 2610000), + _Checkpoint(1652137128, 2620000), + _Checkpoint(1653338800, 2630000), + _Checkpoint(1654539762, 2640000), + _Checkpoint(1655747917, 2650000), + _Checkpoint(1656945266, 2660000), + _Checkpoint(1658150587, 2670000), + _Checkpoint(1659349371, 2680000), + _Checkpoint(1660553735, 2690000), + _Checkpoint(1661752700, 2700000), + _Checkpoint(1662945664, 2710000), + _Checkpoint(1664150159, 2720000), + _Checkpoint(1665357200, 2730000), + _Checkpoint(1666557130, 2740000), + _Checkpoint(1667758004, 2750000), + _Checkpoint(1668963041, 2760000), + _Checkpoint(1670159857, 2770000), + _Checkpoint(1671366967, 2780000), + _Checkpoint(1672562400, 2790000), + _Checkpoint(1673769923, 2800000), + _Checkpoint(1674973607, 2810000), + _Checkpoint(1676162080, 2820000), + _Checkpoint(1677371812, 2830000), + _Checkpoint(1678576821, 2840000), + _Checkpoint(1679780527, 2850000), + _Checkpoint(1680978762, 2860000), + _Checkpoint(1682185252, 2870000), + _Checkpoint(1683386854, 2880000), + _Checkpoint(1684586627, 2890000), + _Checkpoint(1685787011, 2900000), + _Checkpoint(1686993944, 2910000), + _Checkpoint(1688196910, 2920000), + _Checkpoint(1689392833, 2930000), + _Checkpoint(1690593379, 2940000), + _Checkpoint(1691812920, 2950000), + _Checkpoint(1693013768, 2960000), + _Checkpoint(1694214345, 2970000), + _Checkpoint(1695411856, 2980000), + _Checkpoint(1696602209, 2990000), + _Checkpoint(1697813342, 3000000), + _Checkpoint(1699012649, 3010000), + _Checkpoint(1700219506, 3020000), + _Checkpoint(1701417489, 3030000), + _Checkpoint(1702620638, 3040000), + _Checkpoint(1703824734, 3050000), + _Checkpoint(1705022552, 3060000), + _Checkpoint(1706223184, 3070000), + _Checkpoint(1707426775, 3080000), + _Checkpoint(1708628612, 3090000), + _Checkpoint(1709832655, 3100000), + _Checkpoint(1711037724, 3110000), + _Checkpoint(1712236145, 3120000), + _Checkpoint(1713439631, 3130000), + _Checkpoint(1714640176, 3140000), + _Checkpoint(1715838106, 3150000), + _Checkpoint(1717027647, 3160000), + _Checkpoint(1718238665, 3170000), + _Checkpoint(1719430906, 3180000), + _Checkpoint(1720643178, 3190000), + _Checkpoint(1721843329, 3200000), + _Checkpoint(1723042527, 3210000), + _Checkpoint(1724242564, 3220000), + _Checkpoint(1725445200, 3230000), + _Checkpoint(1726636517, 3240000), + _Checkpoint(1727845671, 3250000), + _Checkpoint(1729039416, 3260000), + _Checkpoint(1730243700, 3270000), + _Checkpoint(1731448260, 3280000), + _Checkpoint(1732645674, 3290000), + _Checkpoint(1733848630, 3300000), + _Checkpoint(1735045564, 3310000), + _Checkpoint(1736247165, 3320000), + _Checkpoint(1737444468, 3330000), + _Checkpoint(1738643351, 3340000), + _Checkpoint(1739839603, 3350000), + _Checkpoint(1741046630, 3360000), + _Checkpoint(1742243178, 3370000), + _Checkpoint(1743442732, 3380000), + _Checkpoint(1744648072, 3390000), + _Checkpoint(1745849558, 3400000), + _Checkpoint(1747049310, 3410000), + _Checkpoint(1748238277, 3420000), + _Checkpoint(1749449164, 3430000), + _Checkpoint(1750652323, 3440000), + _Checkpoint(1751852432, 3450000), + _Checkpoint(1753046298, 3460000), + _Checkpoint(1754249974, 3470000), + _Checkpoint(1755455410, 3480000), + _Checkpoint(1756666863, 3490000), + _Checkpoint(1757868614, 3500000), + _Checkpoint(1759061269, 3510000), + _Checkpoint(1760271644, 3520000), + _Checkpoint(1761476806, 3530000), + _Checkpoint(1762672780, 3540000), + _Checkpoint(1763878670, 3550000), + _Checkpoint(1765074231, 3560000), + _Checkpoint(1766276987, 3570000), + _Checkpoint(1767477623, 3580000), + _Checkpoint(1768680288, 3590000), + _Checkpoint(1769885820, 3600000), + _Checkpoint(1771090287, 3610000), + _Checkpoint(1772293937, 3620000), + _Checkpoint(1773490619, 3630000), + _Checkpoint(1774693829, 3640000), + ]; + + static int getBlockHeightByTime(DateTime time) { + final t = time.toUtc().millisecondsSinceEpoch; + + if (_points.isEmpty) return 0; + + if (t <= _points.first.timeMs) { + return 1; + } + + for (int i = 0; i < _points.length - 1; i++) { + final p0 = _points[i]; + final p1 = _points[i + 1]; + + if (t >= p0.timeMs && t < p1.timeMs) { + return _interpolate( + p0.height, + p1.height, + p0.timeMs, + p1.timeMs, + t, + ); + } + } + + final last = _points[_points.length - 1]; + final prev = _points[_points.length - 2]; + + final avgBlockTimeMs = (last.timeMs - prev.timeMs) / (last.height - prev.height); + + final blocksSinceLast = ((t - last.timeMs) / avgBlockTimeMs).floor(); + + return last.height + blocksSinceLast; + } + + static int _interpolate( + int h0, + int h1, + int t0, + int t1, + int t, + ) { + final ratio = (t - t0) / (t1 - t0); + return h0 + ((h1 - h0) * ratio).floor(); + } +} + +class _Checkpoint { + final int timeMs; + final int height; + + _Checkpoint(int timeSec, this.height) : timeMs = timeSec * 1000; +}