1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
// Copyright 2022 Webb Technologies Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # DKG Metadata Module
//!
//! A pallet to manage metadata about the DKG and DKG proposal system.
//!
//! ## Overview
//!
//! The DKG Metadata pallet manages the following metadata about the DKG and DKG proposal system:
//! - The active DKG public key
//! - The active DKG authorities
//! - The next DKG public key
//! - The next DKG authorities
//! - The DKG signature threshold (the `t` in `t-out-of-n` threshold signatures)
//! - The key refresh process
//! - The misbehavior reporting process
//!
//! The pallet tracks authority changes after each session and updates the metadata for the
//! current and next authority sets respectively. The pallet also exposes a way for the root origin
//! to update the signature threshold used in the DKG signing system.
//!
//! The pallet is responsible with initiating the key refresh process for rotating the DKG keys
//! across authority set changes and executing the rotation when a new session starts.
//!
//! The pallet tracks reputations of DKG authorities by providing extrinsics and storage for
//! submitting misbehaviour reports about authorities that misbehave.
//!
//! ### Terminology
//!
//! - **Authority**: A DKG authority.
//! - **Authority Set**: A set of DKG authorities.
//! - **Active DKG public key**: The public key of the DKG protocol that is currently active.
//! - **Next DKG public key**: The public key of the DKG protocol that will be active after the next
//!   authority set change.
//! - **DKG signature threshold**: The `t` in `t-out-of-n` threshold signatures used in the DKG
//!   signing system.
//! - **Misbheaviour Report**: A report of a DKG authority misbehaving.
//! - **Refresh delay**: The length of time within a session that the key refresh protocol will be
//!   initiated.
//!
//! ### Implementation
//!
//! The pallet is implemented to track and maintain a variety of different pieces of data. It is the
//! primary pallet used to store the active and next DKG public keys that are generated by the
//! active and next authorities of the underlying blockchain protocol. A runtime API is used to
//! expose the active and next authorities to the external workers responsible with executing the
//! DKG and signing protocol.
//!
//! The pallet exposes a variety of extrinsics for updating metadata:
//! - `set_threshold`: Allows a root-origin to update the DKG signature threshold used in the
//!   threshold signing protocol.
//! - `set_refresh_delay`: Allows a root-origin to update the delay before the key refresh process
//!   is initiated.
//! - `submit_misbehaviour_reports`: Allows authorities to submit misbehaviour reports. Once the
//!   `threshold` number of reports is submitted, the offending authority will lose reputation.
//! - `submit_public_key`: Allows submitting of the genesis public key by the initial authorities of
//!   the DKG protocol.
//! - `submit_next_public_key`: Allows submitting of the next public key by the next authorities of
//!   the DKG protocol.
//!
//! The refresh process is initiated `T::RefreshDelay` into each session. A RefreshProposal is
//! created and sent directly to the `pallet-dkg-proposal-handler` for inclusion into the unsigned
//! proposal queue and soon after for signing. Once this proposal is signed, the signature is posted
//! back on-chain to this pallet which rotates the DKG keys when the session ends.
//!
//! The misbehaviour reporting process relies on a honest-threshold assumption. When DKG authorities
//! misbehave offchain, any detecting authority can submit a report of the offending authority. If a
//! `threshold` number of reports is submitted, then the offending authority will lose reputation.
//! This reputation map is utilized by each DKG authority to ensure every authority can generate a
//! deterministic signing set for the threshold signing protocols. The signing set is taken to
//! initially be the top `t` DKG authorities by reputation.
//!
//! ## Related Modules
//!
//! * [`System`](https://github.com/paritytech/substrate/tree/master/frame/system)
//! * [`Support`](https://github.com/paritytech/substrate/tree/master/frame/support)
//! * [`DKG Proposals`](../../pallet-dkg-proposals)
//! * [`DKG Proposal Handler`](../../pallet-dkg-proposal-handler)

#![cfg_attr(not(feature = "std"), no_std)]

use codec::Encode;
use dkg_runtime_primitives::{
	offchain::storage_keys::{
		AGGREGATED_MISBEHAVIOUR_REPORTS, AGGREGATED_MISBEHAVIOUR_REPORTS_LOCK,
		AGGREGATED_PUBLIC_KEYS, AGGREGATED_PUBLIC_KEYS_AT_GENESIS,
		AGGREGATED_PUBLIC_KEYS_AT_GENESIS_LOCK, AGGREGATED_PUBLIC_KEYS_LOCK,
		SUBMIT_GENESIS_KEYS_AT, SUBMIT_KEYS_AT,
	},
	proposal::Proposal,
	traits::{GetDKGPublicKey, OnAuthoritySetChangeHandler},
	utils::{ecdsa, to_slice_33, verify_signer_from_set_ecdsa},
	AggregatedMisbehaviourReports, AggregatedPublicKeys, AuthorityIndex, AuthoritySet,
	ConsensusLog, MisbehaviourType, ProposalHandlerTrait, ProposalNonce, RefreshProposal,
	DKG_ENGINE_ID,
};
use frame_support::{
	dispatch::DispatchResultWithPostInfo,
	ensure,
	pallet_prelude::{Get, Weight},
	traits::{EstimateNextSessionRotation, OneSessionHandler},
	BoundedVec,
};
use frame_system::{
	offchain::{Signer, SubmitTransaction},
	pallet_prelude::BlockNumberFor,
};
pub use pallet::*;
use sp_io::hashing::keccak_256;
use sp_runtime::{
	generic::DigestItem,
	offchain::{
		storage::StorageValueRef,
		storage_lock::{StorageLock, Time},
	},
	traits::{AtLeast32BitUnsigned, Convert, IsMember, One, Saturating, Zero},
	DispatchError, Permill, RuntimeAppPublic,
};
use sp_std::{
	collections::btree_map::BTreeMap,
	convert::{TryFrom, TryInto},
	fmt::Debug,
	marker::PhantomData,
	ops::{Rem, Sub},
	prelude::*,
	vec,
};

use types::RoundMetadata;
use weights::WeightInfo;

// Reputation assigned to genesis authorities
pub const INITIAL_REPUTATION: u32 = 1_000_000_000;

// Our goal is to trigger the ShouldExecuteNewKeygen to true if we have passed exactly X blocks from
// the last session rotation and still have not seen a new key, this value cannot be too small
// either because we need to accomodate delays between `keygen process starting + completion +
// posted onchain`. If the delay is smaller than the above then we might inadvertently rotate
// sessions.
pub const BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER: u32 = 20;

// Reputation increase awarded to authorities on submission of next public key
pub const REPUTATION_INCREMENT: u32 = INITIAL_REPUTATION / 1000;

#[cfg(test)]
mod mock;
pub mod types;

#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

pub mod weights;

#[frame_support::pallet]
pub mod pallet {
	use dkg_runtime_primitives::{traits::OnDKGPublicKeyChangeHandler, ProposalHandlerTrait};
	use frame_support::pallet_prelude::*;
	use frame_system::{
		ensure_signed,
		offchain::{AppCrypto, CreateSignedTransaction},
		pallet_prelude::*,
	};
	use log;
	use sp_runtime::Percent;

	use super::*;

	/// A `Convert` implementation that finds the stash of the given controller account,
	/// if any.
	pub struct AuthorityIdOf<T>(sp_std::marker::PhantomData<T>);

	impl<T: Config> Convert<T::AccountId, Option<T::DKGId>> for AuthorityIdOf<T> {
		fn convert(controller: T::AccountId) -> Option<T::DKGId> {
			AccountToAuthority::<T>::get(controller)
		}
	}

	pub struct VoterSetData {
		pub voter_set_merkle_root: [u8; 32],
		pub average_session_length_in_millisecs: u64,
		pub voter_count: u32,
	}

	#[pallet::config]
	pub trait Config:
		frame_system::Config + pallet_timestamp::Config + CreateSignedTransaction<Call<Self>>
	{
		/// The overarching RuntimeEvent type.
		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
		/// Authority identifier type
		type DKGId: Member
			+ Parameter
			+ RuntimeAppPublic
			+ MaybeSerializeDeserialize
			+ AsRef<[u8]>
			+ Into<ecdsa::Public>
			+ From<ecdsa::Public>
			+ MaxEncodedLen;
		/// Convert DKG AuthorityId to a form that would end up in the Merkle Tree.
		///
		/// For instance for ECDSA (secp256k1) we want to store uncompressed public keys (65 bytes)
		/// and later to Ethereum Addresses (160 bits) to simplify using them on Ethereum chain,
		/// but the rest of the Substrate codebase is storing them compressed (33 bytes) for
		/// efficiency reasons.
		type DKGAuthorityToMerkleLeaf: Convert<Self::DKGId, Vec<u8>>;
		/// Jail lengths for misbehaviours
		type KeygenJailSentence: Get<BlockNumberFor<Self>>;
		type SigningJailSentence: Get<BlockNumberFor<Self>>;
		/// Map from controller accounts to their DKG authority identifier.
		type AuthorityIdOf: Convert<Self::AccountId, Option<Self::DKGId>>;
		/// The reputation decay percentage
		type Reputation: Member
			+ Parameter
			+ Default
			+ Encode
			+ Decode
			+ AtLeast32BitUnsigned
			+ MaxEncodedLen
			+ Copy;
		/// The reputation decay percentage
		type DecayPercentage: Get<Percent>;
		/// The identifier type for an offchain worker.
		type OffChainAuthId: AppCrypto<Self::Public, Self::Signature>;

		/// Listener for authority set changes
		type OnAuthoritySetChangeHandler: OnAuthoritySetChangeHandler<
			Self::AccountId,
			dkg_runtime_primitives::AuthoritySetId,
			Self::DKGId,
		>;

		/// Utility trait for handling DKG public key changes
		type OnDKGPublicKeyChangeHandler: OnDKGPublicKeyChangeHandler<
			dkg_runtime_primitives::AuthoritySetId,
		>;

		/// Proposer handler trait
		type ProposalHandler: ProposalHandlerTrait<MaxProposalLength = Self::MaxProposalLength>;

		/// A type that gives allows the pallet access to the session progress
		type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;

		/// Number of blocks of cooldown after unsigned transaction is included.
		///
		/// This ensures that we only accept unsigned transactions once, every `UnsignedInterval`
		/// blocks.
		#[pallet::constant]
		type UnsignedInterval: Get<BlockNumberFor<Self>>;
		/// A configuration for base priority of unsigned transactions.
		///
		/// This is exposed so that it can be tuned for particular runtime, when
		/// multiple pallets send unsigned transactions.
		#[pallet::constant]
		type UnsignedPriority: Get<TransactionPriority>;

		/// Session length helper allowing to query session length across runtime upgrades.
		#[pallet::constant]
		type SessionPeriod: Get<BlockNumberFor<Self>>;

		/// MaxLength for keys
		#[pallet::constant]
		type MaxKeyLength: Get<u32>
			+ Default
			+ TypeInfo
			+ MaxEncodedLen
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord;

		/// MaxLength for signature
		#[pallet::constant]
		type MaxSignatureLength: Get<u32>
			+ Default
			+ TypeInfo
			+ MaxEncodedLen
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord;

		/// Max authorities to store
		#[pallet::constant]
		type MaxAuthorities: Get<u32>
			+ Default
			+ TypeInfo
			+ MaxEncodedLen
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord;

		/// Max reporters to store
		#[pallet::constant]
		type MaxReporters: Get<u32>
			+ Default
			+ TypeInfo
			+ MaxEncodedLen
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord;

		/// Length of encoded proposer vote
		#[pallet::constant]
		type VoteLength: Get<u32>
			+ Default
			+ TypeInfo
			+ MaxEncodedLen
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord;

		/// The origin which may forcibly reset parameters or otherwise alter
		/// privileged attributes.
		type ForceOrigin: EnsureOrigin<Self::RuntimeOrigin>;

		/// Max length of a proposal
		#[pallet::constant]
		type MaxProposalLength: Get<u32>
			+ Debug
			+ Clone
			+ Eq
			+ PartialEq
			+ PartialOrd
			+ Ord
			+ TypeInfo;

		type WeightInfo: WeightInfo;
	}

	#[pallet::pallet]
	pub struct Pallet<T>(PhantomData<T>);

	#[pallet::hooks]
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
		fn offchain_worker(block_number: BlockNumberFor<T>) {
			let res = Self::submit_genesis_public_key_onchain(block_number);
			log::debug!(
				target: "runtime::dkg_metadata",
				"submit_genesis_public_key_onchain : {:?}",
				res,
			);
			let res = Self::submit_next_public_key_onchain(block_number);
			log::debug!(
				target: "runtime::dkg_metadata",
				"submit_next_public_key_onchain : {:?}",
				res,
			);
			let res = Self::submit_misbehaviour_reports_onchain(block_number);
			log::debug!(
				target: "runtime::dkg_metadata",
				"submit_misbehaviour_reports_onchain : {:?}",
				res,
			);
			let (authority_id, pk) = DKGPublicKey::<T>::get();
			let maybe_next_key = NextDKGPublicKey::<T>::get();
			log::debug!(
				target: "runtime::dkg_metadata",
				"Current Authority({}) DKG PublicKey:
				**********************************************************
				compressed: 0x{}
				uncompressed: 0x{}
				**********************************************************",
				authority_id,
				hex::encode(pk.clone()),
				hex::encode(Self::decompress_public_key(pk.into()).unwrap_or_default()),
			);
			if let Some((next_authority_id, next_pk)) = maybe_next_key {
				log::debug!(
					target: "runtime::dkg_metadata",
					"Next Authority({}) DKG PublicKey:
					**********************************************************
					compressed: 0x{}
					uncompressed: 0x{}
					**********************************************************",
					next_authority_id,
					hex::encode(next_pk.clone()),
					hex::encode(Self::decompress_public_key(next_pk.into()).unwrap_or_default()),
				);
			}
		}

		fn on_initialize(n: BlockNumberFor<T>) -> frame_support::weights::Weight {
			// reset the `ShouldExecuteNewKeygen` flag if it is set to true.
			// this is done to ensure that the flag is reset and only read once per DKG
			// `on_finality_notification` call.
			if let (true, _) = ShouldExecuteNewKeygen::<T>::get() {
				ShouldExecuteNewKeygen::<T>::put((false, false))
			}

			// Our goal is to trigger the ShouldExecuteNewKeygen if either of the two conditions are
			// true : 1. A SessionPeriod of blocks have passed from the LastSessionRotationBlock
			// 2. If 1 is true and we have not yet seen NextKey on chain for the last
			// BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER blocks check if we have passed exactly
			// `Period` blocks from the last session rotation
			let blocks_passed_since_last_session_rotation =
				n - LastSessionRotationBlock::<T>::get();
			if blocks_passed_since_last_session_rotation >= T::SessionPeriod::get() &&
				blocks_passed_since_last_session_rotation %
					BLOCKS_TO_WAIT_BEFORE_KEYGEN_RETRY_TRIGGER.into() ==
					0u32.into()
			{
				// lets set the ShouldStartDKG to true
				// we dont set force_keygen to true, that is reserved for emergency rotate
				ShouldExecuteNewKeygen::<T>::put((true, false));
			}

			// Check if we shall refresh the DKG.
			if Self::should_refresh(n) && !Self::refresh_in_progress() {
				if let Some(pub_key) = Self::next_dkg_public_key() {
					Self::do_refresh(pub_key.1.into());
					return Weight::from_parts(1_u64, 1024)
				}
			}

			Weight::from_parts(0, 0)
		}
	}

	/// Public key Signatures for past sessions
	#[pallet::storage]
	#[pallet::getter(fn used_signatures)]
	pub type UsedSignatures<T: Config> = StorageValue<
		_,
		BoundedVec<BoundedVec<u8, T::MaxSignatureLength>, T::MaxSignatureLength>,
		ValueQuery,
	>;

	/// Nonce value for next refresh proposal
	#[pallet::storage]
	#[pallet::getter(fn refresh_nonce)]
	pub type RefreshNonce<T: Config> = StorageValue<_, u32, ValueQuery>;

	/// Defines the block when next unsigned transaction will be accepted.
	///
	/// To prevent spam of unsigned (and unpayed!) transactions on the network,
	/// we only allow one transaction every `T::UnsignedInterval` blocks.
	/// This storage entry defines when new transaction is going to be accepted.
	#[pallet::storage]
	#[pallet::getter(fn next_unsigned_at)]
	pub(super) type NextUnsignedAt<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
	/// Check if there is a refresh in progress.
	#[pallet::storage]
	#[pallet::getter(fn refresh_in_progress)]
	pub type RefreshInProgress<T: Config> = StorageValue<_, bool, ValueQuery>;

	/// Should we start a new Keygen
	#[pallet::storage]
	#[pallet::getter(fn should_execute_new_keygen)]
	// Should execute new keygen -> (should_execute, force_new_keygen)
	pub type ShouldExecuteNewKeygen<T: Config> = StorageValue<_, (bool, bool), ValueQuery>;

	/// Should we submit a vote for the new DKG governor if we are a proposer
	#[pallet::storage]
	#[pallet::getter(fn should_submit_proposer_vote)]
	pub type ShouldSubmitProposerVote<T: Config> = StorageValue<_, bool, ValueQuery>;

	/// Holds public key for next session
	#[pallet::storage]
	#[pallet::getter(fn next_dkg_public_key)]
	pub type NextDKGPublicKey<T: Config> = StorageValue<
		_,
		(dkg_runtime_primitives::AuthoritySetId, BoundedVec<u8, T::MaxKeyLength>),
		OptionQuery,
	>;

	/// Signature of the DKG public key for the next session
	#[pallet::storage]
	#[pallet::getter(fn next_public_key_signature)]
	pub type NextPublicKeySignature<T: Config> =
		StorageValue<_, BoundedVec<u8, T::MaxSignatureLength>, OptionQuery>;

	/// Holds active public key for ongoing session
	#[pallet::storage]
	#[pallet::getter(fn dkg_public_key)]
	pub type DKGPublicKey<T: Config> = StorageValue<
		_,
		(dkg_runtime_primitives::AuthoritySetId, BoundedVec<u8, T::MaxKeyLength>),
		ValueQuery,
	>;

	/// Signature of the current DKG public key
	#[pallet::storage]
	#[pallet::getter(fn public_key_signature)]
	pub type DKGPublicKeySignature<T: Config> =
		StorageValue<_, BoundedVec<u8, T::MaxSignatureLength>, ValueQuery>;

	/// Holds public key for immediate past session
	#[pallet::storage]
	#[pallet::getter(fn previous_public_key)]
	pub type PreviousPublicKey<T: Config> = StorageValue<
		_,
		(dkg_runtime_primitives::AuthoritySetId, BoundedVec<u8, T::MaxKeyLength>),
		ValueQuery,
	>;

	/// Tracks current voter set
	#[pallet::storage]
	#[pallet::getter(fn historical_rounds)]
	pub type HistoricalRounds<T: Config> = StorageMap<
		_,
		Blake2_256,
		dkg_runtime_primitives::AuthoritySetId,
		RoundMetadata<T::MaxKeyLength, T::MaxSignatureLength>,
		ValueQuery,
	>;

	/// The current signature threshold (i.e. the `t` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn signature_threshold)]
	pub(super) type SignatureThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The current signature threshold (i.e. the `n` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn keygen_threshold)]
	pub(super) type KeygenThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The current signature threshold (i.e. the `t` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn next_signature_threshold)]
	pub(super) type NextSignatureThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The current signature threshold (i.e. the `n` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn next_keygen_threshold)]
	pub(super) type NextKeygenThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The pending signature threshold (i.e. the `t` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn pending_signature_threshold)]
	pub(super) type PendingSignatureThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The pending signature threshold (i.e. the `n` in t-of-n)
	#[pallet::storage]
	#[pallet::getter(fn pending_keygen_threshold)]
	pub(super) type PendingKeygenThreshold<T: Config> = StorageValue<_, u16, ValueQuery>;

	/// The current authorities set
	#[pallet::storage]
	#[pallet::getter(fn authorities)]
	pub(super) type Authorities<T: Config> =
		StorageValue<_, BoundedVec<T::DKGId, T::MaxAuthorities>, ValueQuery>;

	/// The current authority set id
	#[pallet::storage]
	#[pallet::getter(fn authority_set_id)]
	pub(super) type AuthoritySetId<T: Config> =
		StorageValue<_, dkg_runtime_primitives::AuthoritySetId, ValueQuery>;

	/// The next authority set id
	#[pallet::storage]
	#[pallet::getter(fn next_authority_set_id)]
	pub(super) type NextAuthoritySetId<T: Config> =
		StorageValue<_, dkg_runtime_primitives::AuthoritySetId, ValueQuery>;

	/// Authorities set scheduled to be used with the next session
	#[pallet::storage]
	#[pallet::getter(fn next_authorities)]
	pub(super) type NextAuthorities<T: Config> =
		StorageValue<_, BoundedVec<T::DKGId, T::MaxAuthorities>, ValueQuery>;

	/// Accounts for the current authorities
	#[pallet::storage]
	#[pallet::getter(fn current_authorities_accounts)]
	pub type CurrentAuthoritiesAccounts<T: Config> =
		StorageValue<_, BoundedVec<T::AccountId, T::MaxAuthorities>, ValueQuery>;

	/// Authority account ids scheduled for the next session
	#[pallet::storage]
	#[pallet::getter(fn next_authorities_accounts)]
	pub(super) type NextAuthoritiesAccounts<T: Config> =
		StorageValue<_, BoundedVec<T::AccountId, T::MaxAuthorities>, ValueQuery>;

	/// Authority account ids scheduled for the next session
	#[pallet::storage]
	#[pallet::getter(fn account_to_authority)]
	pub(super) type AccountToAuthority<T: Config> =
		StorageMap<_, Blake2_256, T::AccountId, T::DKGId, OptionQuery>;

	/// Tracks misbehaviour reports
	#[pallet::storage]
	#[pallet::getter(fn misbehaviour_reports)]
	pub type MisbehaviourReports<T: Config> = StorageMap<
		_,
		Blake2_256,
		(
			dkg_runtime_primitives::MisbehaviourType,
			dkg_runtime_primitives::AuthoritySetId,
			T::DKGId,
		),
		AggregatedMisbehaviourReports<T::DKGId, T::MaxSignatureLength, T::MaxReporters>,
		OptionQuery,
	>;

	/// Tracks authority reputations
	#[pallet::storage]
	#[pallet::getter(fn authority_reputations)]
	pub type AuthorityReputations<T: Config> =
		StorageMap<_, Blake2_128Concat, T::DKGId, T::Reputation, ValueQuery>;

	/// Tracks jailed authorities for keygen by mapping
	/// to the block number when the authority was last jailed
	#[pallet::storage]
	#[pallet::getter(fn jailed_keygen_authorities)]
	pub type JailedKeygenAuthorities<T: Config> =
		StorageMap<_, Blake2_256, T::DKGId, BlockNumberFor<T>, ValueQuery>;

	/// Tracks jailed authorities for signing by mapping
	/// to the block number when the authority was last jailed
	#[pallet::storage]
	#[pallet::getter(fn jailed_signing_authorities)]
	pub type JailedSigningAuthorities<T: Config> =
		StorageMap<_, Blake2_256, T::DKGId, BlockNumberFor<T>, ValueQuery>;

	/// The current best authorities of the active keygen set
	#[pallet::storage]
	#[pallet::getter(fn best_authorities)]
	pub(super) type BestAuthorities<T: Config> =
		StorageValue<_, BoundedVec<(u16, T::DKGId), T::MaxAuthorities>, ValueQuery>;

	/// The next best authorities of the active keygen set
	#[pallet::storage]
	#[pallet::getter(fn next_best_authorities)]
	pub(super) type NextBestAuthorities<T: Config> =
		StorageValue<_, BoundedVec<(u16, T::DKGId), T::MaxAuthorities>, ValueQuery>;

	/// The last BlockNumber at which the session rotation happened
	#[pallet::storage]
	#[pallet::getter(fn last_session_rotation_block)]
	pub(super) type LastSessionRotationBlock<T: Config> =
		StorageValue<_, BlockNumberFor<T>, ValueQuery>;

	/// The pending refresh proposal waiting for signature
	#[pallet::storage]
	#[pallet::getter(fn pending_refresh_proposal)]
	pub(super) type PendingRefreshProposal<T: Config> =
		StorageValue<_, RefreshProposal, OptionQuery>;

	/// The current refresh proposal signed and ready to process
	#[pallet::storage]
	#[pallet::getter(fn current_refresh_proposal)]
	pub(super) type CurrentRefreshProposal<T: Config> =
		StorageValue<_, RefreshProposal, OptionQuery>;

	#[pallet::error]
	pub enum Error<T> {
		/// No mapped account to authority
		NoMappedAccount,
		/// Invalid threshold
		InvalidThreshold,
		/// Must be queued  to become an authority
		MustBeAQueuedAuthority,
		/// Must be an an authority
		MustBeAnActiveAuthority,
		/// Invalid public key submission
		InvalidPublicKeys,
		/// Already submitted a public key
		AlreadySubmittedPublicKey,
		/// Already submitted a public key signature
		AlreadySubmittedSignature,
		/// Used signature from past sessions
		UsedSignature,
		/// Invalid public key signature submission
		InvalidSignature,
		/// Invalid Nonece used, must be greater than [`refresh_nonce`].
		InvalidNonce,
		/// Invalid misbehaviour reports
		InvalidMisbehaviourReports,
		/// DKG Refresh is already in progress.
		RefreshInProgress,
		/// No current refresh active
		NoRefreshProposal,
		/// Invalid refresh proposal data
		InvalidRefreshProposal,
		/// No NextPublicKey stored on-chain.
		NoNextPublicKey,
		/// Must be calling from the controller account
		InvalidControllerAccount,
		/// Input is out of bounds
		OutOfBounds,
		/// Cannot retreive signer from ecdsa signature
		CannotRetreiveSigner,
		/// Proposal is not signed and should not be processed
		ProposalNotSigned,
		/// Reported misbehaviour against a non authority
		OffenderNotAuthority,
		/// Authority is already jailed
		AlreadyJailed,
		/// We do not have authorities to jail
		NotEnoughAuthoritiesToJail,
	}

	// Pallets use events to inform users when important changes are made.
	#[pallet::event]
	#[pallet::generate_deposit(pub fn deposit_event)]
	pub enum Event<T: Config> {
		/// Current public key submitted
		PublicKeySubmitted { compressed_pub_key: Vec<u8> },
		/// Next public key submitted
		NextPublicKeySubmitted { compressed_pub_key: Vec<u8> },
		/// Next public key signature submitted
		NextPublicKeySignatureSubmitted {
			/// The merkle root of the voters (validators)
			voter_merkle_root: [u8; 32],
			/// The session length in milliseconds
			session_length: u64,
			/// The number of voters
			voter_count: u32,
			/// The refresh nonce for the rotation
			nonce: ProposalNonce,
			/// The public key of the governor
			pub_key: Vec<u8>,
			/// The Signature of the data above, concatenated.
			signature: Vec<u8>,
			/// The compressed pub key
			compressed_pub_key: Vec<u8>,
		},
		/// Current Public Key Changed.
		PublicKeyChanged { compressed_pub_key: Vec<u8> },
		/// Current Public Key Signature Changed.
		PublicKeySignatureChanged {
			/// The merkle root of the voters (validators)
			voter_merkle_root: [u8; 32],
			/// The session length in milliseconds
			session_length: u64,
			/// The number of voters
			voter_count: u32,
			/// The refresh nonce for the rotation
			nonce: ProposalNonce,
			/// The public key of the governor
			pub_key: Vec<u8>,
			/// The Signature of the data above, concatenated.
			signature: Vec<u8>,
			/// The compressed pub key
			compressed_pub_key: Vec<u8>,
		},
		/// Misbehaviour reports submitted
		MisbehaviourReportsSubmitted {
			misbehaviour_type: MisbehaviourType,
			reporters: Vec<T::DKGId>,
			offender: T::DKGId,
		},
		/// Proposer votes submitted
		ProposerSetVotesSubmitted { voters: Vec<T::DKGId>, signatures: Vec<Vec<u8>>, vote: Vec<u8> },
		/// Refresh DKG Keys Finished (forcefully).
		RefreshKeysFinished { next_authority_set_id: dkg_runtime_primitives::AuthoritySetId },
		/// NextKeygenThreshold updated
		NextKeygenThresholdUpdated { next_keygen_threshold: u16 },
		/// NextSignatureThreshold updated
		NextSignatureThresholdUpdated { next_signature_threshold: u16 },
		/// PendingKeygenThreshold updated
		PendingKeygenThresholdUpdated { pending_keygen_threshold: u16 },
		/// PendingSignatureThreshold updated
		PendingSignatureThresholdUpdated { pending_signature_threshold: u16 },
		/// An Emergency Keygen Protocol was triggered.
		EmergencyKeygenTriggered,
		/// An authority has been jailed for misbehaviour
		AuthorityJailed { misbehaviour_type: MisbehaviourType, authority: T::DKGId },
		/// An authority has been unjailed
		AuthorityUnJailed { authority: T::DKGId },
	}

	#[pallet::genesis_config]
	pub struct GenesisConfig<T: Config> {
		pub authorities: Vec<T::DKGId>,
		pub keygen_threshold: u16,
		pub signature_threshold: u16,
		pub authority_ids: Vec<T::AccountId>,
	}

	impl<T: Config> Default for GenesisConfig<T> {
		fn default() -> Self {
			Self {
				authorities: Vec::new(),
				signature_threshold: 1,
				keygen_threshold: 3,
				authority_ids: Vec::new(),
			}
		}
	}

	#[pallet::genesis_build]
	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
		fn build(&self) {
			assert!(
				self.signature_threshold < self.keygen_threshold,
				"Signature threshold must be less than keygen threshold"
			);
			assert!(self.keygen_threshold > 1, "Keygen threshold must be greater than 1");
			assert!(
				self.authority_ids.len() >= self.keygen_threshold as usize,
				"Not enough authority ids specified"
			);

			// Set thresholds to be the same
			SignatureThreshold::<T>::put(self.signature_threshold);
			KeygenThreshold::<T>::put(self.keygen_threshold);
			NextSignatureThreshold::<T>::put(self.signature_threshold);
			NextKeygenThreshold::<T>::put(self.keygen_threshold);
			PendingSignatureThreshold::<T>::put(self.signature_threshold);
			PendingKeygenThreshold::<T>::put(self.keygen_threshold);
			RefreshNonce::<T>::put(0);
		}
	}

	#[pallet::call]
	impl<T: Config> Pallet<T> {
		/// Set the pending signature threshold for the session following the next session.
		///
		/// We cannot assume that the next DKG has not already completed keygen.
		/// After all, if we are in a new session the next DKG may have already completed.
		/// Therefore, when we update the thresholds we are updating a threshold
		/// that will become the next threshold after the next session update.
		///
		/// * `origin` - The account origin.
		/// * `new_threshold` - The new signature threshold for the DKG.
		#[pallet::weight(<T as Config>::WeightInfo::set_signature_threshold())]
		#[pallet::call_index(0)]
		pub fn set_signature_threshold(
			origin: OriginFor<T>,
			new_threshold: u16,
		) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			ensure!(new_threshold > 0, Error::<T>::InvalidThreshold);
			ensure!(
				usize::from(new_threshold) < NextAuthorities::<T>::get().len(),
				Error::<T>::InvalidThreshold
			);
			PendingSignatureThreshold::<T>::try_mutate(|threshold| {
				*threshold = new_threshold;
				Self::deposit_event(Event::PendingSignatureThresholdUpdated {
					pending_signature_threshold: new_threshold,
				});
				Ok(().into())
			})
		}

		/// Set the pending keygen threshold for the session following the next session.
		///
		/// We cannot assume that the next DKG has not already completed keygen.
		/// After all, if we are in a new session the next DKG may have already completed.
		/// Therefore, when we update the thresholds we are updating a threshold
		/// that will become the next threshold after the next session update.
		///
		/// * `origin` - The account origin.
		/// * `new_threshold` - The new keygen threshold for the DKG.

		#[pallet::weight(<T as Config>::WeightInfo::set_keygen_threshold())]
		#[pallet::call_index(1)]
		pub fn set_keygen_threshold(
			origin: OriginFor<T>,
			new_threshold: u16,
		) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			ensure!(new_threshold > 1, Error::<T>::InvalidThreshold);
			ensure!(
				usize::from(new_threshold) <= NextAuthorities::<T>::get().len(),
				Error::<T>::InvalidThreshold
			);

			if new_threshold <= PendingSignatureThreshold::<T>::get() {
				let pending_signature_threshold = new_threshold.saturating_sub(1);
				Self::update_signature_threshold(pending_signature_threshold)?;
				Self::deposit_event(Event::PendingSignatureThresholdUpdated {
					pending_signature_threshold,
				});
			}

			Self::update_keygen_threshold(new_threshold)?;
			Self::deposit_event(Event::PendingKeygenThresholdUpdated {
				pending_keygen_threshold: new_threshold,
			});
			Ok(().into())
		}

		/// Submits and stores the active public key for the genesis session into the on-chain
		/// storage. This is primarily used to separate the genesis public key submission from
		/// non-genesis rounds.
		///
		/// Can only be submitted by the current authorities. It is also required that a
		/// `SignatureThreshold` of submissions is reached in order to successfully
		/// store the public key on-chain.
		///
		/// * `origin` - The account origin.
		/// * `keys_and_signatures` - The aggregated public keys and signatures for possible current
		///   DKG public keys.

		#[pallet::weight(<T as Config>::WeightInfo::submit_public_key(keys_and_signatures.keys_and_signatures.len() as u32))]
		#[pallet::call_index(2)]
		pub fn submit_public_key(
			origin: OriginFor<T>,
			keys_and_signatures: AggregatedPublicKeys,
		) -> DispatchResultWithPostInfo {
			ensure_none(origin)?;
			ensure!(!DKGPublicKey::<T>::exists(), Error::<T>::AlreadySubmittedPublicKey);

			let authorities: Vec<T::DKGId> =
				Self::best_authorities().iter().map(|id| id.1.clone()).collect();

			let dict = Self::process_public_key_submissions(keys_and_signatures, authorities)?;
			let threshold = Self::signature_threshold();

			let mut accepted = false;
			for (key, reporters) in dict.iter() {
				if reporters.len() >= threshold.into() {
					let bounded_key: BoundedVec<_, _> =
						key.clone().try_into().map_err(|_| Error::<T>::OutOfBounds)?;
					DKGPublicKey::<T>::put((Self::authority_set_id(), bounded_key));
					Self::deposit_event(Event::PublicKeySubmitted {
						compressed_pub_key: key.clone(),
					});
					accepted = true;

					for authority in reporters {
						let decay: Percent = T::DecayPercentage::get();
						let reputation = AuthorityReputations::<T>::get(authority.clone());
						AuthorityReputations::<T>::insert(
							authority,
							decay.mul_floor(reputation).saturating_add(INITIAL_REPUTATION.into()),
						);
					}

					break
				}
			}

			if accepted {
				// now increment the block number at which we expect next unsigned transaction.
				let current_block = <frame_system::Pallet<T>>::block_number();
				<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
				return Ok(().into())
			}

			Err(Error::<T>::InvalidPublicKeys.into())
		}

		/// Submits and stores the next public key for the next session into the on-chain storage.
		///
		/// Can only be submitted by the next authorities. It is also required that a
		/// `NextSignatureThreshold` of submissions is reached in order to successfully
		/// store the public key on-chain.
		///
		/// * `origin` - The account origin.
		/// * `keys_and_signatures` - The aggregated public keys and signatures for possible next
		///   DKG public keys.

		#[pallet::weight(<T as Config>::WeightInfo::submit_next_public_key(keys_and_signatures.keys_and_signatures.len() as u32))]
		#[pallet::call_index(3)]
		pub fn submit_next_public_key(
			origin: OriginFor<T>,
			keys_and_signatures: AggregatedPublicKeys,
		) -> DispatchResultWithPostInfo {
			ensure_none(origin)?;
			ensure!(!NextDKGPublicKey::<T>::exists(), Error::<T>::AlreadySubmittedPublicKey);

			let next_authorities: Vec<T::DKGId> =
				Self::next_best_authorities().iter().map(|id| id.1.clone()).collect();
			let dict = Self::process_public_key_submissions(keys_and_signatures, next_authorities)?;
			let threshold = Self::next_signature_threshold();

			// Loop through the keys, and if we find one that has enough signatures, store it.
			//
			// This loop returns early if a key is found that has enough signatures, otherwise, it
			// will return None.
			let mut keys = dict.iter();
			let accepted_key = loop {
				if let Some((key, accounts)) = keys.next() {
					if accounts.len() >= threshold.into() {
						let bounded_key: BoundedVec<_, _> =
							key.clone().try_into().map_err(|_| Error::<T>::OutOfBounds)?;
						NextDKGPublicKey::<T>::put((Self::next_authority_set_id(), bounded_key));

						// bump reputation for all accounts
						for authority in accounts {
							let reputation = AuthorityReputations::<T>::get(authority.clone());
							AuthorityReputations::<T>::insert(
								authority,
								reputation.saturating_add(REPUTATION_INCREMENT.into()),
							);
						}

						Self::deposit_event(Event::NextPublicKeySubmitted {
							compressed_pub_key: key.clone(),
						});
						break Some((Self::next_authority_set_id(), key.clone()))
					}
				} else {
					break None
				}
			};

			if let Some((set_id, key)) = accepted_key {
				// TODO: Do something about accounts that posted a wrong key
				// now increment the block number at which we expect next unsigned transaction.
				let current_block = <frame_system::Pallet<T>>::block_number();
				<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
				// Reset `RefreshInProgress` to false, so that we submit a new refresh.
				RefreshInProgress::<T>::put(false);
				log::debug!(
					target: "runtime::dkg_metadata",
					"Next DKG Public Key: {}, Authority Set ID: {}",
					hex::encode(key),
					set_id,
				);
				Ok(().into())
			} else {
				Err(Error::<T>::InvalidPublicKeys.into())
			}
		}

		/// Submits misbehaviour reports on chain. Signatures of the offending authority are
		/// verified against the current or next authorities depending on the type of misbehaviour.
		/// - Keygen: Verifies against the next authorities, since they are doing keygen.
		/// - Signing: Verifies against the current authorities, since they are doing signing.
		///
		/// Verifies the reports against the respective thresholds and if enough reports are met
		/// begins to jail and decrease the reputation of the offending authority.
		///
		/// The misbehaviour reputation update is:
		/// 	AUTHORITY_REPUTATION = DECAY_PERCENTAGE * AUTHORITY_REPUTATION
		///
		/// If there are not enough unjailed keygen authorities to perform a keygen after the next
		/// session, then we deduct the pending keygen threshold (and pending signing threshold)
		/// accordingly.
		///
		/// * `origin` - The account origin.
		/// * `reports` - The aggregated misbehaviour reports containing signatures of an offending
		///   authority

		#[pallet::weight(<T as Config>::WeightInfo::submit_misbehaviour_reports(reports.reporters.len() as u32))]
		#[pallet::call_index(5)]
		pub fn submit_misbehaviour_reports(
			origin: OriginFor<T>,
			reports: AggregatedMisbehaviourReports<
				T::DKGId,
				T::MaxSignatureLength,
				T::MaxReporters,
			>,
		) -> DispatchResultWithPostInfo {
			ensure_none(origin)?;
			let offender = reports.offender.clone();

			ensure!(
				!JailedKeygenAuthorities::<T>::contains_key(&offender),
				Error::<T>::AlreadyJailed
			);
			ensure!(
				!JailedSigningAuthorities::<T>::contains_key(&offender),
				Error::<T>::AlreadyJailed
			);

			let misbehaviour_type = reports.misbehaviour_type;
			let authorities = match misbehaviour_type {
				// We assume genesis ran successfully. Therefore, keygen misbehaviours are from next
				// keygen authorities
				MisbehaviourType::Keygen => Self::next_authorities(),
				// Signing misbehaviours are from current authorities
				MisbehaviourType::Sign => Self::authorities(),
			};

			// sanity check, is the offender an authority?
			ensure!(authorities.contains(&offender), Error::<T>::OffenderNotAuthority);

			let valid_reporters = Self::process_misbehaviour_reports(reports, authorities.into());
			// Get the threshold for the misbehaviour type
			let signature_threshold = match misbehaviour_type {
				// Keygen misbehaviours are from next keygen authorities
				MisbehaviourType::Keygen => Self::next_signature_threshold(),
				// Signing misbehaviours are from current authorities
				MisbehaviourType::Sign => Self::signature_threshold(),
			};

			if valid_reporters.len() > signature_threshold.into() {
				// Deduct one point for misbehaviour report
				let reputation = AuthorityReputations::<T>::get(&offender);
				// Compute reputation impact and apply to the offender
				let decay = T::DecayPercentage::get();
				AuthorityReputations::<T>::insert(&offender, decay.mul_floor(reputation));
				// Jail the respective misbehaving party depending on the misbehaviour type
				let now = frame_system::Pallet::<T>::block_number();
				match misbehaviour_type {
					MisbehaviourType::Keygen => {
						// Check if we have enough unjailed authorities to run after the next
						// session change
						let unjailed_authorities = Self::next_best_authorities()
							.into_iter()
							.filter(|(_, id)| !JailedKeygenAuthorities::<T>::contains_key(id))
							.map(|(_, id)| id)
							.collect::<Vec<T::DKGId>>();

						if unjailed_authorities.contains(&offender) {
							// Jail the offender
							JailedKeygenAuthorities::<T>::insert(&offender, now);

							Self::deposit_event(Event::AuthorityJailed {
								misbehaviour_type,
								authority: offender.clone(),
							});

							// Check for authorities that are
							// 1. Not jailed
							// 2. Not already included in the next_best_authorities
							let non_jailed_non_next_best_authorities = Self::next_authorities()
								.into_iter()
								.filter(|id| !unjailed_authorities.contains(id))
								.filter(|id| !JailedKeygenAuthorities::<T>::contains_key(id))
								.collect::<Vec<T::DKGId>>();

							// If we have authorities that can take the place of the jailed
							// authority find the authority with the highest reputation to replace
							// the jailed authority
							if !non_jailed_non_next_best_authorities.is_empty() {
								let mut authorities_ordered_by_reputation =
									AuthorityReputations::<T>::iter()
										.filter(|id| {
											non_jailed_non_next_best_authorities.contains(&id.0)
										})
										.collect::<Vec<(T::DKGId, T::Reputation)>>();

								authorities_ordered_by_reputation.sort_by(|a, b| a.1.cmp(&b.1));

								// If we cannot find any authority by highest reputation
								// pick the first authority
								let highest_reputation_authority =
									if let Some(most_reputed_authority) =
										authorities_ordered_by_reputation.pop()
									{
										most_reputed_authority.0
									} else {
										non_jailed_non_next_best_authorities[0].clone()
									};

								let next_best_authorities: BoundedVec<_, _> =
									Self::get_best_authorities(
										Self::next_keygen_threshold() as usize,
										&unjailed_authorities
											.into_iter()
											.filter(|id| *id != offender)
											.chain(vec![highest_reputation_authority])
											.collect::<Vec<_>>(),
									)
									.try_into()
									.map_err(|_| Error::<T>::OutOfBounds)?;

								// final sanity check, we need atleast two authorities
								ensure!(
									next_best_authorities.len() >= 2,
									Error::<T>::NotEnoughAuthoritiesToJail
								);

								NextBestAuthorities::<T>::put(next_best_authorities);

								// emit event
								Self::deposit_event(Event::MisbehaviourReportsSubmitted {
									misbehaviour_type,
									reporters: valid_reporters,
									offender,
								});

								return Ok(().into())
							}

							// If we do not have any authorities remaining, drop the keygen
							// threshold
							if unjailed_authorities.len() <= Self::next_keygen_threshold().into() {
								// Handle edge case properly (shouldn't drop below 2 authorities)
								if unjailed_authorities.len() > 2 {
									let new_val = u16::try_from(unjailed_authorities.len() - 1)
										.unwrap_or_default();
									Self::update_next_keygen_threshold(new_val);
									Self::update_pending_keygen_threshold(new_val);

									if NextSignatureThreshold::<T>::get() >=
										NextKeygenThreshold::<T>::get()
									{
										// drop signature threshold
										let next_signature_threshold =
											NextSignatureThreshold::<T>::get();
										if next_signature_threshold != 1 {
											NextSignatureThreshold::<T>::put(
												next_signature_threshold - 1,
											);
											PendingSignatureThreshold::<T>::put(
												next_signature_threshold - 1,
											);
										}
									}
								}
							}
						}

						let next_best_authorities: BoundedVec<_, _> = Self::get_best_authorities(
							Self::next_keygen_threshold() as usize,
							&unjailed_authorities
								.into_iter()
								.filter(|id| *id != offender)
								.collect::<Vec<_>>(),
						)
						.try_into()
						.map_err(|_| Error::<T>::OutOfBounds)?;

						// final sanity check, we need atleast two authorities
						ensure!(
							next_best_authorities.len() >= 2,
							Error::<T>::NotEnoughAuthoritiesToJail
						);

						NextBestAuthorities::<T>::put(next_best_authorities);
					},
					MisbehaviourType::Sign => {
						// These are the authorities who underwent keygen.
						let unjailed_authorities = Self::best_authorities()
							.into_iter()
							.filter(|(_, id)| {
								!JailedSigningAuthorities::<T>::contains_key(id) || *id != offender
							})
							.map(|(_, id)| id)
							.collect::<Vec<T::DKGId>>();
						if unjailed_authorities.len() < signature_threshold.into() {
							// Handle edge case properly (can't have -1 signers)
							if !unjailed_authorities.is_empty() {
								JailedSigningAuthorities::<T>::insert(offender.clone(), now);
								// Update the next and pending threshold
								// Since this updates the signature threshold it likely means that
								// all signing under the active DKG is failing. We have to ensure
								// that the DKG signing set contains jailed authorities in a
								// deterministic manner or expect for a forced rotation.
								let new_val = u16::try_from(unjailed_authorities.len() - 1)
									.unwrap_or_default();
								Self::update_next_signature_threshold(new_val);
								PendingSignatureThreshold::<T>::put(new_val);
							}
						} else {
							JailedSigningAuthorities::<T>::insert(offender.clone(), now);
							Self::deposit_event(Event::AuthorityJailed {
								misbehaviour_type,
								authority: offender.clone(),
							});
						}
					},
				};

				Self::deposit_event(Event::MisbehaviourReportsSubmitted {
					misbehaviour_type,
					reporters: valid_reporters,
					offender,
				});

				// now increment the block number at which we expect next unsigned transaction.
				let current_block = <frame_system::Pallet<T>>::block_number();
				<NextUnsignedAt<T>>::put(current_block + T::UnsignedInterval::get());
				return Ok(().into())
			}

			Err(Error::<T>::InvalidMisbehaviourReports.into())
		}

		/// Attempts to remove an authority from all possible jails (keygen & signing).
		/// This can only be called by the controller of the authority in jail. The
		/// origin must map directly to the authority in jail.
		///
		/// The authority's jail sentence for either keygen or signing must be elapsed
		/// for the authority to be removed from the jail.
		///
		/// * `origin` - The account origin.
		#[pallet::weight(<T as Config>::WeightInfo::unjail())]
		#[pallet::call_index(6)]
		pub fn unjail(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
			let origin = ensure_signed(origin)?;
			let authority =
				T::AuthorityIdOf::convert(origin).ok_or(Error::<T>::InvalidControllerAccount)?;
			// TODO: Consider adding a payment to unjail similar to a slash
			if frame_system::Pallet::<T>::block_number() >
				JailedKeygenAuthorities::<T>::get(authority.clone())
					.saturating_add(T::KeygenJailSentence::get())
			{
				JailedKeygenAuthorities::<T>::remove(authority.clone());
			}

			if frame_system::Pallet::<T>::block_number() >
				JailedSigningAuthorities::<T>::get(authority.clone())
					.saturating_add(T::SigningJailSentence::get())
			{
				JailedSigningAuthorities::<T>::remove(authority);
			}
			Ok(().into())
		}

		/// Force removes an authority from keygen jail.
		///
		/// Can only be called by DKG
		/// * `origin` - The account origin.
		/// * `authority` - The authority to be removed from the keygen jail.
		#[pallet::weight(<T as Config>::WeightInfo::force_unjail_keygen())]
		#[pallet::call_index(7)]
		pub fn force_unjail_keygen(
			origin: OriginFor<T>,
			authority: T::DKGId,
		) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			JailedKeygenAuthorities::<T>::remove(authority.clone());
			Self::deposit_event(Event::AuthorityUnJailed { authority });
			Ok(().into())
		}

		/// Force removes an authority from signing jail.
		///
		/// Can only be called by the root origin.
		///
		/// * `origin` - The account origin.
		/// * `authority` - The authority to be removed from the signing jail.
		#[pallet::weight(<T as Config>::WeightInfo::force_unjail_signing())]
		#[pallet::call_index(8)]
		pub fn force_unjail_signing(
			origin: OriginFor<T>,
			authority: T::DKGId,
		) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			JailedSigningAuthorities::<T>::remove(authority.clone());
			Self::deposit_event(Event::AuthorityUnJailed { authority });
			Ok(().into())
		}

		/// Forcefully rotate the DKG
		///
		/// This forces the next authorities into the current authority spot and
		/// automatically increments the authority ID. It uses `change_authorities`
		/// to execute the rotation forcefully.
		#[pallet::weight({0})]
		#[pallet::call_index(9)]
		pub fn force_change_authorities(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			let next_authorities = NextAuthorities::<T>::get();
			let next_authority_accounts = NextAuthoritiesAccounts::<T>::get();
			let next_pub_key = Self::next_dkg_public_key();
			// Clear the `PendingRefreshProposal` and `CurrentRefreshProposal` items.
			PendingRefreshProposal::<T>::kill();
			CurrentRefreshProposal::<T>::kill();
			// Force rotate the next authorities into the active and next set.
			Self::change_authorities(
				next_authorities.clone().into(),
				next_authorities.into(),
				next_authority_accounts.clone().into(),
				next_authority_accounts.into(),
				true,
			);
			// If there's a next key we immediately create a refresh proposal
			// to sign our own key as a means of jumpstarting the mechanism.
			if let Some(pub_key) = next_pub_key {
				ShouldSubmitProposerVote::<T>::put(true);
				// we use the current nonce as the next nonce since the refreshNonce
				// has been incremented in `change_authorities` incrementing here will lead to a
				// difference of two
				let next_nonce = Self::refresh_nonce();
				let data = Self::create_refresh_proposal(pub_key.1.into(), next_nonce)?;
				match T::ProposalHandler::handle_unsigned_proposal(data) {
					Ok(()) => {
						RefreshInProgress::<T>::put(true);
						RefreshNonce::<T>::put(next_nonce);
						log::debug!("Handled refresh proposal");
					},
					Err(e) => {
						log::warn!("Failed to handle refresh proposal: {:?}", e);
					},
				}
			}

			Ok(().into())
		}

		/// Triggers an Emergency Keygen Protocol.
		///
		/// The keygen protocol will then be executed and the result will be stored in the off chain
		/// storage, which will be picked up by the on chain worker and stored on chain.
		///
		/// Note that, this will clear the next public key and its signature, if any.
		#[pallet::weight({0})]
		#[pallet::call_index(10)]
		pub fn trigger_emergency_keygen(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
			T::ForceOrigin::ensure_origin(origin)?;
			// Clear the next public key, if any, to ensure that the keygen protocol runs and we
			// do not have any invalid state.
			NextDKGPublicKey::<T>::kill();
			// Clear the next public key signature, if any.
			NextPublicKeySignature::<T>::kill();
			// Emit `EmergencyKeygenTriggered` RuntimeEvent so that we can see it on monitoring.
			Self::deposit_event(Event::EmergencyKeygenTriggered);
			// Trigger the keygen protocol, activate force_keygen rotation
			<ShouldExecuteNewKeygen<T>>::put((true, true));
			Ok(().into())
		}
	}

	#[pallet::validate_unsigned]
	impl<T: Config> ValidateUnsigned for Pallet<T> {
		type Call = Call<T>;

		/// Validate unsigned call to this module.
		///
		/// By default unsigned transactions are disallowed, but implementing the validator
		/// here we make sure that some particular calls (the ones produced by offchain worker)
		/// are being whitelisted and marked as valid.
		fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
			// we allow calls only from the local OCW engine.
			match source {
				TransactionSource::Local | TransactionSource::InBlock => {},
				_ => return InvalidTransaction::Call.into(),
			}
			// Now let's check if the transaction has any chance to succeed.
			let current_block = <frame_system::Pallet<T>>::block_number();
			let next_unsigned_at = <NextUnsignedAt<T>>::get();
			if next_unsigned_at > current_block {
				log::debug!(
					target: "runtime::dkg_metadata",
					"validate unsigned: early block: current: {:?}, next_unsigned_at: {:?}",
					current_block,
					next_unsigned_at,
				);
				return InvalidTransaction::Stale.into()
			}
			// Next, let's check that we call the right function.
			// Here we will use match stmt, to match over the call and see if it is
			// one of the functions we allow. if not we should return
			// `InvalidTransaction::Call.into()`.
			// we should handle the following calls:
			// 1. `submit_public_key`
			// 2. `submit_next_public_key`
			// 3. `submit_misbehaviour_reports`.
			// other than that we should return `InvalidTransaction::Call.into()`.
			let is_valid_call = matches! {
				call,
				Call::submit_public_key { .. } |
					Call::submit_next_public_key { .. } |
					Call::submit_misbehaviour_reports { .. }
			};
			if !is_valid_call {
				log::warn!(
					target: "runtime::dkg_metadata",
					"validate unsigned: invalid call: {:?}",
					call,
				);
				InvalidTransaction::Call.into()
			} else {
				log::debug!(
					target: "runtime::dkg_metadata",
					"validate unsigned: valid call: {:?}",
					call,
				);
				ValidTransaction::with_tag_prefix("DKG")
					// We set base priority to 2**20 and hope it's included before any other
					// transactions in the pool. Next we tweak the priority by the current block,
					// so that transactions from older blocks are (more) included first.
					.priority(T::UnsignedPriority::get())
					// This transaction does not require anything else to go before into the pool.
					// In theory we could require `previous_unsigned_at` transaction to go first,
					// but it's not necessary in our case.
					//.and_requires()
					// We set the `provides` tag to be the same as `next_unsigned_at`. This makes
					// sure only one transaction produced after `next_unsigned_at` will ever
					// get to the transaction pool and will end up in the block.
					// We can still have multiple transactions compete for the same "spot",
					// and the one with higher priority will replace other one in the pool.
					// The transaction is only valid for next 5 blocks. After that it's
					// going to be revalidated by the pool.
					.longevity(5)
					.and_provides(current_block)
					// It's fine to propagate that transaction to other peers, which means it can be
					// created even by nodes that don't produce blocks.
					// Note that sometimes it's better to keep it for yourself (if you are the block
					// producer), since for instance in some schemes others may copy your solution
					// and claim a reward.
					.propagate(true)
					.build()
			}
		}
	}
}

impl<T: Config> Pallet<T> {
	/// Return the current active DKG authority set.
	pub fn authority_set() -> AuthoritySet<T::DKGId, T::MaxAuthorities> {
		AuthoritySet::<T::DKGId, T::MaxAuthorities> {
			authorities: Self::authorities(),
			id: Self::authority_set_id(),
		}
	}

	/// Return the next DKG authority set.
	pub fn next_authority_set() -> AuthoritySet<T::DKGId, T::MaxAuthorities> {
		AuthoritySet::<T::DKGId, T::MaxAuthorities> {
			authorities: Self::next_authorities(),
			id: Self::next_authority_set_id(),
		}
	}

	pub fn update_signature_threshold(new_threshold: u16) -> DispatchResultWithPostInfo {
		PendingSignatureThreshold::<T>::try_mutate(|threshold| {
			*threshold = new_threshold;
			Ok(().into())
		})
	}

	pub fn update_keygen_threshold(new_threshold: u16) -> DispatchResultWithPostInfo {
		PendingKeygenThreshold::<T>::try_mutate(|threshold| {
			*threshold = new_threshold;
			Ok(().into())
		})
	}

	pub fn decompress_public_key(compressed: Vec<u8>) -> Result<Vec<u8>, DispatchError> {
		let result = libsecp256k1::PublicKey::parse_slice(
			&compressed,
			Some(libsecp256k1::PublicKeyFormat::Compressed),
		)
		.map(|pk| pk.serialize())
		.map_err(|_| Error::<T>::InvalidPublicKeys)?;
		if result.len() == 65 {
			// remove the 0x04 prefix
			Ok(result[1..].to_vec())
		} else {
			Ok(result.to_vec())
		}
	}

	pub fn do_refresh(pub_key: Vec<u8>) {
		let next_nonce = Self::refresh_nonce() + 1u32;
		let data = match Self::create_refresh_proposal(pub_key, next_nonce) {
			Ok(data) => data,
			Err(e) => {
				log::warn!("Failed to create refresh proposal: {:?}", e);
				return
			},
		};

		match T::ProposalHandler::handle_unsigned_proposal(data) {
			Ok(()) => {
				RefreshInProgress::<T>::put(true);
				log::debug!("Handled refresh proposal");
			},
			Err(e) => {
				log::warn!("Failed to handle refresh proposal: {:?}", e);
			},
		}
	}

	pub fn create_refresh_proposal(
		pub_key: Vec<u8>,
		nonce: u32,
	) -> Result<Proposal<T::MaxProposalLength>, DispatchError> {
		let uncompressed_pub_key = Self::decompress_public_key(pub_key)?;
		let VoterSetData {
			voter_set_merkle_root,
			average_session_length_in_millisecs,
			voter_count,
		} = Self::create_voter_set_data();
		let proposal = RefreshProposal {
			voter_merkle_root: voter_set_merkle_root,
			session_length: average_session_length_in_millisecs,
			voter_count,
			nonce: nonce.into(),
			pub_key: uncompressed_pub_key,
		};

		// Store the proposal in storage. We overwrite the storage always.
		// This is to ensure that we can force rotate and re-sign successfully.
		PendingRefreshProposal::<T>::put(proposal.clone());

		// Encode the proposal and return the unsigned proposal.
		let bounded_proposal_data: BoundedVec<u8, T::MaxProposalLength> =
			proposal.encode().try_into().unwrap_or_default();
		Ok(Proposal::Unsigned { kind: ProposalKind::Refresh, data: bounded_proposal_data })
	}

	/// Creates the voter set merkle tree and auxiliary data for the `RefreshProposal`.
	///
	/// The validators's DKG Id (ECDSA keys) are used to create the voter set. We
	/// hash the public keys into Ethereum compatible 20-byte addresses using the `keccak256` hash
	/// and insert these addresses into a minimally-sized merkle tree. This allows us to use the
	/// Ethereum origins (`msg.sender`) on EVMs to prove membership in the voter set.
	///
	/// The `RefreshProposal` proposal is a message containing:
	/// - The merkle root of the ordered voter set's Ethereum addresses.
	/// - The session length in milliseconds
	/// - The # of proposers accumulated in the merkle root
	/// - The nonce of the refresh proposal
	/// - The public key of the next DKG's shared public key.
	///
	/// This data is intended to be used to update the voter set on other blockchains
	/// that need a fallback mechanism when the DKG is not available or needs to be fixed or
	/// changed.
	fn create_voter_set_data() -> VoterSetData {
		let voters = Self::next_authorities();
		// Merkleize the new voter set
		let voter_set_merkle_root = Self::get_voter_set_tree_root(&voters);
		// Get average session length
		let average_session_length_in_blocks: u64 =
			T::NextSessionRotation::average_session_length().try_into().unwrap_or_default();

		let average_millisecs_per_block: u64 =
			<T as pallet_timestamp::Config>::MinimumPeriod::get()
				.saturating_mul(2u32.into())
				.try_into()
				.unwrap_or_default();

		let average_session_length_in_millisecs =
			average_session_length_in_blocks.saturating_mul(average_millisecs_per_block);

		VoterSetData {
			voter_set_merkle_root,
			average_session_length_in_millisecs,
			voter_count: voters.len() as u32,
		}
	}

	/// Returns the leaves of the voter set merkle tree.
	///
	/// It is expected that the size of the returned vector is a power of 2.
	pub fn pre_process_for_merkleize(voters: &[T::DKGId]) -> Vec<[u8; 32]> {
		let height = Self::get_voter_set_tree_height(voters.len());
		// Hash the external accounts into 32 byte chunks to form the base layer of the merkle tree
		let mut base_layer: Vec<[u8; 32]> = voters
			.iter()
			.map(|account| T::DKGAuthorityToMerkleLeaf::convert(account.clone()))
			.map(|account| keccak_256(&account))
			.collect();
		// Pad base_layer to have length 2^height
		let two = 2;
		while base_layer.len() != two.saturating_pow(height.try_into().unwrap_or_default()) {
			base_layer.push(keccak_256(&[0u8]));
		}
		base_layer
	}

	/// Computes the next layer of the merkle tree by hashing the previous layer.
	pub fn next_layer(curr_layer: Vec<[u8; 32]>) -> Vec<[u8; 32]> {
		let mut layer_above: Vec<[u8; 32]> = Vec::new();
		let mut index = 0;
		while index < curr_layer.len() {
			let mut input_to_hash_as_vec: Vec<u8> = curr_layer[index].to_vec();
			input_to_hash_as_vec.extend_from_slice(&curr_layer[index + 1][..]);
			let input_to_hash_as_slice = &input_to_hash_as_vec[..];
			layer_above.push(keccak_256(input_to_hash_as_slice));
			index += 2;
		}
		layer_above
	}

	// Returns the minimal height of the voter set Merkle tree
	// Right now this takes O(log(size of voter set)) time but can likely be reduced
	pub fn get_voter_set_tree_height(voter_count: usize) -> u32 {
		if voter_count == 1 {
			1
		} else {
			let two: u32 = 2;
			let mut h = 0;
			while two.saturating_pow(h) < voter_count as u32 {
				h += 1;
			}
			h
		}
	}

	/// Computes the merkle root of the voter set tree
	pub fn get_voter_set_tree_root(voters: &[T::DKGId]) -> [u8; 32] {
		let mut curr_layer = Self::pre_process_for_merkleize(voters);
		let mut height = Self::get_voter_set_tree_height(voters.len());
		while height > 0 {
			curr_layer = Self::next_layer(curr_layer);
			height -= 1;
		}

		let mut root = [0u8; 32];
		root.copy_from_slice(&curr_layer[0][..]);
		root
	}

	pub fn process_public_key_submissions(
		aggregated_keys: AggregatedPublicKeys,
		authorities: Vec<T::DKGId>,
	) -> Result<BTreeMap<Vec<u8>, Vec<T::DKGId>>, DispatchError> {
		let mut dict: BTreeMap<Vec<u8>, Vec<T::DKGId>> = BTreeMap::new();

		for (pub_key, signature) in aggregated_keys.keys_and_signatures {
			let maybe_signers = authorities
				.iter()
				.map(|x| {
					ecdsa::Public(to_slice_33(&x.encode()).unwrap_or_else(|| {
						// FIXME: remove this panic, and return an error instead.
						panic!("Failed to convert account id to ecdsa public key")
					}))
				})
				.collect::<Vec<ecdsa::Public>>();

			let (maybe_authority, success) =
				verify_signer_from_set_ecdsa(maybe_signers, &pub_key, &signature);

			let authority = maybe_authority.ok_or(Error::<T>::CannotRetreiveSigner)?;

			if success {
				let authority = T::DKGId::from(authority);
				if !dict.contains_key(&pub_key) {
					dict.insert(pub_key.clone(), Vec::new());
				}
				let temp = dict
					.get_mut(&pub_key)
					.expect("this should never panic, key inserted previously!");
				if !temp.contains(&authority) {
					temp.push(authority);
				}
			}
		}

		Ok(dict)
	}

	pub fn process_misbehaviour_reports(
		reports: AggregatedMisbehaviourReports<T::DKGId, T::MaxSignatureLength, T::MaxReporters>,
		verifying_set: Vec<T::DKGId>,
	) -> Vec<T::DKGId> {
		let mut valid_reporters = Vec::new();
		for (inx, signature) in reports.signatures.iter().enumerate() {
			let mut signed_payload = Vec::new();
			signed_payload.extend_from_slice(&match reports.misbehaviour_type {
				MisbehaviourType::Keygen => [0x01],
				MisbehaviourType::Sign => [0x02],
			});
			signed_payload.extend_from_slice(reports.session_id.to_be_bytes().as_ref());
			signed_payload.extend_from_slice(reports.offender.as_ref());

			let verifying_set: Vec<ecdsa::Public> = verifying_set
				.iter()
				.map(|x| match to_slice_33(x.encode().as_ref()) {
					Some(x) => ecdsa::Public(x),
					None => ecdsa::Public([0u8; 33]),
				})
				.filter(|x| x.0 != [0u8; 33])
				.collect();
			let (_, success) =
				verify_signer_from_set_ecdsa(verifying_set, &signed_payload, signature);

			if success && !valid_reporters.contains(&reports.reporters[inx]) {
				valid_reporters.push(reports.reporters[inx].clone());
			}
		}

		valid_reporters
	}

	pub fn store_consensus_log(
		authority_ids: BoundedVec<T::DKGId, T::MaxAuthorities>,
		next_authority_ids: BoundedVec<T::DKGId, T::MaxAuthorities>,
		active_set_id: dkg_runtime_primitives::AuthoritySetId,
	) {
		let log: DigestItem = DigestItem::Consensus(
			DKG_ENGINE_ID,
			ConsensusLog::AuthoritiesChange {
				active: AuthoritySet::<T::DKGId, T::MaxAuthorities> {
					authorities: authority_ids,
					id: active_set_id,
				},
				queued: AuthoritySet::<T::DKGId, T::MaxAuthorities> {
					authorities: next_authority_ids,
					id: active_set_id.saturating_add(1),
				},
			}
			.encode(),
		);
		<frame_system::Pallet<T>>::deposit_log(log);
	}

	/// Change the current DKG authority set by rotating to the `new_authority_ids` set.
	///
	/// This function is meant to be called on a new session when the next authorities
	/// become the current or `new` authorities. We track the accounts for these
	/// authorities as well.
	fn change_authorities(
		new_authority_ids: Vec<T::DKGId>,
		next_authority_ids: Vec<T::DKGId>,
		new_authorities_accounts: Vec<T::AccountId>,
		next_authorities_accounts: Vec<T::AccountId>,
		forced: bool,
	) {
		// Call set change handler to trigger the other pallet implementing this hook
		<T::OnAuthoritySetChangeHandler as OnAuthoritySetChangeHandler<
			T::AccountId,
			dkg_runtime_primitives::AuthoritySetId,
			T::DKGId,
		>>::on_authority_set_changed(&new_authorities_accounts, &new_authority_ids);
		// Set refresh in progress to false
		RefreshInProgress::<T>::put(false);
		// Update the next thresholds for the next session
		let new_current_signature_threshold = NextSignatureThreshold::<T>::get();
		let new_current_keygen_threshold = NextKeygenThreshold::<T>::get();
		Self::update_next_signature_threshold(PendingSignatureThreshold::<T>::get());
		Self::update_next_keygen_threshold(PendingKeygenThreshold::<T>::get());
		// Compute next ID for next authorities
		let next_id = Self::next_authority_set_id();
		// We continue to rotate the next authority set in case of failure of the previous
		// next authorities to generate a key, thus preventing a signature from being produced.
		let bounded_next_authority_ids: BoundedVec<_, _> = next_authority_ids
			.clone()
			.try_into()
			.expect("This should never overflow, since read from bounded storage");
		NextAuthorities::<T>::put(&bounded_next_authority_ids);
		let bounded_next_authorities_accounts: BoundedVec<_, _> = next_authorities_accounts
			.try_into()
			.expect("This should never overflow, since read from bounded storage");
		NextAuthoritiesAccounts::<T>::put(&bounded_next_authorities_accounts);
		NextAuthoritySetId::<T>::put(next_id.saturating_add(1));
		let new_best_authorities = Self::next_best_authorities();
		// Update the keys for the next authorities
		let next_pub_key = Self::next_dkg_public_key();
		let next_pub_key_signature = Self::next_public_key_signature();
		let dkg_pub_key = Self::dkg_public_key();
		let pub_key_signature = Self::public_key_signature();
		// Ensure next/pending thresholds remain valid across authority set changes that may
		// break. We update the pending thresholds because we call `refresh_keys` below, which
		// rotates all the thresholds into the current / next sets. Pending becomes the next,
		// next becomes the current.
		if next_authority_ids.len() < Self::next_keygen_threshold().into() {
			Self::update_next_keygen_threshold(next_authority_ids.len() as u16);
			PendingKeygenThreshold::<T>::put(next_authority_ids.len() as u16);
		}
		if next_authority_ids.len() <= Self::next_signature_threshold().into() {
			Self::update_next_signature_threshold(next_authority_ids.len() as u16 - 1);
			PendingSignatureThreshold::<T>::put(next_authority_ids.len() as u16 - 1);
		}
		// Update the next best authorities after any and all changes to the thresholds.
		let bounded_authorities: BoundedVec<_, _> =
			Self::get_best_authorities(Self::next_keygen_threshold() as usize, &next_authority_ids)
				.try_into()
				.expect("This should never overflow, since read from bounded storage");
		NextBestAuthorities::<T>::put(bounded_authorities);
		// Switch on forced for forceful rotations
		let v = if forced {
			// If forced we supply an empty signature.
			next_pub_key.zip(Some(Default::default()))
		} else {
			next_pub_key.zip(next_pub_key_signature)
		};
		// Rotate the authority set if a next pub key and next signature exist
		if let Some((next_pub_key, next_pub_key_signature)) = v {
			// Update the active thresholds for the next session
			SignatureThreshold::<T>::put(new_current_signature_threshold);
			KeygenThreshold::<T>::put(new_current_keygen_threshold);
			// Update the new and next authorities
			let bounded_authority_ids: BoundedVec<_, _> = new_authority_ids
				.try_into()
				.expect("This should never overflow, since read from bounded storage");
			Authorities::<T>::put(&bounded_authority_ids);
			let bounded_authority_accounts: BoundedVec<_, _> = new_authorities_accounts
				.try_into()
				.expect("This should never overflow, since read from bounded storage");
			CurrentAuthoritiesAccounts::<T>::put(&bounded_authority_accounts);
			BestAuthorities::<T>::put(new_best_authorities);
			// Update the set id after changing
			AuthoritySetId::<T>::put(next_id);
			// Deposit a consensus log about the authority set change
			Self::store_consensus_log(bounded_authority_ids, bounded_next_authority_ids, next_id);
			// Delete next records
			NextDKGPublicKey::<T>::kill();
			NextPublicKeySignature::<T>::kill();
			// Record historical refresh record
			Self::insert_historical_refresh(
				&(dkg_pub_key.0, dkg_pub_key.clone().1),
				&(next_pub_key.0, next_pub_key.clone().1),
				next_pub_key_signature.clone(),
			);
			// Set new keys
			DKGPublicKey::<T>::put(next_pub_key.clone());
			DKGPublicKeySignature::<T>::put(next_pub_key_signature.clone());
			PreviousPublicKey::<T>::put(dkg_pub_key);
			let _ = UsedSignatures::<T>::try_mutate(|val| {
				let added = val.try_push(pub_key_signature.clone());
				if added.is_err() {
					// this should never happen, log error message that size limit has reached
					log::warn!(
						target: "runtime::dkg_metadata",
						"UsedSignature limit reached!",
					);
				};
				added
			});
			// and increment the nonce
			let current_nonce = Self::refresh_nonce();
			let next_nonce = current_nonce.saturating_add(1);
			RefreshNonce::<T>::put(next_nonce);

			// Emit events so other front-end know that.
			let compressed_pub_key = next_pub_key.1.clone();
			Self::deposit_event(Event::PublicKeyChanged {
				compressed_pub_key: compressed_pub_key.clone().into(),
			});

			// At this point the refresh proposal should ALWAYS exist
			if let Some(curr) = CurrentRefreshProposal::<T>::get() {
				Self::deposit_event(Event::PublicKeySignatureChanged {
					voter_merkle_root: curr.voter_merkle_root,
					session_length: curr.session_length,
					voter_count: curr.voter_count,
					nonce: curr.nonce,
					pub_key: curr.pub_key,
					signature: next_pub_key_signature.into(),
					compressed_pub_key: compressed_pub_key.to_vec(),
				});

				CurrentRefreshProposal::<T>::kill();
			}
		}
	}

	/// Initializes the storage values for authorities and their accounts
	/// on a genesis session and triggers the first authority set change.
	fn initialize_authorities(authorities: &[T::DKGId], authority_account_ids: &[T::AccountId]) {
		if authorities.is_empty() {
			log::warn!(
				target: "runtime::dkg_metadata",
				"trying to intialize the autorities with empty list!",
			);
			return
		}
		log::debug!(
			target: "runtime::dkg_metadata",
			"intializing the authorities with: {:?} and account ids: {:?}",
			authorities,
			authority_account_ids,
		);
		assert!(Authorities::<T>::get().is_empty(), "Authorities are already initialized!");
		// Initialize current authorities
		let bounded_authorities: BoundedVec<_, _> =
			authorities.to_vec().try_into().expect("Genesis Authorities out of bounds!");
		Authorities::<T>::put(bounded_authorities.clone());
		AuthoritySetId::<T>::put(0);
		let bounded_authority_account_ids: BoundedVec<_, _> = authority_account_ids
			.to_vec()
			.try_into()
			.expect("Genesis Authorities accounts out of bounds!");
		CurrentAuthoritiesAccounts::<T>::put(bounded_authority_account_ids.clone());
		// Initialize next authorities
		NextAuthorities::<T>::put(bounded_authorities);
		NextAuthoritySetId::<T>::put(1);
		NextAuthoritiesAccounts::<T>::put(bounded_authority_account_ids);
		let best_authorities =
			Self::get_best_authorities(Self::keygen_threshold() as usize, authorities);
		log::debug!(
			target: "runtime::dkg_metadata",
			"best_authorities: {:?}",
			best_authorities,
		);
		let bounded_best_authorities: BoundedVec<_, _> = best_authorities
			.to_vec()
			.try_into()
			.expect("Genesis Best Authorities out of bounds!");
		BestAuthorities::<T>::put(bounded_best_authorities);
		let next_best_authorities =
			Self::get_best_authorities(Self::keygen_threshold() as usize, authorities);
		let bounded_next_best_authorities: BoundedVec<_, _> = next_best_authorities
			.to_vec()
			.try_into()
			.expect("Genesis Next Best Authorities out of bounds!");
		NextBestAuthorities::<T>::put(bounded_next_best_authorities);

		<T::OnAuthoritySetChangeHandler as OnAuthoritySetChangeHandler<
			T::AccountId,
			dkg_runtime_primitives::AuthoritySetId,
			T::DKGId,
		>>::on_authority_set_changed(authority_account_ids, authorities);
	}

	/// An offchain function that collects the genesis DKG public key
	/// and submits it to the chain.
	///
	/// This submission process is modelled similarly after an oracle.
	/// We require the respective threshold of submissions of the same
	/// DKG public key to be submitted in order to modify the on-chain
	/// storage.
	fn submit_genesis_public_key_onchain(
		block_number: BlockNumberFor<T>,
	) -> Result<(), &'static str> {
		let next_unsigned_at = <NextUnsignedAt<T>>::get();
		if next_unsigned_at > block_number {
			return Err("Too early to send unsigned transaction")
		}
		let mut lock = StorageLock::<Time>::new(AGGREGATED_PUBLIC_KEYS_AT_GENESIS_LOCK);
		{
			let _guard = lock.lock();
			let mut agg_key_ref = StorageValueRef::persistent(AGGREGATED_PUBLIC_KEYS_AT_GENESIS);
			let mut submit_at_ref = StorageValueRef::persistent(SUBMIT_GENESIS_KEYS_AT);
			const RECENTLY_SENT: &str = "Already submitted a key in this session";
			let submit_at = submit_at_ref.get::<BlockNumberFor<T>>();

			let agg_keys = agg_key_ref.get::<AggregatedPublicKeys>();

			if let Ok(None) = agg_keys {
				return Ok(())
			}

			if let Ok(Some(submit_at)) = submit_at {
				if block_number < submit_at {
					log::debug!(target: "runtime::dkg_metadata", "Offchain worker skipping public key submmission");
					return Ok(())
				} else {
					submit_at_ref.clear();
				}
			} else {
				return Err(RECENTLY_SENT)
			}

			if !Self::dkg_public_key().1.is_empty() {
				agg_key_ref.clear();
				return Ok(())
			}

			if let Ok(Some(agg_keys)) = agg_keys {
				let res = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(
					Call::submit_public_key { keys_and_signatures: agg_keys }.into(),
				)
				.map_err(|_| "Failed to submit transaction");
				match res {
					Ok(_) => {
						agg_key_ref.clear();
					},
					Err(e) => {
						log::error!(target: "runtime::dkg_metadata", "Error: {:?}", e);
						return Err("Failed to submit the public key, will retry later")
					},
				};
			}

			Ok(())
		}
	}

	/// An offchain function that collects the next DKG public key
	/// and submits it to the chain.
	///
	/// This submission process is modelled similarly after an oracle.
	/// We require the respective threshold of submissions of the same
	/// DKG public key to be submitted in order to modify the on-chain
	/// storage.
	fn submit_next_public_key_onchain(block_number: BlockNumberFor<T>) -> Result<(), &'static str> {
		let next_unsigned_at = <NextUnsignedAt<T>>::get();
		if next_unsigned_at > block_number {
			return Err("Too early to send unsigned transaction")
		}
		let mut lock = StorageLock::<Time>::new(AGGREGATED_PUBLIC_KEYS_LOCK);
		{
			let _guard = lock.lock();

			let mut agg_key_ref = StorageValueRef::persistent(AGGREGATED_PUBLIC_KEYS);
			let mut submit_at_ref = StorageValueRef::persistent(SUBMIT_KEYS_AT);
			const RECENTLY_SENT: &str = "Already submitted a key in this session";
			let submit_at = submit_at_ref.get::<BlockNumberFor<T>>();

			let agg_keys = agg_key_ref.get::<AggregatedPublicKeys>();

			if let Ok(None) = agg_keys {
				return Ok(())
			}

			if let Ok(Some(submit_at)) = submit_at {
				if block_number < submit_at {
					log::debug!(target: "runtime::dkg_metadata", "Offchain worker skipping next public key submmission");
					return Ok(())
				} else {
					submit_at_ref.clear();
				}
			} else {
				return Err(RECENTLY_SENT)
			}

			if Self::next_dkg_public_key().is_some() {
				agg_key_ref.clear();
				return Ok(())
			}

			if let Ok(Some(agg_keys)) = agg_keys {
				let res = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(
					Call::submit_next_public_key { keys_and_signatures: agg_keys }.into(),
				)
				.map_err(|_| "Failed to submit transaction");

				match res {
					Ok(_) => {
						agg_key_ref.clear();
					},
					Err(e) => {
						log::error!(target: "runtime::dkg_metadata", "Error: {:?}", e);
						return Err("Failed to submit the next public key, will retry later")
					},
				};
			}

			Ok(())
		}
	}

	/// An offchain function that collects the misbehaviour reports in
	/// the offchain storage and submits them to the chain.
	fn submit_misbehaviour_reports_onchain(
		block_number: BlockNumberFor<T>,
	) -> Result<(), &'static str> {
		let next_unsigned_at = <NextUnsignedAt<T>>::get();
		if next_unsigned_at > block_number {
			return Err("Too early to send unsigned transaction")
		}
		let mut lock = StorageLock::<Time>::new(AGGREGATED_MISBEHAVIOUR_REPORTS_LOCK);
		{
			let _guard = lock.lock();

			let signer = Signer::<T, T::OffChainAuthId>::any_account();
			if !signer.can_sign() {
				return Err(
					"No local accounts available. Consider adding one via `author_insertKey` RPC.",
				)
			}

			let mut agg_reports_ref = StorageValueRef::persistent(AGGREGATED_MISBEHAVIOUR_REPORTS);
			let agg_misbehaviour_reports = agg_reports_ref.get::<AggregatedMisbehaviourReports<
				T::DKGId,
				T::MaxSignatureLength,
				T::MaxReporters,
			>>();

			if let Ok(Some(reports)) = agg_misbehaviour_reports {
				// If this offender has already been reported, don't report it again.
				if Self::misbehaviour_reports((
					reports.misbehaviour_type,
					reports.session_id,
					reports.offender.clone(),
				))
				.is_some()
				{
					agg_reports_ref.clear();
					return Ok(())
				}

				let res = SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(
					Call::submit_misbehaviour_reports { reports }.into(),
				)
				.map_err(|_| "Failed to submit transaction");

				match res {
					Ok(_) => {
						agg_reports_ref.clear();
					},
					Err(e) => {
						log::error!(target: "runtime::dkg_metadata", "Error: {:?}", e);
						return Err("Failed to submit the misbehaviour reports, will retry later")
					},
				};
			}

			Ok(())
		}
	}

	pub fn update_next_keygen_threshold(next_threshold: u16) {
		let current_next_keygen_threshold = Self::next_keygen_threshold();
		if current_next_keygen_threshold != next_threshold {
			NextKeygenThreshold::<T>::put(next_threshold);
			Self::deposit_event(Event::NextKeygenThresholdUpdated {
				next_keygen_threshold: next_threshold,
			});
		}
	}

	pub fn update_pending_keygen_threshold(next_threshold: u16) {
		let current_pending_keygen_threshold = Self::pending_keygen_threshold();
		if current_pending_keygen_threshold != next_threshold {
			PendingKeygenThreshold::<T>::put(next_threshold);
			Self::deposit_event(Event::PendingKeygenThresholdUpdated {
				pending_keygen_threshold: next_threshold,
			});
		}
	}

	pub fn update_next_signature_threshold(next_threshold: u16) {
		let current_next_signature_threshold = Self::next_signature_threshold();
		if current_next_signature_threshold != next_threshold {
			NextSignatureThreshold::<T>::put(next_threshold);
			Self::deposit_event(Event::NextSignatureThresholdUpdated {
				next_signature_threshold: next_threshold,
			});
		}
	}

	pub fn should_refresh(_now: BlockNumberFor<T>) -> bool {
		let next_dkg_public_key = Self::next_dkg_public_key();
		let next_dkg_public_key_signature = Self::next_public_key_signature();
		next_dkg_public_key.is_some() && next_dkg_public_key_signature.is_none()
	}

	/// Inserts a successful rotation into the history
	///
	/// Insert historical round metadata consisting of the current round's
	/// public key before rotation, the next round's public key, and the refresh
	/// signature signed by the current key refreshing the next.
	pub fn insert_historical_refresh(
		dkg_pub_key: &(dkg_runtime_primitives::AuthoritySetId, BoundedVec<u8, T::MaxKeyLength>),
		next_pub_key: &(dkg_runtime_primitives::AuthoritySetId, BoundedVec<u8, T::MaxKeyLength>),
		next_pub_key_signature: BoundedVec<u8, T::MaxSignatureLength>,
	) {
		HistoricalRounds::<T>::insert(
			next_pub_key.0,
			RoundMetadata {
				curr_round_pub_key: dkg_pub_key.1.clone(),
				next_round_pub_key: next_pub_key.clone().1,
				refresh_signature: next_pub_key_signature,
			},
		);
	}

	pub fn get_best_authorities_by_reputation(
		count: usize,
		authorities: &[T::DKGId],
	) -> Vec<(u16, T::DKGId)> {
		let mut reputations_of_authorities = authorities
			.iter()
			.map(|id| (AuthorityReputations::<T>::get(id), id))
			.collect::<Vec<(_, _)>>();
		reputations_of_authorities.sort_by(|a, b| b.0.cmp(&a.0));

		return reputations_of_authorities
			.iter()
			.take(count)
			.cloned()
			.enumerate()
			.map(|(i, (_, id))| ((i + 1) as u16, id.clone()))
			.collect()
	}

	pub fn get_best_authorities(count: usize, authorities: &[T::DKGId]) -> Vec<(u16, T::DKGId)> {
		let jailed_authorities = authorities
			.iter()
			.cloned()
			.filter(|id| JailedKeygenAuthorities::<T>::contains_key(id))
			.collect::<Vec<T::DKGId>>();
		let mut best_authorities = authorities
			.iter()
			.cloned()
			.filter(|id| !JailedKeygenAuthorities::<T>::contains_key(id))
			.collect::<Vec<T::DKGId>>();
		if best_authorities.len() < count {
			let best_jailed = Self::get_best_authorities_by_reputation(
				count - best_authorities.len(),
				&jailed_authorities,
			);
			best_authorities.extend(best_jailed.iter().map(|x| x.1.clone()));
		}
		Self::get_best_authorities_by_reputation(count, &best_authorities)
	}

	#[cfg(feature = "runtime-benchmarks")]
	pub fn set_dkg_public_key(key: BoundedVec<u8, T::MaxKeyLength>) {
		DKGPublicKey::<T>::put((0, key))
	}
}

impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
	type Public = T::DKGId;
}

impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
	type Key = T::DKGId;

	fn on_genesis_session<'a, I: 'a>(validators: I)
	where
		I: Iterator<Item = (&'a T::AccountId, T::DKGId)>,
	{
		log::debug!(target: "runtime::dkg_metadata", "on_genesis_session");
		let mut authority_account_ids = Vec::new();
		let authorities = validators
			.map(|(l, k)| {
				authority_account_ids.push(l.clone());
				k
			})
			.collect::<Vec<_>>();

		Self::initialize_authorities(&authorities, &authority_account_ids);
	}

	// We want to run this function always because there are other factors (forcing a new era) that
	// can affect changes to the queued validator set that the session pallet will not take not of
	// until the next session, and this could cause the value of `changed` to be wrong, causing an
	// out of sync between this pallet and the session pallet. The `changed` value is true most of
	// the times except in rare cases, omitting  that check does not cause any harm, since this
	// function is light weight we already have a check in the change_authorities function that
	// would ensure the refresh is not run if the authority set has not changed.
	fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I)
	where
		I: Iterator<Item = (&'a T::AccountId, T::DKGId)>,
	{
		let mut authority_account_ids = Vec::new();
		let mut queued_authority_account_ids = Vec::new();
		let next_authorities = validators
			.map(|(acc, k)| {
				authority_account_ids.push(acc.clone());
				AccountToAuthority::<T>::insert(acc, k.clone());
				k
			})
			.collect::<Vec<_>>();

		let next_queued_authorities = queued_validators
			.map(|(acc, k)| {
				queued_authority_account_ids.push(acc.clone());
				AccountToAuthority::<T>::insert(acc, k.clone());
				k
			})
			.collect::<Vec<_>>();

		// store the current block as the start of new session
		LastSessionRotationBlock::<T>::put(frame_system::Pallet::<T>::block_number());

		Self::change_authorities(
			next_authorities,
			next_queued_authorities,
			authority_account_ids,
			queued_authority_account_ids,
			false,
		);
	}

	fn on_disabled(i: u32) {
		let log: DigestItem = DigestItem::Consensus(
			DKG_ENGINE_ID,
			ConsensusLog::<T::DKGId, T::MaxAuthorities>::OnDisabled(i as AuthorityIndex).encode(),
		);

		<frame_system::Pallet<T>>::deposit_log(log);
	}
}

impl<T: Config> IsMember<T::DKGId> for Pallet<T> {
	fn is_member(authority_id: &T::DKGId) -> bool {
		Self::authorities().iter().any(|id| id == authority_id)
	}
}

impl<T: Config> GetDKGPublicKey for Pallet<T> {
	fn dkg_key() -> Vec<u8> {
		Self::dkg_public_key().1.into()
	}

	fn previous_dkg_key() -> Vec<u8> {
		Self::previous_public_key().1.into()
	}
}

/// Periodic Session manager for DKGMetadata
/// To rotate a session we require three conditions
/// 1. The Period has passed
/// 2. The NextDKGPublicKey has been set on chain
/// 3. The NextPublicKeySignature has been set onchain
pub struct DKGPeriodicSessions<Period, Offset, T>(PhantomData<(Period, Offset, T)>);

impl<
		BlockNumber: Rem<Output = BlockNumber> + Sub<Output = BlockNumber> + Zero + PartialOrd,
		Period: Get<BlockNumber>,
		Offset: Get<BlockNumber>,
		T: Config,
	> pallet_session::ShouldEndSession<BlockNumber> for DKGPeriodicSessions<Period, Offset, T>
{
	fn should_end_session(now: BlockNumber) -> bool {
		// The succesful upload of the new public key is required for a successful rotation we check
		// if the nextPublicKey and nextPublicKeySignature are stored onchain.
		let offset = Offset::get();
		let next_public_key_exists = NextDKGPublicKey::<T>::get().is_some();
		let next_public_key_signature_exists = NextPublicKeySignature::<T>::get().is_some();
		next_public_key_exists &&
			next_public_key_signature_exists &&
			now >= offset &&
			((now - offset) % Period::get()) >= Zero::zero()
	}
}

impl<
		BlockNumber: AtLeast32BitUnsigned + Clone + core::fmt::Debug + sp_std::convert::From<BlockNumberFor<T>>,
		Period: Get<BlockNumber>,
		Offset: Get<BlockNumber>,
		T: Config + pallet_session::Config,
	> EstimateNextSessionRotation<BlockNumber> for DKGPeriodicSessions<Period, Offset, T>
{
	fn average_session_length() -> BlockNumber {
		Period::get()
	}

	fn estimate_current_session_progress(now: BlockNumber) -> (Option<Permill>, Weight) {
		let offset = Offset::get();
		let period = Period::get();

		let progress = if now >= offset {
			// read the last block at which the session was rotated
			let last_rotated_block = LastSessionRotationBlock::<T>::get();
			let current_elapsed_time = now.clone().saturating_sub(last_rotated_block.into());

			// if we have gone above the period, return 100% to signal that we need to rotate
			if current_elapsed_time > period {
				Some(Permill::from_percent(100))
			} else {
				// NOTE: we add one since we assume that the current block has already elapsed,
				// i.e. when evaluating the last block in the session the progress should be 100%
				// (0% is never returned).
				let current = (now - offset) % period.clone() + One::one();
				Some(Permill::from_rational(current, period))
			}
		} else {
			Some(Permill::from_rational(now + One::one(), offset))
		};

		// Weight note: `estimate_current_session_progress` has no storage reads and trivial
		// computational overhead. There should be no risk to the chain having this weight value be
		// zero for now. However, this value of zero was not properly calculated, and so it would be
		// reasonable to come back here and properly calculate the weight of this function.
		(progress, Zero::zero())
	}

	fn estimate_next_session_rotation(now: BlockNumber) -> (Option<BlockNumber>, Weight) {
		let offset = Offset::get();
		let period = Period::get();

		let next_session = if now > offset {
			let block_after_last_session = (now.clone() - offset) % period.clone();
			if block_after_last_session > Zero::zero() {
				now.saturating_add(period.saturating_sub(block_after_last_session))
			} else {
				// this branch happens when the session is already rotated or will rotate in this
				// block (depending on being called before or after `session::on_initialize`). Here,
				// we assume the latter, namely that this is called after `session::on_initialize`,
				// and thus we add period to it as well.
				now + period
			}
		} else {
			offset
		};

		// Weight note: `estimate_next_session_rotation` has no storage reads and trivial
		// computational overhead. There should be no risk to the chain having this weight value be
		// zero for now. However, this value of zero was not properly calculated, and so it would be
		// reasonable to come back here and properly calculate the weight of this function.
		(Some(next_session), Zero::zero())
	}
}

/// A signed proposal handler implementation for handling DKG `RefreshProposal`s
///
/// On a signed `RefreshProposal` we must update the pallet's storage with the
/// signature of the new public key. This then enables us to rotate the authority
/// set on the next session change.
use dkg_runtime_primitives::traits::OnSignedProposal;
use webb_proposals::ProposalKind;
impl<T: Config> OnSignedProposal<T::MaxProposalLength> for Pallet<T> {
	fn on_signed_proposal(proposal: Proposal<T::MaxProposalLength>) -> Result<(), DispatchError> {
		ensure!(proposal.is_signed(), Error::<T>::ProposalNotSigned);

		if proposal.kind() == ProposalKind::Refresh {
			let (_, next_pub_key) =
				Self::next_dkg_public_key().ok_or(Error::<T>::NoNextPublicKey)?;

			// Check if a signature is already submitted. This should also prevent
			// against manipulating the ECDSA signature to replay the submission.
			ensure!(
				Self::next_public_key_signature().is_none(),
				Error::<T>::AlreadySubmittedSignature
			);

			// Check the pending refresh proposal against the proposal data.
			let maybe_prop = Self::pending_refresh_proposal();
			ensure!(maybe_prop.is_some(), Error::<T>::NoRefreshProposal);
			let curr = maybe_prop.unwrap_or_default();
			ensure!(curr.encode() == proposal.data().clone(), Error::<T>::InvalidRefreshProposal);

			// Check if the signature is already used
			let bounded_signature: BoundedVec<_, _> = proposal
				.signature()
				.unwrap_or_default()
				.try_into()
				.map_err(|_| Error::<T>::InvalidSignature)?;
			ensure!(
				!Self::used_signatures().contains(&bounded_signature),
				Error::<T>::UsedSignature
			);
			NextPublicKeySignature::<T>::put(bounded_signature);

			// Set the `CurrentRefreshProposal` for processing on the next session change.
			CurrentRefreshProposal::<T>::put(curr.clone());
			// Clear the `PendingRefreshProposal` storage now that
			// we've processed the signature over it.
			PendingRefreshProposal::<T>::kill();

			// Emit the event
			Self::deposit_event(Event::NextPublicKeySignatureSubmitted {
				signature: proposal.signature().unwrap_or_default(),
				voter_merkle_root: curr.voter_merkle_root,
				session_length: curr.session_length,
				voter_count: curr.voter_count,
				nonce: curr.nonce,
				pub_key: curr.pub_key,
				compressed_pub_key: next_pub_key.into(),
			});
		};

		Ok(())
	}
}