fix: get height by date for monero (#3158)

This commit is contained in:
cyan
2026-04-13 23:42:32 +02:00
committed by GitHub
parent 34bcdab97e
commit dee2b09ebe
2 changed files with 434 additions and 159 deletions
+12 -159
View File
@@ -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<int> 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<int> 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();
+422
View File
@@ -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;
}