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

cyan committed Apr 13, 2026 at 23:42 UTC dee2b09ebe4ec67699dfe5735c7f2420b70600e6
2 files changed +434 -159
cw_core/lib/get_height_by_date.dart
+12 -159
@@ -1,163 +1,12 @@
1 import 'package:cw_core/utils/proxy_wrapper.dart';
2 import 'package:cw_core/utils/print_verbose.dart';
3 import 'package:intl/intl.dart';
4 +import 'package:cw_core/get_height_by_date_xmr.dart';
5 import 'dart:convert';
6
7 // FIXME: Hardcoded values; Works only for monero
8
8 -final dateFormat = DateFormat('yyyy-MM');
9 -final dates = {
10 - "2014-5": 18844,
11 - "2014-6": 65406,
12 - "2014-7": 108882,
13 - "2014-8": 153594,
14 - "2014-9": 198072,
15 - "2014-10": 241088,
16 - "2014-11": 285305,
17 - "2014-12": 328069,
18 - "2015-1": 372369,
19 - "2015-2": 416505,
20 - "2015-3": 456631,
21 - "2015-4": 501084,
22 - "2015-5": 543973,
23 - "2015-6": 588326,
24 - "2015-7": 631187,
25 - "2015-8": 675484,
26 - "2015-9": 719725,
27 - "2015-10": 762463,
28 - "2015-11": 806528,
29 - "2015-12": 849041,
30 - "2016-1": 892866,
31 - "2016-2": 936736,
32 - "2016-3": 977691,
33 - "2016-4": 1015848,
34 - "2016-5": 1037417,
35 - "2016-6": 1059651,
36 - "2016-7": 1081269,
37 - "2016-8": 1103630,
38 - "2016-9": 1125983,
39 - "2016-10": 1147617,
40 - "2016-11": 1169779,
41 - "2016-12": 1191402,
42 - "2017-1": 1213861,
43 - "2017-2": 1236197,
44 - "2017-3": 1256358,
45 - "2017-4": 1278622,
46 - "2017-5": 1300239,
47 - "2017-6": 1322564,
48 - "2017-7": 1344225,
49 - "2017-8": 1366664,
50 - "2017-9": 1389113,
51 - "2017-10": 1410738,
52 - "2017-11": 1433039,
53 - "2017-12": 1454639,
54 - "2018-1": 1477201,
55 - "2018-2": 1499599,
56 - "2018-3": 1519796,
57 - "2018-4": 1542067,
58 - "2018-5": 1562861,
59 - "2018-6": 1585135,
60 - "2018-7": 1606715,
61 - "2018-8": 1629017,
62 - "2018-9": 1651347,
63 - "2018-10": 1673031,
64 - "2018-11": 1695128,
65 - "2018-12": 1716687,
66 - "2019-1": 1738923,
67 - "2019-2": 1761435,
68 - "2019-3": 1781681,
69 - "2019-4": 1803081,
70 - "2019-5": 1824671,
71 - "2019-6": 1847005,
72 - "2019-7": 1868590,
73 - "2019-8": 1890552,
74 - "2019-9": 1912212,
75 - "2019-10": 1932200,
76 - "2019-11": 1957040,
77 - "2019-12": 1978090,
78 - "2020-1": 2001290,
79 - "2020-2": 2022688,
80 - "2020-3": 2043987,
81 - "2020-4": 2066536,
82 - "2020-5": 2090797,
83 - "2020-6": 2111633,
84 - "2020-7": 2131433,
85 - "2020-8": 2153983,
86 - "2020-9": 2176466,
87 - "2020-10": 2198453,
88 - "2020-11": 2220000,
89 - "2020-12": 2242240,
90 - "2021-1": 2264584,
91 - "2021-2": 2286892,
92 - "2021-3": 2307079,
93 - "2021-4": 2329385,
94 - "2021-5": 2351004,
95 - "2021-6": 2373306,
96 - "2021-7": 2394882,
97 - "2021-8": 2417162,
98 - "2021-9": 2439490,
99 - "2021-10": 2461020,
100 - "2021-11": 2483377,
101 - "2021-12": 2504932,
102 - "2022-1": 2527316,
103 - "2022-2": 2549605,
104 - "2022-3": 2569711,
105 - "2022-4": 2591995,
106 - "2022-5": 2613603,
107 - "2022-6": 2635840,
108 - "2022-7": 2657395,
109 - "2022-8": 2679705,
110 - "2022-9": 2701991,
111 - "2022-10": 2723607,
112 - "2022-11": 2745899,
113 - "2022-12": 2767427,
114 - "2023-1": 2789763,
115 - "2023-2": 2811996,
116 - "2023-3": 2832118,
117 - "2023-4": 2854365,
118 - "2023-5": 2875972,
119 - "2023-6": 2898234,
120 - "2023-7": 2919771,
121 - "2023-8": 2942045,
122 - "2023-9": 2964280,
123 - "2023-10": 2985937,
124 - "2023-11": 3008178,
125 - "2023-12": 3029759
126 -};
127 -
128 -int getMoneroHeigthByDate({required DateTime date}) {
129 - final raw = '${date.year}' + '-' + '${date.month}';
130 - final lastHeight = dates.values.last;
131 - int startHeight;
132 - int endHeight;
133 - int height = 0;
134 -
135 - try {
136 - if ((dates[raw] == null) || (dates[raw] == lastHeight)) {
137 - startHeight = dates.values.toList()[dates.length - 2];
138 - endHeight = dates.values.toList()[dates.length - 1];
139 - final heightPerDay = (endHeight - startHeight) / 31;
140 - final endDateRaw = dates.keys.toList()[dates.length - 1].split('-');
141 - final endYear = int.parse(endDateRaw[0]);
142 - final endMonth = int.parse(endDateRaw[1]);
143 - final endDate = DateTime(endYear, endMonth);
144 - final differenceInDays = date.difference(endDate).inDays;
145 - final daysHeight = (differenceInDays * heightPerDay).round();
146 - height = endHeight + daysHeight;
147 - } else {
148 - startHeight = dates[raw]!;
149 - final index = dates.values.toList().indexOf(startHeight);
150 - endHeight = dates.values.toList()[index + 1];
151 - final heightPerDay = ((endHeight - startHeight) / 31).round();
152 - final daysHeight = (date.day - 1) * heightPerDay;
153 - height = startHeight + daysHeight - heightPerDay;
154 - }
155 - } catch (e) {
156 - printV(e.toString());
157 - }
158 -
159 - return height;
160 -}
9 +int getMoneroHeigthByDate({required DateTime date}) => MoneroHeight.getBlockHeightByTime(date..subtract(Duration(days: 1)));
10
11 const havenDates = {
12 "2023-05": 1352995,
@@ -223,6 +72,7 @@ const havenDates = {
72 "2018-04": 32000,
73 "2018-03": 8500
74 };
75 +final dateFormat = DateFormat('yyyy-MM');
76
77 DateTime formatMapKey(String key) => dateFormat.parse(key);
78
@@ -234,9 +84,10 @@ int getHavenHeightByDate({required DateTime date}) {
84 }
85
86 Future<int> getHavenCurrentHeight() async {
237 - final req = await ProxyWrapper().getHttpClient()
238 - .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'))
239 - .timeout(Duration(seconds: 15));
87 + final req = await ProxyWrapper()
88 + .getHttpClient()
89 + .getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'))
90 + .timeout(Duration(seconds: 15));
91 final response = await req.close();
92 final stringResponse = await response.transform(utf8.decoder).join();
93
@@ -273,9 +124,11 @@ const bitcoinDates = {
124 };
125
126 Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
276 - final req = await ProxyWrapper().getHttpClient()
277 - .getUrl(Uri.parse("https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}"))
278 - .timeout(Duration(seconds: 15));
127 + final req = await ProxyWrapper()
128 + .getHttpClient()
129 + .getUrl(Uri.parse(
130 + "https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}"))
131 + .timeout(Duration(seconds: 15));
132 final response = await req.close();
133 final stringResponse = await response.transform(utf8.decoder).join();
134
cw_core/lib/get_height_by_date_xmr.dart new
+422
@@ -0,0 +1,422 @@
1 +
2 +class MoneroHeight {
3 + // 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
4 + static final List<_Checkpoint> _points = [
5 + _Checkpoint(1398386790, 10000),
6 + _Checkpoint(1398970097, 20000),
7 + _Checkpoint(1399529049, 30000),
8 + _Checkpoint(1400107914, 40000),
9 + _Checkpoint(1400673084, 50000),
10 + _Checkpoint(1401259431, 60000),
11 + _Checkpoint(1401861514, 70000),
12 + _Checkpoint(1402455081, 80000),
13 + _Checkpoint(1403051337, 90000),
14 + _Checkpoint(1403639801, 100000),
15 + _Checkpoint(1404238831, 110000),
16 + _Checkpoint(1404841666, 120000),
17 + _Checkpoint(1405444927, 130000),
18 + _Checkpoint(1406035044, 140000),
19 + _Checkpoint(1406634825, 150000),
20 + _Checkpoint(1407238604, 160000),
21 + _Checkpoint(1407838442, 170000),
22 + _Checkpoint(1408443936, 180000),
23 + _Checkpoint(1409041095, 190000),
24 + _Checkpoint(1409644412, 200000),
25 + _Checkpoint(1410247699, 210000),
26 + _Checkpoint(1410851018, 220000),
27 + _Checkpoint(1411455976, 230000),
28 + _Checkpoint(1412059180, 240000),
29 + _Checkpoint(1412661506, 250000),
30 + _Checkpoint(1413267445, 260000),
31 + _Checkpoint(1413873271, 270000),
32 + _Checkpoint(1414480925, 280000),
33 + _Checkpoint(1415086077, 290000),
34 + _Checkpoint(1415690591, 300000),
35 + _Checkpoint(1416296909, 310000),
36 + _Checkpoint(1416902704, 320000),
37 + _Checkpoint(1417507901, 330000),
38 + _Checkpoint(1418109054, 340000),
39 + _Checkpoint(1418722232, 350000),
40 + _Checkpoint(1419326271, 360000),
41 + _Checkpoint(1419928389, 370000),
42 + _Checkpoint(1420541216, 380000),
43 + _Checkpoint(1421145579, 390000),
44 + _Checkpoint(1421749732, 400000),
45 + _Checkpoint(1422354623, 410000),
46 + _Checkpoint(1422956207, 420000),
47 + _Checkpoint(1423562393, 430000),
48 + _Checkpoint(1424166115, 440000),
49 + _Checkpoint(1424767351, 450000),
50 + _Checkpoint(1425371690, 460000),
51 + _Checkpoint(1425975620, 470000),
52 + _Checkpoint(1426579077, 480000),
53 + _Checkpoint(1427182546, 490000),
54 + _Checkpoint(1427785048, 500000),
55 + _Checkpoint(1428385900, 510000),
56 + _Checkpoint(1428990297, 520000),
57 + _Checkpoint(1429593770, 530000),
58 + _Checkpoint(1430197340, 540000),
59 + _Checkpoint(1430803986, 550000),
60 + _Checkpoint(1431408119, 560000),
61 + _Checkpoint(1432011390, 570000),
62 + _Checkpoint(1432613317, 580000),
63 + _Checkpoint(1433222583, 590000),
64 + _Checkpoint(1433825715, 600000),
65 + _Checkpoint(1434431094, 610000),
66 + _Checkpoint(1435033265, 620000),
67 + _Checkpoint(1435636924, 630000),
68 + _Checkpoint(1436243604, 640000),
69 + _Checkpoint(1436848163, 650000),
70 + _Checkpoint(1437455928, 660000),
71 + _Checkpoint(1438056769, 670000),
72 + _Checkpoint(1438662194, 680000),
73 + _Checkpoint(1439267688, 690000),
74 + _Checkpoint(1439872751, 700000),
75 + _Checkpoint(1440479855, 710000),
76 + _Checkpoint(1441084930, 720000),
77 + _Checkpoint(1441690778, 730000),
78 + _Checkpoint(1442300128, 740000),
79 + _Checkpoint(1442902966, 750000),
80 + _Checkpoint(1443510081, 760000),
81 + _Checkpoint(1444120229, 770000),
82 + _Checkpoint(1444725863, 780000),
83 + _Checkpoint(1445334248, 790000),
84 + _Checkpoint(1445938467, 800000),
85 + _Checkpoint(1446548650, 810000),
86 + _Checkpoint(1447157167, 820000),
87 + _Checkpoint(1447766950, 830000),
88 + _Checkpoint(1448375042, 840000),
89 + _Checkpoint(1448982313, 850000),
90 + _Checkpoint(1449591976, 860000),
91 + _Checkpoint(1450206082, 870000),
92 + _Checkpoint(1450817995, 880000),
93 + _Checkpoint(1451431001, 890000),
94 + _Checkpoint(1452044620, 900000),
95 + _Checkpoint(1452654325, 910000),
96 + _Checkpoint(1453271464, 920000),
97 + _Checkpoint(1453874045, 930000),
98 + _Checkpoint(1454490333, 940000),
99 + _Checkpoint(1455096906, 950000),
100 + _Checkpoint(1455704830, 960000),
101 + _Checkpoint(1456315340, 970000),
102 + _Checkpoint(1456926968, 980000),
103 + _Checkpoint(1457536684, 990000),
104 + _Checkpoint(1458145453, 1000000),
105 + _Checkpoint(1458780543, 1010000),
106 + _Checkpoint(1459961331, 1020000),
107 + _Checkpoint(1461174469, 1030000),
108 + _Checkpoint(1462375809, 1040000),
109 + _Checkpoint(1463578591, 1050000),
110 + _Checkpoint(1464785682, 1060000),
111 + _Checkpoint(1465981307, 1070000),
112 + _Checkpoint(1467185150, 1080000),
113 + _Checkpoint(1468365704, 1090000),
114 + _Checkpoint(1469573151, 1100000),
115 + _Checkpoint(1470777161, 1110000),
116 + _Checkpoint(1471975662, 1120000),
117 + _Checkpoint(1473164186, 1130000),
118 + _Checkpoint(1474374066, 1140000),
119 + _Checkpoint(1475577458, 1150000),
120 + _Checkpoint(1476776898, 1160000),
121 + _Checkpoint(1477990372, 1170000),
122 + _Checkpoint(1479187102, 1180000),
123 + _Checkpoint(1480378008, 1190000),
124 + _Checkpoint(1481575804, 1200000),
125 + _Checkpoint(1482772399, 1210000),
126 + _Checkpoint(1483965031, 1220000),
127 + _Checkpoint(1485170094, 1230000),
128 + _Checkpoint(1486369447, 1240000),
129 + _Checkpoint(1487569956, 1250000),
130 + _Checkpoint(1488775148, 1260000),
131 + _Checkpoint(1489970122, 1270000),
132 + _Checkpoint(1491168799, 1280000),
133 + _Checkpoint(1492371569, 1290000),
134 + _Checkpoint(1493568547, 1300000),
135 + _Checkpoint(1494770503, 1310000),
136 + _Checkpoint(1495965162, 1320000),
137 + _Checkpoint(1497168519, 1330000),
138 + _Checkpoint(1498361038, 1340000),
139 + _Checkpoint(1499552117, 1350000),
140 + _Checkpoint(1500747868, 1360000),
141 + _Checkpoint(1501946180, 1370000),
142 + _Checkpoint(1503149952, 1380000),
143 + _Checkpoint(1504330700, 1390000),
144 + _Checkpoint(1505525706, 1400000),
145 + _Checkpoint(1506725266, 1410000),
146 + _Checkpoint(1507924408, 1420000),
147 + _Checkpoint(1509129536, 1430000),
148 + _Checkpoint(1510332372, 1440000),
149 + _Checkpoint(1511529796, 1450000),
150 + _Checkpoint(1512713363, 1460000),
151 + _Checkpoint(1513909535, 1470000),
152 + _Checkpoint(1515100139, 1480000),
153 + _Checkpoint(1516298977, 1490000),
154 + _Checkpoint(1517489351, 1500000),
155 + _Checkpoint(1518688093, 1510000),
156 + _Checkpoint(1519885580, 1520000),
157 + _Checkpoint(1521088410, 1530000),
158 + _Checkpoint(1522289764, 1540000),
159 + _Checkpoint(1523589333, 1550000),
160 + _Checkpoint(1524783179, 1560000),
161 + _Checkpoint(1525991638, 1570000),
162 + _Checkpoint(1527194575, 1580000),
163 + _Checkpoint(1528395704, 1590000),
164 + _Checkpoint(1529603343, 1600000),
165 + _Checkpoint(1530796888, 1610000),
166 + _Checkpoint(1531995687, 1620000),
167 + _Checkpoint(1533197982, 1630000),
168 + _Checkpoint(1534403578, 1640000),
169 + _Checkpoint(1535600184, 1650000),
170 + _Checkpoint(1536793547, 1660000),
171 + _Checkpoint(1537992755, 1670000),
172 + _Checkpoint(1539198355, 1680000),
173 + _Checkpoint(1540414062, 1690000),
174 + _Checkpoint(1541612717, 1700000),
175 + _Checkpoint(1542815406, 1710000),
176 + _Checkpoint(1544019553, 1720000),
177 + _Checkpoint(1545229810, 1730000),
178 + _Checkpoint(1546431793, 1740000),
179 + _Checkpoint(1547615007, 1750000),
180 + _Checkpoint(1548812515, 1760000),
181 + _Checkpoint(1549998027, 1770000),
182 + _Checkpoint(1551198085, 1780000),
183 + _Checkpoint(1552503513, 1790000),
184 + _Checkpoint(1553698458, 1800000),
185 + _Checkpoint(1554900519, 1810000),
186 + _Checkpoint(1556102453, 1820000),
187 + _Checkpoint(1557301054, 1830000),
188 + _Checkpoint(1558508921, 1840000),
189 + _Checkpoint(1559706132, 1850000),
190 + _Checkpoint(1560908667, 1860000),
191 + _Checkpoint(1562106679, 1870000),
192 + _Checkpoint(1563311957, 1880000),
193 + _Checkpoint(1564511944, 1890000),
194 + _Checkpoint(1565709489, 1900000),
195 + _Checkpoint(1566910782, 1910000),
196 + _Checkpoint(1568109052, 1920000),
197 + _Checkpoint(1569319349, 1930000),
198 + _Checkpoint(1570518236, 1940000),
199 + _Checkpoint(1571718656, 1950000),
200 + _Checkpoint(1572919811, 1960000),
201 + _Checkpoint(1574128184, 1970000),
202 + _Checkpoint(1575292812, 1980000),
203 + _Checkpoint(1576479575, 1990000),
204 + _Checkpoint(1577680194, 2000000),
205 + _Checkpoint(1578876107, 2010000),
206 + _Checkpoint(1580075963, 2020000),
207 + _Checkpoint(1581273916, 2030000),
208 + _Checkpoint(1582472927, 2040000),
209 + _Checkpoint(1583679893, 2050000),
210 + _Checkpoint(1584883948, 2060000),
211 + _Checkpoint(1586084634, 2070000),
212 + _Checkpoint(1587287479, 2080000),
213 + _Checkpoint(1588480325, 2090000),
214 + _Checkpoint(1589683808, 2100000),
215 + _Checkpoint(1590881378, 2110000),
216 + _Checkpoint(1592087857, 2120000),
217 + _Checkpoint(1593277684, 2130000),
218 + _Checkpoint(1594490084, 2140000),
219 + _Checkpoint(1595692597, 2150000),
220 + _Checkpoint(1596887172, 2160000),
221 + _Checkpoint(1598105106, 2170000),
222 + _Checkpoint(1599306018, 2180000),
223 + _Checkpoint(1600510218, 2190000),
224 + _Checkpoint(1601703776, 2200000),
225 + _Checkpoint(1602893696, 2210000),
226 + _Checkpoint(1604112554, 2220000),
227 + _Checkpoint(1605313298, 2230000),
228 + _Checkpoint(1606513918, 2240000),
229 + _Checkpoint(1607716100, 2250000),
230 + _Checkpoint(1608912594, 2260000),
231 + _Checkpoint(1610111416, 2270000),
232 + _Checkpoint(1611312080, 2280000),
233 + _Checkpoint(1612512703, 2290000),
234 + _Checkpoint(1613707976, 2300000),
235 + _Checkpoint(1614906615, 2310000),
236 + _Checkpoint(1616110597, 2320000),
237 + _Checkpoint(1617306552, 2330000),
238 + _Checkpoint(1618511460, 2340000),
239 + _Checkpoint(1619709663, 2350000),
240 + _Checkpoint(1620910784, 2360000),
241 + _Checkpoint(1622108971, 2370000),
242 + _Checkpoint(1623312679, 2380000),
243 + _Checkpoint(1624516914, 2390000),
244 + _Checkpoint(1625715884, 2400000),
245 + _Checkpoint(1626915471, 2410000),
246 + _Checkpoint(1628116823, 2420000),
247 + _Checkpoint(1629318052, 2430000),
248 + _Checkpoint(1630517187, 2440000),
249 + _Checkpoint(1631717800, 2450000),
250 + _Checkpoint(1632918546, 2460000),
251 + _Checkpoint(1634124541, 2470000),
252 + _Checkpoint(1635324499, 2480000),
253 + _Checkpoint(1636519414, 2490000),
254 + _Checkpoint(1637720692, 2500000),
255 + _Checkpoint(1638925683, 2510000),
256 + _Checkpoint(1640127154, 2520000),
257 + _Checkpoint(1641321384, 2530000),
258 + _Checkpoint(1642524155, 2540000),
259 + _Checkpoint(1643722767, 2550000),
260 + _Checkpoint(1644923112, 2560000),
261 + _Checkpoint(1646128603, 2570000),
262 + _Checkpoint(1647331058, 2580000),
263 + _Checkpoint(1648530154, 2590000),
264 + _Checkpoint(1649731449, 2600000),
265 + _Checkpoint(1650930600, 2610000),
266 + _Checkpoint(1652137128, 2620000),
267 + _Checkpoint(1653338800, 2630000),
268 + _Checkpoint(1654539762, 2640000),
269 + _Checkpoint(1655747917, 2650000),
270 + _Checkpoint(1656945266, 2660000),
271 + _Checkpoint(1658150587, 2670000),
272 + _Checkpoint(1659349371, 2680000),
273 + _Checkpoint(1660553735, 2690000),
274 + _Checkpoint(1661752700, 2700000),
275 + _Checkpoint(1662945664, 2710000),
276 + _Checkpoint(1664150159, 2720000),
277 + _Checkpoint(1665357200, 2730000),
278 + _Checkpoint(1666557130, 2740000),
279 + _Checkpoint(1667758004, 2750000),
280 + _Checkpoint(1668963041, 2760000),
281 + _Checkpoint(1670159857, 2770000),
282 + _Checkpoint(1671366967, 2780000),
283 + _Checkpoint(1672562400, 2790000),
284 + _Checkpoint(1673769923, 2800000),
285 + _Checkpoint(1674973607, 2810000),
286 + _Checkpoint(1676162080, 2820000),
287 + _Checkpoint(1677371812, 2830000),
288 + _Checkpoint(1678576821, 2840000),
289 + _Checkpoint(1679780527, 2850000),
290 + _Checkpoint(1680978762, 2860000),
291 + _Checkpoint(1682185252, 2870000),
292 + _Checkpoint(1683386854, 2880000),
293 + _Checkpoint(1684586627, 2890000),
294 + _Checkpoint(1685787011, 2900000),
295 + _Checkpoint(1686993944, 2910000),
296 + _Checkpoint(1688196910, 2920000),
297 + _Checkpoint(1689392833, 2930000),
298 + _Checkpoint(1690593379, 2940000),
299 + _Checkpoint(1691812920, 2950000),
300 + _Checkpoint(1693013768, 2960000),
301 + _Checkpoint(1694214345, 2970000),
302 + _Checkpoint(1695411856, 2980000),
303 + _Checkpoint(1696602209, 2990000),
304 + _Checkpoint(1697813342, 3000000),
305 + _Checkpoint(1699012649, 3010000),
306 + _Checkpoint(1700219506, 3020000),
307 + _Checkpoint(1701417489, 3030000),
308 + _Checkpoint(1702620638, 3040000),
309 + _Checkpoint(1703824734, 3050000),
310 + _Checkpoint(1705022552, 3060000),
311 + _Checkpoint(1706223184, 3070000),
312 + _Checkpoint(1707426775, 3080000),
313 + _Checkpoint(1708628612, 3090000),
314 + _Checkpoint(1709832655, 3100000),
315 + _Checkpoint(1711037724, 3110000),
316 + _Checkpoint(1712236145, 3120000),
317 + _Checkpoint(1713439631, 3130000),
318 + _Checkpoint(1714640176, 3140000),
319 + _Checkpoint(1715838106, 3150000),
320 + _Checkpoint(1717027647, 3160000),
321 + _Checkpoint(1718238665, 3170000),
322 + _Checkpoint(1719430906, 3180000),
323 + _Checkpoint(1720643178, 3190000),
324 + _Checkpoint(1721843329, 3200000),
325 + _Checkpoint(1723042527, 3210000),
326 + _Checkpoint(1724242564, 3220000),
327 + _Checkpoint(1725445200, 3230000),
328 + _Checkpoint(1726636517, 3240000),
329 + _Checkpoint(1727845671, 3250000),
330 + _Checkpoint(1729039416, 3260000),
331 + _Checkpoint(1730243700, 3270000),
332 + _Checkpoint(1731448260, 3280000),
333 + _Checkpoint(1732645674, 3290000),
334 + _Checkpoint(1733848630, 3300000),
335 + _Checkpoint(1735045564, 3310000),
336 + _Checkpoint(1736247165, 3320000),
337 + _Checkpoint(1737444468, 3330000),
338 + _Checkpoint(1738643351, 3340000),
339 + _Checkpoint(1739839603, 3350000),
340 + _Checkpoint(1741046630, 3360000),
341 + _Checkpoint(1742243178, 3370000),
342 + _Checkpoint(1743442732, 3380000),
343 + _Checkpoint(1744648072, 3390000),
344 + _Checkpoint(1745849558, 3400000),
345 + _Checkpoint(1747049310, 3410000),
346 + _Checkpoint(1748238277, 3420000),
347 + _Checkpoint(1749449164, 3430000),
348 + _Checkpoint(1750652323, 3440000),
349 + _Checkpoint(1751852432, 3450000),
350 + _Checkpoint(1753046298, 3460000),
351 + _Checkpoint(1754249974, 3470000),
352 + _Checkpoint(1755455410, 3480000),
353 + _Checkpoint(1756666863, 3490000),
354 + _Checkpoint(1757868614, 3500000),
355 + _Checkpoint(1759061269, 3510000),
356 + _Checkpoint(1760271644, 3520000),
357 + _Checkpoint(1761476806, 3530000),
358 + _Checkpoint(1762672780, 3540000),
359 + _Checkpoint(1763878670, 3550000),
360 + _Checkpoint(1765074231, 3560000),
361 + _Checkpoint(1766276987, 3570000),
362 + _Checkpoint(1767477623, 3580000),
363 + _Checkpoint(1768680288, 3590000),
364 + _Checkpoint(1769885820, 3600000),
365 + _Checkpoint(1771090287, 3610000),
366 + _Checkpoint(1772293937, 3620000),
367 + _Checkpoint(1773490619, 3630000),
368 + _Checkpoint(1774693829, 3640000),
369 + ];
370 +
371 + static int getBlockHeightByTime(DateTime time) {
372 + final t = time.toUtc().millisecondsSinceEpoch;
373 +
374 + if (_points.isEmpty) return 0;
375 +
376 + if (t <= _points.first.timeMs) {
377 + return 1;
378 + }
379 +
380 + for (int i = 0; i < _points.length - 1; i++) {
381 + final p0 = _points[i];
382 + final p1 = _points[i + 1];
383 +
384 + if (t >= p0.timeMs && t < p1.timeMs) {
385 + return _interpolate(
386 + p0.height,
387 + p1.height,
388 + p0.timeMs,
389 + p1.timeMs,
390 + t,
391 + );
392 + }
393 + }
394 +
395 + final last = _points[_points.length - 1];
396 + final prev = _points[_points.length - 2];
397 +
398 + final avgBlockTimeMs = (last.timeMs - prev.timeMs) / (last.height - prev.height);
399 +
400 + final blocksSinceLast = ((t - last.timeMs) / avgBlockTimeMs).floor();
401 +
402 + return last.height + blocksSinceLast;
403 + }
404 +
405 + static int _interpolate(
406 + int h0,
407 + int h1,
408 + int t0,
409 + int t1,
410 + int t,
411 + ) {
412 + final ratio = (t - t0) / (t1 - t0);
413 + return h0 + ((h1 - h0) * ratio).floor();
414 + }
415 +}
416 +
417 +class _Checkpoint {
418 + final int timeMs;
419 + final int height;
420 +
421 + _Checkpoint(int timeSec, this.height) : timeMs = timeSec * 1000;
422 +}